function pubsub_init(&$a) { $nick = argc() > 1 ? escape_tags(trim(argv(1))) : ''; $contact_id = argc() > 2 ? intval(argv(2)) : 0; if ($_SERVER['REQUEST_METHOD'] === 'GET') { $hub_mode = x($_GET, 'hub_mode') ? notags(trim($_GET['hub_mode'])) : ''; $hub_topic = x($_GET, 'hub_topic') ? notags(trim($_GET['hub_topic'])) : ''; $hub_challenge = x($_GET, 'hub_challenge') ? notags(trim($_GET['hub_challenge'])) : ''; $hub_lease = x($_GET, 'hub_lease_seconds') ? notags(trim($_GET['hub_lease_seconds'])) : ''; $hub_verify = x($_GET, 'hub_verify_token') ? notags(trim($_GET['hub_verify_token'])) : ''; logger('pubsub: Subscription from ' . $_SERVER['REMOTE_ADDR']); logger('pubsub: data: ' . print_r($_GET, true), LOGGER_DATA); $subscribe = $hub_mode === 'subscribe' ? 1 : 0; $channel = channelx_by_nick($nick); if (!$channel) { http_status_exit(404, 'not found.'); } $connections = abook_connections($channel['channel_id'], ' and abook_id = ' . $contact_id); if ($connections) { $xchan = $connections[0]; } else { logger('connection ' . $contact_id . ' not found.'); http_status_exit(404, 'not found.'); } if ($hub_verify) { $verify = get_abconfig($channel['channel_id'], $xchan['xchan_hash'], 'pubsubhubbub', 'verify_token'); if ($verify != $hub_verify) { logger('hub verification failed.'); http_status_exit(404, 'not found.'); } } $feed_url = z_root() . '/feed/' . $channel['channel_address']; if ($hub_topic) { if (!link_compare($hub_topic, $feed_url)) { logger('hub topic ' . $hub_topic . ' != ' . $feed_url); // should abort but let's humour them. } } $contact = $r[0]; // We must initiate an unsubscribe request with a verify_token. // Don't allow outsiders to unsubscribe us. if ($hub_mode === 'unsubscribe') { if (!strlen($hub_verify)) { logger('pubsub: bogus unsubscribe'); http_status_exit(403, 'permission denied.'); } logger('pubsub: unsubscribe success'); } if ($hub_mode) { set_abconfig($channel['channel_id'], $xchan['xchan_hash'], 'pubsubhubbub', 'subscribed', intval($subscribe)); } header($_SERVER["SERVER_PROTOCOL"] . ' 200 ' . 'OK'); echo $hub_challenge; killme(); } }
function init() { if (!local_channel()) { return; } $uid = local_channel(); $url = notags(trim($_REQUEST['url'])); $return_url = $_SESSION['return_url']; $confirm = intval($_REQUEST['confirm']); $channel = \App::get_channel(); // Warning: Do not edit the following line. The first symbol is UTF-8 @ $url = str_replace('@', '@', $url); $result = new_contact($uid, $url, $channel, true, $confirm); if ($result['success'] == false) { if ($result['message']) { notice($result['message']); } goaway($return_url); } info(t('Channel added.') . EOL); $clone = array(); foreach ($result['abook'] as $k => $v) { if (strpos($k, 'abook_') === 0) { $clone[$k] = $v; } } unset($clone['abook_id']); unset($clone['abook_account']); unset($clone['abook_channel']); $abconfig = load_abconfig($channel['channel_id'], $clone['abook_xchan']); if ($abconfig) { $clone['abconfig'] = $abconfig; } build_sync_packet(0, array('abook' => array($clone)), true); $can_view_stream = intval(get_abconfig($channel['channel_id'], $clone['abook_xchan'], 'their_perms', 'view_stream')); // If we can view their stream, pull in some posts if ($can_view_stream || $result['abook']['xchan_network'] === 'rss') { \Zotlabs\Daemon\Master::Summon(array('Onepoll', $result['abook']['abook_id'])); } goaway(z_root() . '/connedit/' . $result['abook']['abook_id'] . '?f=&follow=1'); }
public static function run($argc, $argv) { logger('onepoll: start'); if ($argc > 1 && intval($argv[1])) { $contact_id = intval($argv[1]); } if (!$contact_id) { logger('onepoll: no contact'); return; } $d = datetime_convert(); $contacts = q("SELECT abook.*, xchan.*, account.*\n\t\t\tFROM abook LEFT JOIN account on abook_account = account_id left join xchan on xchan_hash = abook_xchan \n\t\t\twhere abook_id = %d\n\t\t\tand abook_pending = 0 and abook_archived = 0 and abook_blocked = 0 and abook_ignored = 0\n\t\t\tAND (( account_flags = %d ) OR ( account_flags = %d )) limit 1", intval($contact_id), intval(ACCOUNT_OK), intval(ACCOUNT_UNVERIFIED)); if (!$contacts) { logger('onepoll: abook_id not found: ' . $contact_id); return; } $contact = $contacts[0]; $t = $contact['abook_updated']; $importer_uid = $contact['abook_channel']; $r = q("SELECT * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1", intval($importer_uid)); if (!$r) { return; } $importer = $r[0]; logger("onepoll: poll: ({$contact['id']}) IMPORTER: {$importer['xchan_name']}, CONTACT: {$contact['xchan_name']}"); $last_update = $contact['abook_updated'] === $contact['abook_created'] || $contact['abook_updated'] <= NULL_DATE ? datetime_convert('UTC', 'UTC', 'now - 7 days') : datetime_convert('UTC', 'UTC', $contact['abook_updated'] . ' - 2 days'); if ($contact['xchan_network'] === 'rss') { logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG); handle_feed($importer['channel_id'], $contact_id, $contact['xchan_hash']); q("update abook set abook_connected = '%s' where abook_id = %d", dbesc(datetime_convert()), intval($contact['abook_id'])); return; } if ($contact['xchan_network'] !== 'zot') { return; } // update permissions $x = zot_refresh($contact, $importer); $responded = false; $updated = datetime_convert(); $connected = datetime_convert(); if (!$x) { // mark for death by not updating abook_connected, this is caught in include/poller.php q("update abook set abook_updated = '%s' where abook_id = %d", dbesc($updated), intval($contact['abook_id'])); } else { q("update abook set abook_updated = '%s', abook_connected = '%s' where abook_id = %d", dbesc($updated), dbesc($connected), intval($contact['abook_id'])); $responded = true; } if (!$responded) { return; } if ($contact['xchan_connurl']) { $fetch_feed = true; $x = null; // They haven't given us permission to see their stream $can_view_stream = intval(get_abconfig($importer_uid, $contact['abook_xchan'], 'their_perms', 'view_stream')); if (!$can_view_stream) { $fetch_feed = false; } // we haven't given them permission to send us their stream $can_send_stream = intval(get_abconfig($importer_uid, $contact['abook_xchan'], 'my_perms', 'send_stream')); if (!$can_send_stream) { $fetch_feed = false; } if ($fetch_feed) { $feedurl = str_replace('/poco/', '/zotfeed/', $contact['xchan_connurl']); $feedurl .= '?f=&mindate=' . urlencode($last_update); $x = z_fetch_url($feedurl); logger('feed_update: ' . print_r($x, true), LOGGER_DATA); } if ($x && $x['success']) { $total = 0; logger('onepoll: feed update ' . $contact['xchan_name'] . ' ' . $feedurl); $j = json_decode($x['body'], true); if ($j['success'] && $j['messages']) { 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_DATA); $total++; } logger("onepoll: {$total} messages processed"); } } } // update the poco details for this connection if ($contact['xchan_connurl']) { $r = q("SELECT xlink_id from xlink \n\t\t\t\twhere xlink_xchan = '%s' and xlink_updated > %s - INTERVAL %s and xlink_static = 0 limit 1", intval($contact['xchan_hash']), db_utcnow(), db_quoteinterval('1 DAY')); if (!$r) { poco_load($contact['xchan_hash'], $contact['xchan_connurl']); } } return; }
/** * @brief * * Checks to see if this item owner is referenced as a source for this channel and if the post * matches the rules for inclusion in this channel. Returns true if we should create a second delivery * chain and false if none of the rules apply, or if the item is private. * * @param int $uid * @param array $item */ function check_item_source($uid, $item) { $r = q("select * from source where src_channel_id = %d and ( src_xchan = '%s' or src_xchan = '*' ) limit 1", intval($uid), dbesc($item['source_xchan'] ? $item['source_xchan'] : $item['owner_xchan'])); if (!$r) { return false; } $x = q("select abook_their_perms, abook_feed from abook where abook_channel = %d and abook_xchan = '%s' limit 1", intval($uid), dbesc($item['owner_xchan'])); if (!$x) { return false; } if (!get_abconfig($uid, $item['owner_xchan'], 'their_perms', 'republish')) { return false; } if ($item['item_private'] && !intval($x[0]['abook_feed'])) { return false; } if ($r[0]['src_channel_xchan'] === $item['owner_xchan']) { return false; } // since we now have connection filters with more features, the source filter is redundant and can probably go away if (!$r[0]['src_patt']) { return true; } require_once 'include/html2plain.php'; $text = prepare_text($item['body'], $item['mimetype']); $text = html2plain($text); $tags = count($item['term']) ? $item['term'] : false; $words = explode("\n", $r[0]['src_patt']); if ($words) { foreach ($words as $word) { if (substr($word, 0, 1) === '#' && $tags) { foreach ($tags as $t) { if (($t['ttype'] == TERM_HASHTAG || $t['ttype'] == TERM_COMMUNITYTAG) && ($t['term'] === substr($word, 1) || substr($word, 1) === '*')) { return true; } } } elseif (strpos($word, '/') === 0 && preg_match($word, $text)) { return true; } elseif (stristr($text, $word) !== false) { return true; } } } return false; }
function pubsubhubbub_subscribe($url, $channel, $xchan, $feed, $hubmode = 'subscribe') { $push_url = z_root() . '/pubsub/' . $channel['channel_address'] . '/' . $xchan['abook_id']; $verify = get_abconfig($channel['channel_id'], $xchan['xchan_hash'], 'pubsubhubbub', 'verify_token'); if (!$verify) { $verify = set_abconfig($channel['channel_id'], $xchan['xchan_hash'], 'pubsubhubbub', 'verify_token', random_string(16)); } if ($feed) { set_xconfig($xchan['xchan_hash'], 'system', 'feed_url', $feed); } else { $feed = get_xconfig($xchan['xchan_hash'], 'system', 'feed_url'); } $params = 'hub.mode=' . $hubmode . '&hub.callback=' . urlencode($push_url) . '&hub.topic=' . urlencode($feed) . '&hub.verify=async&hub.verify_token=' . $verify; logger('subscribe_to_hub: ' . $hubmode . ' ' . $xchan['xchan_name'] . ' to hub ' . $url . ' endpoint: ' . $push_url . ' with verifier ' . $verify); $x = z_post_url($url, $params); logger('subscribe_to_hub: returns: ' . $x['return_code'], LOGGER_DEBUG); return; }
function get() { $channel = \App::get_channel(); $atoken = null; $atoken_xchan = ''; if (argc() > 2) { $id = argv(2); $atoken = q("select * from atoken where atoken_id = %d and atoken_uid = %d", intval($id), intval(local_channel())); if ($atoken) { $atoken = $atoken[0]; $atoken_xchan = substr($channel['channel_hash'], 0, 16) . '.' . $atoken['atoken_name']; } if ($atoken && argc() > 3 && argv(3) === 'drop') { atoken_delete($id); $atoken = null; $atoken_xchan = ''; } } $t = q("select * from atoken where atoken_uid = %d", intval(local_channel())); $desc = t('Use this form to create temporary access identifiers to share things with non-members. These identities may be used in Access Control Lists and visitors may login using these credentials to access private content.'); $desc2 = t('You may also provide <em>dropbox</em> style access links to friends and associates by adding the Login Password to any specific site URL as shown. Examples:'); $global_perms = \Zotlabs\Access\Permissions::Perms(); $existing = get_all_perms(local_channel(), $atoken_xchan ? $atoken_xchan : ''); if ($atoken_xchan) { $theirs = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'their_perms'", intval(local_channel()), dbesc($atoken_xchan)); $their_perms = array(); if ($theirs) { foreach ($theirs as $t) { $their_perms[$t['k']] = $t['v']; } } } foreach ($global_perms as $k => $v) { $thisperm = get_abconfig(local_channel(), $contact['abook_xchan'], 'my_perms', $k); //fixme $checkinherited = \Zotlabs\Access\PermissionLimits::Get(local_channel(), $k); if ($existing[$k]) { $thisperm = "1"; } $perms[] = array('perms_' . $k, $v, array_key_exists($k, $their_perms) ? intval($their_perms[$k]) : '', $thisperm, 1, $checkinherited & PERMS_SPECIFIC ? '' : '1', '', $checkinherited); } $tpl = get_markup_template("settings_tokens.tpl"); $o .= replace_macros($tpl, array('$form_security_token' => get_form_security_token("settings_tokens"), '$title' => t('Guest Access Tokens'), '$desc' => $desc, '$desc2' => $desc2, '$tokens' => $t, '$atoken' => $atoken, '$url1' => z_root() . '/channel/' . $channel['channel_address'], '$url2' => z_root() . '/photos/' . $channel['channel_address'], '$name' => array('name', t('Login Name') . ' <span class="required">*</span>', $atoken ? $atoken['atoken_name'] : '', ''), '$token' => array('token', t('Login Password') . ' <span class="required">*</span>', $atoken ? $atoken['atoken_token'] : autoname(8), ''), '$expires' => array('expires', t('Expires (yyyy-mm-dd)'), $atoken['atoken_expires'] && $atoken['atoken_expires'] > NULL_DATE ? datetime_convert('UTC', date_default_timezone_get(), $atoken['atoken_expires']) : '', ''), '$them' => t('Their Settings'), '$me' => t('My Settings'), '$perms' => $perms, '$inherited' => t('inherited'), '$notself' => '1', '$permlbl' => t('Individual Permissions'), '$permnote' => t('Some permissions may be inherited from your channel\'s <a href="settings"><strong>privacy settings</strong></a>, which have higher priority than individual settings. You can <strong>not</strong> change those settings here.'), '$submit' => t('Submit'))); return $o; }
/** * Returns user info array. */ function api_get_user($a, $contact_id = null, $contact_xchan = null) { global $called_api; $user = null; $extra_query = ""; if (!is_null($contact_xchan)) { $user = local_channel(); $extra_query = " and abook_xchan = '" . dbesc($contact_xchan) . "' "; } else { if (!is_null($contact_id)) { $user = $contact_id; $extra_query = " AND abook_id = %d "; } if (is_null($user) && x($_GET, 'user_id')) { $user = intval($_GET['user_id']); $extra_query = " AND abook_id = %d "; } if (is_null($user) && x($_GET, 'screen_name')) { $user = dbesc($_GET['screen_name']); $extra_query = " AND xchan_addr like '%s@%%' "; if (api_user() !== false) { $extra_query .= " AND abook_channel = " . intval(api_user()); } } if (is_null($user) && argc() > count($called_api) - 1 && strstr(App::$cmd, '/users')) { $argid = count($called_api); list($xx, $null) = explode(".", argv($argid)); if (is_numeric($xx)) { $user = intval($xx); $extra_query = " AND abook_id = %d "; } else { $user = dbesc($xx); $extra_query = " AND xchan_addr like '%s@%%' "; if (api_user() !== false) { $extra_query .= " AND abook_channel = " . intval(api_user()); } } } } if (!$user) { if (api_user() === false) { api_login($a); return False; } else { $user = local_channel(); $extra_query = " AND abook_channel = %d AND abook_self = 1 "; } } logger('api_user: '******', user: '******'abook_self'])) { $usr = q("select * from channel where channel_id = %d limit 1", intval(api_user())); $profile = q("select * from profile where uid = %d and `is_default` = 1 limit 1", intval(api_user())); $item_normal = item_normal(); // count public wall messages $r = q("SELECT COUNT(`id`) as `count` FROM `item`\n\t\t\t\t\tWHERE `uid` = %d\n\t\t\t\t\tAND item_wall = 1 {$item_normal} \n\t\t\t\t\tAND `allow_cid`='' AND `allow_gid`='' AND `deny_cid`='' AND `deny_gid`=''\n\t\t\t\t\tAND item_private = 0 ", intval($usr[0]['channel_id'])); $countitms = $r[0]['count']; $following = true; } else { $r = q("SELECT COUNT(`id`) as `count` FROM `item`\n\t\t\t\t\tWHERE author_xchan = '%s'\n\t\t\t\t\tAND `allow_cid`='' AND `allow_gid`='' AND `deny_cid`='' AND `deny_gid`=''\n\t\t\t\t\tAND item_private = 0 ", intval($uinfo[0]['xchan_hash'])); $countitms = $r[0]['count']; $following = get_abconfig($uinfo[0]['abook_channel'], $uinfo[0]['abook_xchan'], 'my_perms', 'view_stream') ? true : false; } // count friends if ($usr) { $r = q("SELECT COUNT(abook_id) as `count` FROM abook\n\t\t\t\t\tWHERE abook_channel = %d AND abook_self = 0 ", intval($usr[0]['channel_id'])); $countfriends = $r[0]['count']; $countfollowers = $r[0]['count']; } $r = q("SELECT count(`id`) as `count` FROM item where item_starred = 1 and uid = %d " . item_normal(), intval($uinfo[0]['channel_id'])); $starred = $r[0]['count']; if (!intval($uinfo[0]['abook_self'])) { $countfriends = 0; $countfollowers = 0; $starred = 0; } $ret = array('id' => intval($uinfo[0]['abook_id']), 'self' => intval($uinfo[0]['abook_self']) ? 1 : 0, 'uid' => intval($uinfo[0]['abook_channel']), 'guid' => $uinfo[0]['xchan_hash'], 'name' => $uinfo[0]['xchan_name'] ? $uinfo[0]['xchan_name'] : substr($uinfo[0]['xchan_addr'], 0, strpos($uinfo[0]['xchan_addr'], '@')), 'screen_name' => substr($uinfo[0]['xchan_addr'], 0, strpos($uinfo[0]['xchan_addr'], '@')), 'location' => $usr ? $usr[0]['channel_location'] : '', 'profile_image_url' => $uinfo[0]['xchan_photo_l'], 'url' => $uinfo[0]['xchan_url'], 'contact_url' => z_root() . "/connections/" . $uinfo[0]['abook_id'], 'protected' => false, 'friends_count' => intval($countfriends), 'created_at' => api_date($uinfo[0]['abook_created']), 'utc_offset' => "+00:00", 'time_zone' => 'UTC', 'geo_enabled' => false, 'statuses_count' => intval($countitms), 'lang' => App::$language, 'description' => $profile ? $profile[0]['pdesc'] : '', 'followers_count' => intval($countfollowers), 'favourites_count' => intval($starred), 'contributors_enabled' => false, 'follow_request_sent' => true, 'profile_background_color' => 'cfe8f6', 'profile_text_color' => '000000', 'profile_link_color' => 'FF8500', 'profile_sidebar_fill_color' => 'AD0066', 'profile_sidebar_border_color' => 'AD0066', 'profile_background_image_url' => '', 'profile_background_tile' => false, 'profile_use_background_image' => false, 'notifications' => false, 'following' => $following, 'verified' => true); $x = api_get_status($uinfo[0]['xchan_hash']); if ($x) { $ret['status'] = $x; } // logger('api_get_user: ' . print_r($ret,true)); return $ret; }
/** * @brief Refreshes after permission changed or friending, etc. * * zot_refresh is typically invoked when somebody has changed permissions of a channel and they are notified * to fetch new permissions via a finger/discovery operation. This may result in a new connection * (abook entry) being added to a local channel and it may result in auto-permissions being granted. * * Friending in zot is accomplished by sending a refresh packet to a specific channel which indicates a * permission change has been made by the sender which affects the target channel. The hub controlling * the target channel does targetted discovery (a zot-finger request requesting permissions for the local * channel). These are decoded here, and if necessary and abook structure (addressbook) is created to store * the permissions assigned to this channel. * * Initially these abook structures are created with a 'pending' flag, so that no reverse permissions are * implied until this is approved by the owner channel. A channel can also auto-populate permissions in * return and send back a refresh packet of its own. This is used by forum and group communication channels * so that friending and membership in the channel's "club" is automatic. * * @param array $them => xchan structure of sender * @param array $channel => local channel structure of target recipient, required for "friending" operations * @param array $force default false * * @returns boolean true if successful, else false */ function zot_refresh($them, $channel = null, $force = false) { if (array_key_exists('xchan_network', $them) && $them['xchan_network'] !== 'zot') { logger('zot_refresh: not got zot. ' . $them['xchan_name']); return true; } logger('zot_refresh: them: ' . print_r($them, true), LOGGER_DATA, LOG_DEBUG); if ($channel) { logger('zot_refresh: channel: ' . print_r($channel, true), LOGGER_DATA, LOG_DEBUG); } $url = null; if ($them['hubloc_url']) { $url = $them['hubloc_url']; } 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_primary from hubloc where hubloc_addr = '%s' order by hubloc_id desc", dbesc($them['xchan_addr'])); } if (!$r) { $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 (intval($rr['hubloc_primary'])) { $url = $rr['hubloc_url']; break; } } if (!$url) { $url = $r[0]['hubloc_url']; } } } if (!$url) { logger('zot_refresh: no url'); return false; } $token = random_string(); $postvars = array(); $postvars['token'] = $token; if ($channel) { $postvars['target'] = $channel['channel_guid']; $postvars['target_sig'] = $channel['channel_guid_sig']; $postvars['key'] = $channel['channel_pubkey']; } if (array_key_exists('xchan_addr', $them) && $them['xchan_addr']) { $postvars['address'] = $them['xchan_addr']; } if (array_key_exists('xchan_hash', $them) && $them['xchan_hash']) { $postvars['guid_hash'] = $them['xchan_hash']; } if (array_key_exists('xchan_guid', $them) && $them['xchan_guid'] && array_key_exists('xchan_guid_sig', $them) && $them['xchan_guid_sig']) { $postvars['guid'] = $them['xchan_guid']; $postvars['guid_sig'] = $them['xchan_guid_sig']; } $rhs = '/.well-known/zot-info'; $result = z_post_url($url . $rhs, $postvars); logger('zot_refresh: zot-info: ' . print_r($result, true), LOGGER_DATA, LOG_DEBUG); if ($result['success']) { $j = json_decode($result['body'], true); if (!($j && $j['success'])) { logger('zot_refresh: result not decodable'); return false; } $signed_token = is_array($j) && array_key_exists('signed_token', $j) ? $j['signed_token'] : null; if ($signed_token) { $valid = rsa_verify('token.' . $token, base64url_decode($signed_token), $j['key']); if (!$valid) { logger('invalid signed token: ' . $url . $rhs, LOGGER_NORMAL, LOG_ERR); return false; } } else { logger('No signed token from ' . $url . $rhs, LOGGER_NORMAL, LOG_WARNING); // after 2017-01-01 this will be a hard error unless you over-ride it. if (time() > 1483228800 && !get_config('system', 'allow_unsigned_zotfinger')) { return false; } } $x = import_xchan($j, $force ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED); if (!$x['success']) { return false; } if ($channel) { if ($j['permissions']['data']) { $permissions = crypto_unencapsulate(array('data' => $j['permissions']['data'], 'key' => $j['permissions']['key'], 'iv' => $j['permissions']['iv']), $channel['channel_prvkey']); if ($permissions) { $permissions = json_decode($permissions, true); } logger('decrypted permissions: ' . print_r($permissions, true), LOGGER_DATA, LOG_DEBUG); } else { $permissions = $j['permissions']; } $connected_set = false; if ($permissions && is_array($permissions)) { $old_read_stream_perm = get_abconfig($channel['channel_id'], $x['hash'], 'their_perms', 'view_stream'); foreach ($permissions as $k => $v) { set_abconfig($channel['channel_id'], $x['hash'], 'their_perms', $k, $v); } } if (array_key_exists('profile', $j) && array_key_exists('next_birthday', $j['profile'])) { $next_birthday = datetime_convert('UTC', 'UTC', $j['profile']['next_birthday']); } else { $next_birthday = NULL_DATE; } $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'])); if ($r) { // connection exists // if the dob is the same as what we have stored (disregarding the year), keep the one // we have as we may have updated the year after sending a notification; and resetting // to the one we just received would cause us to create duplicated events. if (substr($r[0]['abook_dob'], 5) == substr($next_birthday, 5)) { $next_birthday = $r[0]['abook_dob']; } $y = q("update abook set abook_dob = '%s'\n\t\t\t\t\twhere abook_xchan = '%s' and abook_channel = %d\n\t\t\t\t\tand abook_self = 0 ", dbescdate($next_birthday), dbesc($x['hash']), intval($channel['channel_id'])); if (!$y) { logger('abook update failed'); } else { // if we were just granted read stream permission and didn't have it before, try to pull in some posts if (!$old_read_stream_perm && intval($permissions['view_stream'])) { Zotlabs\Daemon\Master::Summon(array('Onepoll', $r[0]['abook_id'])); } } } else { // new connection $my_perms = null; $automatic = false; $role = get_pconfig($channel['channel_id'], 'system', 'permissions_role'); if ($role) { $xx = \Zotlabs\Access\PermissionRoles::role_perms($role); if ($xx['perms_auto']) { $automatic = true; $default_perms = $xx['perms_connect']; $my_perms = \Zotlabs\Access\Permissions::FilledPerms($default_perms); } } if (!$my_perms) { $m = \Zotlabs\Access\Permissions::FilledAutoperms($channel['channel_id']); if ($m) { $automatic = true; $my_perms = $m; } } if ($my_perms) { foreach ($my_perms as $k => $v) { set_abconfig($channel['channel_id'], $x['hash'], 'my_perms', $k, $v); } } // Keep original perms to check if we need to notify them $previous_perms = get_all_perms($channel['channel_id'], $x['hash']); $closeness = get_pconfig($channel['channel_id'], 'system', 'new_abook_closeness'); if ($closeness === false) { $closeness = 80; } $y = q("insert into abook ( abook_account, abook_channel, abook_closeness, abook_xchan, abook_created, abook_updated, abook_dob, abook_pending ) values ( %d, %d, %d, '%s', '%s', '%s', '%s', %d )", intval($channel['channel_account_id']), intval($channel['channel_id']), intval($closeness), dbesc($x['hash']), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($next_birthday), intval($automatic ? 0 : 1)); if ($y) { logger("New introduction received for {$channel['channel_name']}"); $new_perms = get_all_perms($channel['channel_id'], $x['hash']); // 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 abook_self = 0 order by abook_created desc limit 1", dbesc($x['hash']), intval($channel['channel_id'])); if ($new_connection) { if (!\Zotlabs\Access\Permissions::PermsCompare($new_perms, $previous_perms)) { Zotlabs\Daemon\Master::Summon(array('Notifier', 'permission_create', $new_connection[0]['abook_id'])); } Zotlabs\Lib\Enotify::submit(array('type' => NOTIFY_INTRO, 'from_xchan' => $x['hash'], 'to_xchan' => $channel['channel_hash'], 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'])); if (intval($permissions['view_stream'])) { if (intval(get_pconfig($channel['channel_id'], 'perm_limits', 'send_stream') & PERMS_PENDING) || !intval($new_connection[0]['abook_pending'])) { Zotlabs\Daemon\Master::Summon(array('Onepoll', $new_connection[0]['abook_id'])); } } /** If there is a default group for this channel, add this connection to it */ $default_group = $channel['channel_default_group']; if ($default_group) { require_once 'include/group.php'; $g = group_rec_byhash($channel['channel_id'], $default_group); if ($g) { group_add_member($channel['channel_id'], '', $x['hash'], $g['id']); } } unset($new_connection[0]['abook_id']); unset($new_connection[0]['abook_account']); unset($new_connection[0]['abook_channel']); $abconfig = load_abconfig($channel['channel_id'], $new_connection['abook_xchan']); if ($abconfig) { $new_connection['abconfig'] = $abconfig; } build_sync_packet($channel['channel_id'], array('abook' => $new_connection)); } } } } return true; } return false; }
function get() { $sort_type = 0; $o = ''; if (!local_channel()) { notice(t('Permission denied.') . EOL); return login(); } $channel = \App::get_channel(); $my_perms = get_channel_default_perms(local_channel()); $role = get_pconfig(local_channel(), 'system', 'permissions_role'); if ($role) { $x = \Zotlabs\Access\PermissionRoles::role_perms($role); if ($x['perms_connect']) { $my_perms = $x['perms_connect']; } } $yes_no = array(t('No'), t('Yes')); if ($my_perms) { $o .= "<script>function connectDefaultShare() {\n\t\t\t\$('.abook-edit-me').each(function() {\n\t\t\t\tif(! \$(this).is(':disabled'))\n\t\t\t\t\t\$(this).prop('checked', false);\n\t\t\t});\n\n"; $perms = get_perms(); foreach ($perms as $p => $v) { if ($my_perms & $v[1]) { $o .= "\$('#me_id_perms_" . $p . "').prop('checked', true); \n"; } } $o .= " }\n</script>\n"; } if (argc() == 3) { $contact_id = intval(argv(1)); if (!$contact_id) { return; } $cmd = argv(2); $orig_record = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash\n\t\t\t\tWHERE abook_id = %d AND abook_channel = %d AND abook_self = 0 LIMIT 1", intval($contact_id), intval(local_channel())); if (!count($orig_record)) { notice(t('Could not access address book record.') . EOL); goaway(z_root() . '/connections'); } if ($cmd === 'update') { // pull feed and consume it, which should subscribe to the hub. \Zotlabs\Daemon\Master::Summon(array('Poller', $contact_id)); goaway(z_root() . '/connedit/' . $contact_id); } if ($cmd === 'resetphoto') { q("update xchan set xchan_photo_date = '2001-01-01 00:00:00' where xchan_hash = '%s' limit 1", dbesc($orig_record[0]['xchan_hash'])); $cmd = 'refresh'; } if ($cmd === 'refresh') { if ($orig_record[0]['xchan_network'] === 'zot') { if (!zot_refresh($orig_record[0], \App::get_channel())) { notice(t('Refresh failed - channel is currently unavailable.')); } } else { // if you are on a different network we'll force a refresh of the connection basic info \Zotlabs\Daemon\Master::Summon(array('Notifier', 'permission_update', $contact_id)); } goaway(z_root() . '/connedit/' . $contact_id); } if ($cmd === 'block') { if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_BLOCKED)) { $this->connedit_clone($a); } else { notice(t('Unable to set address book parameters.') . EOL); } goaway(z_root() . '/connedit/' . $contact_id); } if ($cmd === 'ignore') { if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_IGNORED)) { $this->connedit_clone($a); } else { notice(t('Unable to set address book parameters.') . EOL); } goaway(z_root() . '/connedit/' . $contact_id); } if ($cmd === 'archive') { if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_ARCHIVED)) { $this->connedit_clone($a); } else { notice(t('Unable to set address book parameters.') . EOL); } goaway(z_root() . '/connedit/' . $contact_id); } if ($cmd === 'hide') { if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_HIDDEN)) { $this->connedit_clone($a); } else { notice(t('Unable to set address book parameters.') . EOL); } goaway(z_root() . '/connedit/' . $contact_id); } // We'll prevent somebody from unapproving an already approved contact. // Though maybe somebody will want this eventually (??) if ($cmd === 'approve') { if (intval($orig_record[0]['abook_pending'])) { if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_PENDING)) { $this->connedit_clone($a); } else { notice(t('Unable to set address book parameters.') . EOL); } } goaway(z_root() . '/connedit/' . $contact_id); } if ($cmd === 'drop') { // FIXME // We need to send either a purge or a refresh packet to the other side (the channel being unfriended). // The issue is that the abook DB record _may_ get destroyed when we call contact_remove. As the notifier runs // in the background there could be a race condition preventing this packet from being sent in all cases. // PLACEHOLDER contact_remove(local_channel(), $orig_record[0]['abook_id']); build_sync_packet(0, array('abook' => array(array('abook_xchan' => $orig_record[0]['abook_xchan'], 'entry_deleted' => true)))); info(t('Connection has been removed.') . EOL); if (x($_SESSION, 'return_url')) { goaway(z_root() . '/' . $_SESSION['return_url']); } goaway(z_root() . '/contacts'); } } if (\App::$poi) { $contact_id = \App::$poi['abook_id']; $contact = \App::$poi; $tools = array('view' => array('label' => t('View Profile'), 'url' => chanlink_cid($contact['abook_id']), 'sel' => '', 'title' => sprintf(t('View %s\'s profile'), $contact['xchan_name'])), 'refresh' => array('label' => t('Refresh Permissions'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/refresh', 'sel' => '', 'title' => t('Fetch updated permissions')), 'recent' => array('label' => t('Recent Activity'), 'url' => z_root() . '/network/?f=&cid=' . $contact['abook_id'], 'sel' => '', 'title' => t('View recent posts and comments')), 'block' => array('label' => intval($contact['abook_blocked']) ? t('Unblock') : t('Block'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/block', 'sel' => intval($contact['abook_blocked']) ? 'active' : '', 'title' => t('Block (or Unblock) all communications with this connection'), 'info' => intval($contact['abook_blocked']) ? t('This connection is blocked!') : ''), 'ignore' => array('label' => intval($contact['abook_ignored']) ? t('Unignore') : t('Ignore'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/ignore', 'sel' => intval($contact['abook_ignored']) ? 'active' : '', 'title' => t('Ignore (or Unignore) all inbound communications from this connection'), 'info' => intval($contact['abook_ignored']) ? t('This connection is ignored!') : ''), 'archive' => array('label' => intval($contact['abook_archived']) ? t('Unarchive') : t('Archive'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/archive', 'sel' => intval($contact['abook_archived']) ? 'active' : '', 'title' => t('Archive (or Unarchive) this connection - mark channel dead but keep content'), 'info' => intval($contact['abook_archived']) ? t('This connection is archived!') : ''), 'hide' => array('label' => intval($contact['abook_hidden']) ? t('Unhide') : t('Hide'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/hide', 'sel' => intval($contact['abook_hidden']) ? 'active' : '', 'title' => t('Hide or Unhide this connection from your other connections'), 'info' => intval($contact['abook_hidden']) ? t('This connection is hidden!') : ''), 'delete' => array('label' => t('Delete'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/drop', 'sel' => '', 'title' => t('Delete this connection'))); $self = false; if (intval($contact['abook_self'])) { $self = true; } $tpl = get_markup_template("abook_edit.tpl"); if (feature_enabled(local_channel(), 'affinity')) { $labels = array(t('Me'), t('Family'), t('Friends'), t('Acquaintances'), t('All')); call_hooks('affinity_labels', $labels); $label_str = ''; if ($labels) { foreach ($labels as $l) { if ($label_str) { $label_str .= ", '|'"; $label_str .= ", '" . $l . "'"; } else { $label_str .= "'" . $l . "'"; } } } $slider_tpl = get_markup_template('contact_slider.tpl'); $slide = replace_macros($slider_tpl, array('$min' => 1, '$val' => $contact['abook_closeness'] ? $contact['abook_closeness'] : 99, '$labels' => $label_str)); } $rating_val = 0; $rating_text = ''; $xl = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1", dbesc($channel['channel_hash']), dbesc($contact['xchan_hash'])); if ($xl) { $rating_val = intval($xl[0]['xlink_rating']); $rating_text = $xl[0]['xlink_rating_text']; } $poco_rating = get_config('system', 'poco_rating_enable'); // if unset default to enabled if ($poco_rating === false) { $poco_rating = true; } if ($poco_rating) { $rating = replace_macros(get_markup_template('rating_slider.tpl'), array('$min' => -10, '$val' => $rating_val)); } else { $rating = false; } $perms = array(); $channel = \App::get_channel(); $global_perms = \Zotlabs\Access\Permissions::Perms(); $existing = get_all_perms(local_channel(), $contact['abook_xchan']); $unapproved = array('pending', t('Approve this connection'), '', t('Accept connection to allow communication'), array(t('No'), 'Yes')); $multiprofs = feature_enabled(local_channel(), 'multi_profiles') ? true : false; if ($slide && !$multiprofs) { $affinity = t('Set Affinity'); } if (!$slide && $multiprofs) { $affinity = t('Set Profile'); } if ($slide && $multiprofs) { $affinity = t('Set Affinity & Profile'); } $theirs = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'their_perms'", intval(local_channel()), dbesc($contact['abook_xchan'])); $their_perms = array(); if ($theirs) { foreach ($theirs as $t) { $their_perms[$t['k']] = $t['v']; } } foreach ($global_perms as $k => $v) { $thisperm = get_abconfig(local_channel(), $contact['abook_xchan'], 'my_perms', $k); //fixme $checkinherited = \Zotlabs\Access\PermissionLimits::Get(local_channel(), $k); // For auto permissions (when $self is true) we don't want to look at existing // permissions because they are enabled for the channel owner if (!$self && $existing[$k]) { $thisperm = "1"; } $perms[] = array('perms_' . $k, $v, array_key_exists($k, $their_perms) ? intval($their_perms[$k]) : '', $thisperm, 1, $checkinherited & PERMS_SPECIFIC ? '' : '1', '', $checkinherited); } $locstr = ''; $locs = q("select hubloc_addr as location from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s'\n\t\t\t\tand hubloc_deleted = 0 and site_dead = 0", dbesc($contact['xchan_hash'])); if ($locs) { foreach ($locs as $l) { if (!$l['location']) { continue; } if (strpos($locstr, $l['location']) !== false) { continue; } if (strlen($locstr)) { $locstr .= ', '; } $locstr .= $l['location']; } } else { $locstr = t('none'); } $o .= replace_macros($tpl, array('$header' => $self ? t('Connection Default Permissions') : sprintf(t('Connection: %s'), $contact['xchan_name']), '$autoperms' => array('autoperms', t('Apply these permissions automatically'), get_pconfig(local_channel(), 'system', 'autoperms') ? 1 : 0, t('Connection requests will be approved without your interaction'), $yes_no), '$addr' => $contact['xchan_addr'], '$addr_text' => t('This connection\'s primary address is'), '$loc_text' => t('Available locations:'), '$locstr' => $locstr, '$notself' => $self ? '' : '1', '$self' => $self ? '1' : '', '$autolbl' => t('The permissions indicated on this page will be applied to all new connections.'), '$tools_label' => t('Connection Tools'), '$tools' => $self ? '' : $tools, '$lbl_slider' => t('Slide to adjust your degree of friendship'), '$lbl_rating' => t('Rating'), '$lbl_rating_label' => t('Slide to adjust your rating'), '$lbl_rating_txt' => t('Optionally explain your rating'), '$connfilter' => feature_enabled(local_channel(), 'connfilter'), '$connfilter_label' => t('Custom Filter'), '$incl' => array('abook_incl', t('Only import posts with this text'), $contact['abook_incl'], t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')), '$excl' => array('abook_excl', t('Do not import posts with this text'), $contact['abook_excl'], t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')), '$rating_text' => array('rating_text', t('Optionally explain your rating'), $rating_text, ''), '$rating_info' => t('This information is public!'), '$rating' => $rating, '$rating_val' => $rating_val, '$slide' => $slide, '$affinity' => $affinity, '$pending_label' => t('Connection Pending Approval'), '$is_pending' => intval($contact['abook_pending']) ? 1 : '', '$unapproved' => $unapproved, '$inherited' => t('inherited'), '$submit' => t('Submit'), '$lbl_vis2' => sprintf(t('Please choose the profile you would like to display to %s when viewing your profile securely.'), $contact['xchan_name']), '$close' => $contact['abook_closeness'], '$them' => t('Their Settings'), '$me' => t('My Settings'), '$perms' => $perms, '$permlbl' => t('Individual Permissions'), '$permnote' => t('Some permissions may be inherited from your channel\'s <a href="settings"><strong>privacy settings</strong></a>, which have higher priority than individual settings. You can <strong>not</strong> change those settings here.'), '$permnote_self' => t('Some permissions may be inherited from your channel\'s <a href="settings"><strong>privacy settings</strong></a>, which have higher priority than individual settings. You can change those settings here but they wont have any impact unless the inherited setting changes.'), '$lastupdtext' => t('Last update:'), '$last_update' => relative_date($contact['abook_connected']), '$profile_select' => contact_profile_assign($contact['abook_profile']), '$multiprofs' => $multiprofs, '$contact_id' => $contact['abook_id'], '$name' => $contact['xchan_name'])); $arr = array('contact' => $contact, 'output' => $o); call_hooks('contact_edit', $arr); return $arr['output']; } }
function get() { $o = ''; nav_set_selected('settings'); if (!local_channel() || $_SESSION['delegate']) { notice(t('Permission denied.') . EOL); return login(); } $channel = \App::get_channel(); if ($channel) { head_set_icon($channel['xchan_photo_s']); } $yes_no = array(t('No'), t('Yes')); if (argc() > 1 && argv(1) === 'oauth') { if (argc() > 2 && argv(2) === 'add') { $tpl = get_markup_template("settings_oauth_edit.tpl"); $o .= replace_macros($tpl, array('$form_security_token' => get_form_security_token("settings_oauth"), '$title' => t('Add application'), '$submit' => t('Submit'), '$cancel' => t('Cancel'), '$name' => array('name', t('Name'), '', t('Name of application')), '$key' => array('key', t('Consumer Key'), random_string(16), t('Automatically generated - change if desired. Max length 20')), '$secret' => array('secret', t('Consumer Secret'), random_string(16), t('Automatically generated - change if desired. Max length 20')), '$redirect' => array('redirect', t('Redirect'), '', t('Redirect URI - leave blank unless your application specifically requires this')), '$icon' => array('icon', t('Icon url'), '', t('Optional')))); return $o; } if (argc() > 3 && argv(2) === 'edit') { $r = q("SELECT * FROM clients WHERE client_id='%s' AND uid=%d", dbesc(argv(3)), local_channel()); if (!count($r)) { notice(t('Application not found.')); return; } $app = $r[0]; $tpl = get_markup_template("settings_oauth_edit.tpl"); $o .= replace_macros($tpl, array('$form_security_token' => get_form_security_token("settings_oauth"), '$title' => t('Add application'), '$submit' => t('Update'), '$cancel' => t('Cancel'), '$name' => array('name', t('Name'), $app['clname'], ''), '$key' => array('key', t('Consumer Key'), $app['client_id'], ''), '$secret' => array('secret', t('Consumer Secret'), $app['pw'], ''), '$redirect' => array('redirect', t('Redirect'), $app['redirect_uri'], ''), '$icon' => array('icon', t('Icon url'), $app['icon'], ''))); return $o; } if (argc() > 3 && argv(2) === 'delete') { check_form_security_token_redirectOnErr('/settings/oauth', 'settings_oauth', 't'); $r = q("DELETE FROM clients WHERE client_id='%s' AND uid=%d", dbesc(argv(3)), local_channel()); goaway(z_root() . "/settings/oauth/"); return; } $r = q("SELECT clients.*, tokens.id as oauth_token, (clients.uid=%d) AS my \n\t\t\t\t\tFROM clients\n\t\t\t\t\tLEFT JOIN tokens ON clients.client_id=tokens.client_id\n\t\t\t\t\tWHERE clients.uid IN (%d,0)", local_channel(), local_channel()); $tpl = get_markup_template("settings_oauth.tpl"); $o .= replace_macros($tpl, array('$form_security_token' => get_form_security_token("settings_oauth"), '$baseurl' => z_root(), '$title' => t('Connected Apps'), '$add' => t('Add application'), '$edit' => t('Edit'), '$delete' => t('Delete'), '$consumerkey' => t('Client key starts with'), '$noname' => t('No name'), '$remove' => t('Remove authorization'), '$apps' => $r)); return $o; } if (argc() > 1 && argv(1) === 'featured') { $settings_addons = ""; $o = ''; $r = q("SELECT * FROM `hook` WHERE `hook` = 'feature_settings' "); if (!$r) { $settings_addons = t('No feature settings configured'); } call_hooks('feature_settings', $settings_addons); $tpl = get_markup_template("settings_addons.tpl"); $o .= replace_macros($tpl, array('$form_security_token' => get_form_security_token("settings_featured"), '$title' => t('Feature/Addon Settings'), '$settings_addons' => $settings_addons)); return $o; } /* * ACCOUNT SETTINGS */ if (argc() > 1 && argv(1) === 'account') { $account_settings = ""; call_hooks('account_settings', $account_settings); $email = \App::$account['account_email']; $tpl = get_markup_template("settings_account.tpl"); $o .= replace_macros($tpl, array('$form_security_token' => get_form_security_token("settings_account"), '$title' => t('Account Settings'), '$origpass' => array('origpass', t('Current Password'), ' ', ''), '$password1' => array('npassword', t('Enter New Password'), '', ''), '$password2' => array('confirm', t('Confirm New Password'), '', t('Leave password fields blank unless changing')), '$submit' => t('Submit'), '$email' => array('email', t('Email Address:'), $email, ''), '$removeme' => t('Remove Account'), '$removeaccount' => t('Remove this account including all its channels'), '$account_settings' => $account_settings)); return $o; } if (argc() > 1 && argv(1) === 'tokens') { $atoken = null; $atoken_xchan = ''; if (argc() > 2) { $id = argv(2); $atoken = q("select * from atoken where atoken_id = %d and atoken_uid = %d", intval($id), intval(local_channel())); if ($atoken) { $atoken = $atoken[0]; $atoken_xchan = substr($channel['channel_hash'], 0, 16) . '.' . $atoken['atoken_name']; } if ($atoken && argc() > 3 && argv(3) === 'drop') { atoken_delete($id); $atoken = null; $atoken_xchan = ''; } } $t = q("select * from atoken where atoken_uid = %d", intval(local_channel())); $desc = t('Use this form to create temporary access identifiers to share things with non-members. These identities may be used in Access Control Lists and visitors may login using these credentials to access private content.'); $desc2 = t('You may also provide <em>dropbox</em> style access links to friends and associates by adding the Login Password to any specific site URL as shown. Examples:'); $global_perms = \Zotlabs\Access\Permissions::Perms(); $existing = get_all_perms(local_channel(), $atoken_xchan ? $atoken_xchan : ''); if ($atoken_xchan) { $theirs = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'their_perms'", intval(local_channel()), dbesc($atoken_xchan)); $their_perms = array(); if ($theirs) { foreach ($theirs as $t) { $their_perms[$t['k']] = $t['v']; } } } foreach ($global_perms as $k => $v) { $thisperm = get_abconfig(local_channel(), $contact['abook_xchan'], 'my_perms', $k); //fixme $checkinherited = \Zotlabs\Access\PermissionLimits::Get(local_channel(), $k); if ($existing[$k]) { $thisperm = "1"; } $perms[] = array('perms_' . $k, $v, array_key_exists($k, $their_perms) ? intval($their_perms[$k]) : '', $thisperm, 1, $checkinherited & PERMS_SPECIFIC ? '' : '1', '', $checkinherited); } $tpl = get_markup_template("settings_tokens.tpl"); $o .= replace_macros($tpl, array('$form_security_token' => get_form_security_token("settings_tokens"), '$title' => t('Guest Access Tokens'), '$desc' => $desc, '$desc2' => $desc2, '$tokens' => $t, '$atoken' => $atoken, '$url1' => z_root() . '/channel/' . $channel['channel_address'], '$url2' => z_root() . '/photos/' . $channel['channel_address'], '$name' => array('name', t('Login Name') . ' <span class="required">*</span>', $atoken ? $atoken['atoken_name'] : '', ''), '$token' => array('token', t('Login Password') . ' <span class="required">*</span>', $atoken ? $atoken['atoken_token'] : autoname(8), ''), '$expires' => array('expires', t('Expires (yyyy-mm-dd)'), $atoken['atoken_expires'] && $atoken['atoken_expires'] != NULL_DATE ? datetime_convert('UTC', date_default_timezone_get(), $atoken['atoken_expires']) : '', ''), '$them' => t('Their Settings'), '$me' => t('My Settings'), '$perms' => $perms, '$inherited' => t('inherited'), '$notself' => '1', '$permlbl' => t('Individual Permissions'), '$permnote' => t('Some permissions may be inherited from your channel\'s <a href="settings"><strong>privacy settings</strong></a>, which have higher priority than individual settings. You can <strong>not</strong> change those settings here.'), '$submit' => t('Submit'))); return $o; } if (argc() > 1 && argv(1) === 'features') { $arr = array(); $features = get_features(); foreach ($features as $fname => $fdata) { $arr[$fname] = array(); $arr[$fname][0] = $fdata[0]; foreach (array_slice($fdata, 1) as $f) { $arr[$fname][1][] = array('feature_' . $f[0], $f[1], intval(feature_enabled(local_channel(), $f[0])) ? "1" : '', $f[2], array(t('Off'), t('On'))); } } $tpl = get_markup_template("settings_features.tpl"); $o .= replace_macros($tpl, array('$form_security_token' => get_form_security_token("settings_features"), '$title' => t('Additional Features'), '$features' => $arr, '$submit' => t('Submit'))); return $o; } if (argc() > 1 && argv(1) === 'connectors') { $settings_connectors = ""; call_hooks('connector_settings', $settings_connectors); $r = null; $tpl = get_markup_template("settings_connectors.tpl"); $o .= replace_macros($tpl, array('$form_security_token' => get_form_security_token("settings_connectors"), '$title' => t('Connector Settings'), '$submit' => t('Submit'), '$settings_connectors' => $settings_connectors)); call_hooks('display_settings', $o); return $o; } /* * DISPLAY SETTINGS */ if (argc() > 1 && argv(1) === 'display') { $default_theme = get_config('system', 'theme'); if (!$default_theme) { $default_theme = 'default'; } $default_mobile_theme = get_config('system', 'mobile_theme'); if (!$mobile_default_theme) { $mobile_default_theme = 'none'; } $allowed_themes_str = get_config('system', 'allowed_themes'); $allowed_themes_raw = explode(',', $allowed_themes_str); $allowed_themes = array(); if (count($allowed_themes_raw)) { foreach ($allowed_themes_raw as $x) { if (strlen(trim($x)) && is_dir("view/theme/{$x}")) { $allowed_themes[] = trim($x); } } } $themes = array(); $files = glob('view/theme/*'); if ($allowed_themes) { foreach ($allowed_themes as $th) { $f = $th; $is_experimental = file_exists('view/theme/' . $th . '/experimental'); $unsupported = file_exists('view/theme/' . $th . '/unsupported'); $is_mobile = file_exists('view/theme/' . $th . '/mobile'); $is_library = file_exists('view/theme/' . $th . '/library'); $mobile_themes["---"] = t("No special theme for mobile devices"); if (!$is_experimental or $is_experimental && (get_config('experimentals', 'exp_themes') == 1 or get_config('experimentals', 'exp_themes') === false)) { $theme_name = $is_experimental ? sprintf(t('%s - (Experimental)'), $f) : $f; if (!$is_library) { if ($is_mobile) { $mobile_themes[$f] = $themes[$f] = $theme_name . ' (' . t('mobile') . ')'; } else { $mobile_themes[$f] = $themes[$f] = $theme_name; } } } } } $theme_selected = !x($_SESSION, 'theme') ? $default_theme : $_SESSION['theme']; $mobile_theme_selected = !x($_SESSION, 'mobile_theme') ? $default_mobile_theme : $_SESSION['mobile_theme']; $preload_images = get_pconfig(local_channel(), 'system', 'preload_images'); $preload_images = $preload_images === false ? '0' : $preload_images; // default if not set: 0 $user_scalable = get_pconfig(local_channel(), 'system', 'user_scalable'); $user_scalable = $user_scalable === false ? '1' : $user_scalable; // default if not set: 1 $browser_update = intval(get_pconfig(local_channel(), 'system', 'update_interval')); $browser_update = $browser_update == 0 ? 80 : $browser_update / 1000; // default if not set: 40 seconds $itemspage = intval(get_pconfig(local_channel(), 'system', 'itemspage')); $itemspage = $itemspage > 0 && $itemspage < 101 ? $itemspage : 20; // default if not set: 20 items $nosmile = get_pconfig(local_channel(), 'system', 'no_smilies'); $nosmile = $nosmile === false ? '0' : $nosmile; // default if not set: 0 $title_tosource = get_pconfig(local_channel(), 'system', 'title_tosource'); $title_tosource = $title_tosource === false ? '0' : $title_tosource; // default if not set: 0 $theme_config = ""; if (($themeconfigfile = $this->get_theme_config_file($theme_selected)) != null) { require_once $themeconfigfile; $theme_config = theme_content($a); } $tpl = get_markup_template("settings_display.tpl"); $o = replace_macros($tpl, array('$ptitle' => t('Display Settings'), '$d_tset' => t('Theme Settings'), '$d_ctset' => t('Custom Theme Settings'), '$d_cset' => t('Content Settings'), '$form_security_token' => get_form_security_token("settings_display"), '$submit' => t('Submit'), '$baseurl' => z_root(), '$uid' => local_channel(), '$theme' => $themes ? array('theme', t('Display Theme:'), $theme_selected, '', $themes, 'preview') : false, '$mobile_theme' => $mobile_themes ? array('mobile_theme', t('Mobile Theme:'), $mobile_theme_selected, '', $mobile_themes, '') : false, '$preload_images' => array('preload_images', t("Preload images before rendering the page"), $preload_images, t("The subjective page load time will be longer but the page will be ready when displayed"), $yes_no), '$user_scalable' => array('user_scalable', t("Enable user zoom on mobile devices"), $user_scalable, '', $yes_no), '$ajaxint' => array('browser_update', t("Update browser every xx seconds"), $browser_update, t('Minimum of 10 seconds, no maximum')), '$itemspage' => array('itemspage', t("Maximum number of conversations to load at any time:"), $itemspage, t('Maximum of 100 items')), '$nosmile' => array('nosmile', t("Show emoticons (smilies) as images"), 1 - intval($nosmile), '', $yes_no), '$title_tosource' => array('title_tosource', t("Link post titles to source"), $title_tosource, '', $yes_no), '$layout_editor' => t('System Page Layout Editor - (advanced)'), '$theme_config' => $theme_config, '$expert' => feature_enabled(local_channel(), 'expert'), '$channel_list_mode' => array('channel_list_mode', t('Use blog/list mode on channel page'), get_pconfig(local_channel(), 'system', 'channel_list_mode'), t('(comments displayed separately)'), $yes_no), '$network_list_mode' => array('network_list_mode', t('Use blog/list mode on grid page'), get_pconfig(local_channel(), 'system', 'network_list_mode'), t('(comments displayed separately)'), $yes_no), '$channel_divmore_height' => array('channel_divmore_height', t('Channel page max height of content (in pixels)'), get_pconfig(local_channel(), 'system', 'channel_divmore_height') ? get_pconfig(local_channel(), 'system', 'channel_divmore_height') : 400, t('click to expand content exceeding this height')), '$network_divmore_height' => array('network_divmore_height', t('Grid page max height of content (in pixels)'), get_pconfig(local_channel(), 'system', 'network_divmore_height') ? get_pconfig(local_channel(), 'system', 'network_divmore_height') : 400, t('click to expand content exceeding this height')))); return $o; } if (argv(1) === 'channel') { require_once 'include/acl_selectors.php'; require_once 'include/permissions.php'; $p = q("SELECT * FROM `profile` WHERE `is_default` = 1 AND `uid` = %d LIMIT 1", intval(local_channel())); if (count($p)) { $profile = $p[0]; } load_pconfig(local_channel(), 'expire'); $channel = \App::get_channel(); $global_perms = \Zotlabs\Access\Permissions::Perms(); $permiss = array(); $perm_opts = array(array(t('Nobody except yourself'), 0), array(t('Only those you specifically allow'), PERMS_SPECIFIC), array(t('Approved connections'), PERMS_CONTACTS), array(t('Any connections'), PERMS_PENDING), array(t('Anybody on this website'), PERMS_SITE), array(t('Anybody in this network'), PERMS_NETWORK), array(t('Anybody authenticated'), PERMS_AUTHED), array(t('Anybody on the internet'), PERMS_PUBLIC)); $limits = \Zotlabs\Access\PermissionLimits::Get(local_channel()); foreach ($global_perms as $k => $perm) { $options = array(); foreach ($perm_opts as $opt) { $options[$opt[1]] = $opt[0]; } $permiss[] = array($k, $perm, $limits[$k], '', $options); } //logger('permiss: ' . print_r($permiss,true)); $username = $channel['channel_name']; $nickname = $channel['channel_address']; $timezone = $channel['channel_timezone']; $notify = $channel['channel_notifyflags']; $defloc = $channel['channel_location']; $maxreq = $channel['channel_max_friend_req']; $expire = $channel['channel_expire_days']; $adult_flag = intval($channel['channel_pageflags'] & PAGE_ADULT); $sys_expire = get_config('system', 'default_expire_days'); // $unkmail = \App::$user['unkmail']; // $cntunkmail = \App::$user['cntunkmail']; $hide_presence = intval(get_pconfig(local_channel(), 'system', 'hide_online_status')); $expire_items = get_pconfig(local_channel(), 'expire', 'items'); $expire_items = $expire_items === false ? '1' : $expire_items; // default if not set: 1 $expire_notes = get_pconfig(local_channel(), 'expire', 'notes'); $expire_notes = $expire_notes === false ? '1' : $expire_notes; // default if not set: 1 $expire_starred = get_pconfig(local_channel(), 'expire', 'starred'); $expire_starred = $expire_starred === false ? '1' : $expire_starred; // default if not set: 1 $expire_photos = get_pconfig(local_channel(), 'expire', 'photos'); $expire_photos = $expire_photos === false ? '0' : $expire_photos; // default if not set: 0 $expire_network_only = get_pconfig(local_channel(), 'expire', 'network_only'); $expire_network_only = $expire_network_only === false ? '0' : $expire_network_only; // default if not set: 0 $suggestme = get_pconfig(local_channel(), 'system', 'suggestme'); $suggestme = $suggestme === false ? '0' : $suggestme; // default if not set: 0 $post_newfriend = get_pconfig(local_channel(), 'system', 'post_newfriend'); $post_newfriend = $post_newfriend === false ? '0' : $post_newfriend; // default if not set: 0 $post_joingroup = get_pconfig(local_channel(), 'system', 'post_joingroup'); $post_joingroup = $post_joingroup === false ? '0' : $post_joingroup; // default if not set: 0 $post_profilechange = get_pconfig(local_channel(), 'system', 'post_profilechange'); $post_profilechange = $post_profilechange === false ? '0' : $post_profilechange; // default if not set: 0 $blocktags = get_pconfig(local_channel(), 'system', 'blocktags'); $blocktags = $blocktags === false ? '0' : $blocktags; $timezone = date_default_timezone_get(); $opt_tpl = get_markup_template("field_checkbox.tpl"); if (get_config('system', 'publish_all')) { $profile_in_dir = '<input type="hidden" name="profile_in_directory" value="1" />'; } else { $profile_in_dir = replace_macros($opt_tpl, array('$field' => array('profile_in_directory', t('Publish your default profile in the network directory'), $profile['publish'], '', $yes_no))); } $suggestme = replace_macros($opt_tpl, array('$field' => array('suggestme', t('Allow us to suggest you as a potential friend to new members?'), $suggestme, '', $yes_no))); $subdir = strlen(\App::get_path()) ? '<br />' . t('or') . ' ' . z_root() . '/channel/' . $nickname : ''; $tpl_addr = get_markup_template("settings_nick_set.tpl"); $prof_addr = replace_macros($tpl_addr, array('$desc' => t('Your channel address is'), '$nickname' => $nickname, '$subdir' => $subdir, '$basepath' => \App::get_hostname())); $stpl = get_markup_template('settings.tpl'); $acl = new \Zotlabs\Access\AccessList($channel); $perm_defaults = $acl->get(); require_once 'include/group.php'; $group_select = mini_group_select(local_channel(), $channel['channel_default_group']); require_once 'include/menu.php'; $m1 = menu_list(local_channel()); $menu = false; if ($m1) { $menu = array(); $current = get_pconfig(local_channel(), 'system', 'channel_menu'); $menu[] = array('name' => '', 'selected' => !$current ? true : false); foreach ($m1 as $m) { $menu[] = array('name' => htmlspecialchars($m['menu_name'], ENT_COMPAT, 'UTF-8'), 'selected' => $m['menu_name'] === $current ? ' selected="selected" ' : false); } } $evdays = get_pconfig(local_channel(), 'system', 'evdays'); if (!$evdays) { $evdays = 3; } $permissions_role = get_pconfig(local_channel(), 'system', 'permissions_role'); if (!$permissions_role) { $permissions_role = 'custom'; } $permissions_set = $permissions_role != 'custom' ? true : false; $vnotify = get_pconfig(local_channel(), 'system', 'vnotify'); $always_show_in_notices = get_pconfig(local_channel(), 'system', 'always_show_in_notices'); if ($vnotify === false) { $vnotify = -1; } $o .= replace_macros($stpl, array('$ptitle' => t('Channel Settings'), '$submit' => t('Submit'), '$baseurl' => z_root(), '$uid' => local_channel(), '$form_security_token' => get_form_security_token("settings"), '$nickname_block' => $prof_addr, '$h_basic' => t('Basic Settings'), '$username' => array('username', t('Full Name:'), $username, ''), '$email' => array('email', t('Email Address:'), $email, ''), '$timezone' => array('timezone_select', t('Your Timezone:'), $timezone, '', get_timezones()), '$defloc' => array('defloc', t('Default Post Location:'), $defloc, t('Geographical location to display on your posts')), '$allowloc' => array('allow_location', t('Use Browser Location:'), get_pconfig(local_channel(), 'system', 'use_browser_location') ? 1 : '', '', $yes_no), '$adult' => array('adult', t('Adult Content'), $adult_flag, t('This channel frequently or regularly publishes adult content. (Please tag any adult material and/or nudity with #NSFW)'), $yes_no), '$h_prv' => t('Security and Privacy Settings'), '$permissions_set' => $permissions_set, '$server_role' => \Zotlabs\Lib\System::get_server_role(), '$perms_set_msg' => t('Your permissions are already configured. Click to view/adjust'), '$hide_presence' => array('hide_presence', t('Hide my online presence'), $hide_presence, t('Prevents displaying in your profile that you are online'), $yes_no), '$lbl_pmacro' => t('Simple Privacy Settings:'), '$pmacro3' => t('Very Public - <em>extremely permissive (should be used with caution)</em>'), '$pmacro2' => t('Typical - <em>default public, privacy when desired (similar to social network permissions but with improved privacy)</em>'), '$pmacro1' => t('Private - <em>default private, never open or public</em>'), '$pmacro0' => t('Blocked - <em>default blocked to/from everybody</em>'), '$permiss_arr' => $permiss, '$blocktags' => array('blocktags', t('Allow others to tag your posts'), 1 - $blocktags, t('Often used by the community to retro-actively flag inappropriate content'), $yes_no), '$lbl_p2macro' => t('Advanced Privacy Settings'), '$expire' => array('expire', t('Expire other channel content after this many days'), $expire, t('0 or blank to use the website limit.') . ' ' . (intval($sys_expire) ? sprintf(t('This website expires after %d days.'), intval($sys_expire)) : t('This website does not expire imported content.')) . ' ' . t('The website limit takes precedence if lower than your limit.')), '$maxreq' => array('maxreq', t('Maximum Friend Requests/Day:'), intval($channel['channel_max_friend_req']), t('May reduce spam activity')), '$permissions' => t('Default Post and Publish Permissions'), '$permdesc' => t("(click to open/close)"), '$aclselect' => populate_acl($perm_defaults, false, \Zotlabs\Lib\PermissionDescription::fromDescription(t('Use my default audience setting for the type of object published'))), '$allow_cid' => acl2json($perm_defaults['allow_cid']), '$allow_gid' => acl2json($perm_defaults['allow_gid']), '$deny_cid' => acl2json($perm_defaults['deny_cid']), '$deny_gid' => acl2json($perm_defaults['deny_gid']), '$suggestme' => $suggestme, '$group_select' => $group_select, '$role' => array('permissions_role', t('Channel permissions category:'), $permissions_role, '', get_roles()), '$profile_in_dir' => $profile_in_dir, '$hide_friends' => $hide_friends, '$hide_wall' => $hide_wall, '$unkmail' => $unkmail, '$cntunkmail' => array('cntunkmail', t('Maximum private messages per day from unknown people:'), intval($channel['channel_max_anon_mail']), t("Useful to reduce spamming")), '$h_not' => t('Notification Settings'), '$activity_options' => t('By default post a status message when:'), '$post_newfriend' => array('post_newfriend', t('accepting a friend request'), $post_newfriend, '', $yes_no), '$post_joingroup' => array('post_joingroup', t('joining a forum/community'), $post_joingroup, '', $yes_no), '$post_profilechange' => array('post_profilechange', t('making an <em>interesting</em> profile change'), $post_profilechange, '', $yes_no), '$lbl_not' => t('Send a notification email when:'), '$notify1' => array('notify1', t('You receive a connection request'), $notify & NOTIFY_INTRO, NOTIFY_INTRO, '', $yes_no), '$notify2' => array('notify2', t('Your connections are confirmed'), $notify & NOTIFY_CONFIRM, NOTIFY_CONFIRM, '', $yes_no), '$notify3' => array('notify3', t('Someone writes on your profile wall'), $notify & NOTIFY_WALL, NOTIFY_WALL, '', $yes_no), '$notify4' => array('notify4', t('Someone writes a followup comment'), $notify & NOTIFY_COMMENT, NOTIFY_COMMENT, '', $yes_no), '$notify5' => array('notify5', t('You receive a private message'), $notify & NOTIFY_MAIL, NOTIFY_MAIL, '', $yes_no), '$notify6' => array('notify6', t('You receive a friend suggestion'), $notify & NOTIFY_SUGGEST, NOTIFY_SUGGEST, '', $yes_no), '$notify7' => array('notify7', t('You are tagged in a post'), $notify & NOTIFY_TAGSELF, NOTIFY_TAGSELF, '', $yes_no), '$notify8' => array('notify8', t('You are poked/prodded/etc. in a post'), $notify & NOTIFY_POKE, NOTIFY_POKE, '', $yes_no), '$lbl_vnot' => t('Show visual notifications including:'), '$vnotify1' => array('vnotify1', t('Unseen grid activity'), $vnotify & VNOTIFY_NETWORK, VNOTIFY_NETWORK, '', $yes_no), '$vnotify2' => array('vnotify2', t('Unseen channel activity'), $vnotify & VNOTIFY_CHANNEL, VNOTIFY_CHANNEL, '', $yes_no), '$vnotify3' => array('vnotify3', t('Unseen private messages'), $vnotify & VNOTIFY_MAIL, VNOTIFY_MAIL, t('Recommended'), $yes_no), '$vnotify4' => array('vnotify4', t('Upcoming events'), $vnotify & VNOTIFY_EVENT, VNOTIFY_EVENT, '', $yes_no), '$vnotify5' => array('vnotify5', t('Events today'), $vnotify & VNOTIFY_EVENTTODAY, VNOTIFY_EVENTTODAY, '', $yes_no), '$vnotify6' => array('vnotify6', t('Upcoming birthdays'), $vnotify & VNOTIFY_BIRTHDAY, VNOTIFY_BIRTHDAY, t('Not available in all themes'), $yes_no), '$vnotify7' => array('vnotify7', t('System (personal) notifications'), $vnotify & VNOTIFY_SYSTEM, VNOTIFY_SYSTEM, '', $yes_no), '$vnotify8' => array('vnotify8', t('System info messages'), $vnotify & VNOTIFY_INFO, VNOTIFY_INFO, t('Recommended'), $yes_no), '$vnotify9' => array('vnotify9', t('System critical alerts'), $vnotify & VNOTIFY_ALERT, VNOTIFY_ALERT, t('Recommended'), $yes_no), '$vnotify10' => array('vnotify10', t('New connections'), $vnotify & VNOTIFY_INTRO, VNOTIFY_INTRO, t('Recommended'), $yes_no), '$vnotify11' => array('vnotify11', t('System Registrations'), $vnotify & VNOTIFY_REGISTER, VNOTIFY_REGISTER, '', $yes_no), '$always_show_in_notices' => array('always_show_in_notices', t('Also show new wall posts, private messages and connections under Notices'), $always_show_in_notices, 1, '', $yes_no), '$evdays' => array('evdays', t('Notify me of events this many days in advance'), $evdays, t('Must be greater than 0')), '$h_advn' => t('Advanced Account/Page Type Settings'), '$h_descadvn' => t('Change the behaviour of this account for special situations'), '$pagetype' => $pagetype, '$expert' => feature_enabled(local_channel(), 'expert'), '$hint' => t('Please enable expert mode (in <a href="settings/features">Settings > Additional features</a>) to adjust!'), '$lbl_misc' => t('Miscellaneous Settings'), '$photo_path' => array('photo_path', t('Default photo upload folder'), get_pconfig(local_channel(), 'system', 'photo_path'), t('%Y - current year, %m - current month')), '$attach_path' => array('attach_path', t('Default file upload folder'), get_pconfig(local_channel(), 'system', 'attach_path'), t('%Y - current year, %m - current month')), '$menus' => $menu, '$menu_desc' => t('Personal menu to display in your channel pages'), '$removeme' => t('Remove Channel'), '$removechannel' => t('Remove this channel.'), '$firefoxshare' => t('Firefox Share $Projectname provider'), '$cal_first_day' => array('first_day', t('Start calendar week on monday'), get_pconfig(local_channel(), 'system', 'cal_first_day') ? 1 : '', '', $yes_no))); call_hooks('settings_form', $o); //$o .= '</form>' . "\r\n"; return $o; } }