aboutsummaryrefslogtreecommitdiffstats
path: root/include/channel.php
diff options
context:
space:
mode:
Diffstat (limited to 'include/channel.php')
-rw-r--r--include/channel.php630
1 files changed, 542 insertions, 88 deletions
diff --git a/include/channel.php b/include/channel.php
index 856fb6303..f6252f094 100644
--- a/include/channel.php
+++ b/include/channel.php
@@ -57,8 +57,9 @@ function identity_check_service_class($account_id) {
* Plugins can set additional policies such as full name requirements, character
* sets, multi-byte length, etc.
*
+ * @hooks validate_channelname
+ * * \e array \b name
* @param string $name
- *
* @returns nil return if name is valid, or string describing the error state.
*/
function validate_channelname($name) {
@@ -69,7 +70,7 @@ function validate_channelname($name) {
if (strlen($name) > 255)
return t('Name too long');
- $arr = array('name' => $name);
+ $arr = ['name' => $name];
call_hooks('validate_channelname', $arr);
if (x($arr, 'message'))
@@ -242,24 +243,23 @@ function create_identity($arr) {
$expire = 0;
- $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_system, channel_expire_days, channel_timezone )
- values ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s' ) ",
+ $r = channel_store_lowlevel(
+ [
+ 'channel_account_id' => intval($arr['account_id']),
+ 'channel_primary' => intval($primary),
+ 'channel_name' => $name,
+ 'channel_address' => $nick,
+ 'channel_guid' => $guid,
+ 'channel_guid_sig' => $sig,
+ 'channel_hash' => $hash,
+ 'channel_prvkey' => $key['prvkey'],
+ 'channel_pubkey' => $key['pubkey'],
+ 'channel_pageflags' => intval($pageflags),
+ 'channel_system' => intval($system),
+ 'channel_expire_days' => intval($expire),
+ 'channel_timezone' => App::$timezone
- intval($arr['account_id']),
- intval($primary),
- dbesc($name),
- dbesc($nick),
- dbesc($guid),
- dbesc($sig),
- dbesc($hash),
- dbesc($key['prvkey']),
- dbesc($key['pubkey']),
- intval($pageflags),
- intval($system),
- intval($expire),
- dbesc(App::$timezone)
+ ]
);
$r = q("select * from channel where channel_account_id = %d
@@ -454,6 +454,108 @@ function create_identity($arr) {
return $ret;
}
+
+function change_channel_keys($channel) {
+
+ $ret = array('success' => false);
+
+ $stored = [];
+
+ $key = new_keypair(4096);
+
+ $sig = base64url_encode(rsa_sign($channel['channel_guid'],$key['prvkey']));
+ $hash = make_xchan_hash($channel['channel_guid'],$sig);
+
+ $stored['old_guid'] = $channel['channel_guid'];
+ $stored['old_guid_sig'] = $channel['channel_guid_sig'];
+ $stored['old_key'] = $channel['channel_pubkey'];
+ $stored['old_hash'] = $channel['channel_hash'];
+
+ $stored['new_key'] = $key['pubkey'];
+ $stored['new_sig'] = base64url_encode(rsa_sign($key['pubkey'],$channel['channel_prvkey']));
+
+ // Save this info for the notifier to collect
+
+ set_pconfig($channel['channel_id'],'system','keychange',$stored);
+
+ $r = q("update channel set channel_prvkey = '%s', channel_pubkey = '%s', channel_guid_sig = '%s', channel_hash = '%s' where channel_id = %d",
+ dbesc($key['prvkey']),
+ dbesc($key['pubkey']),
+ dbesc($sig),
+ dbesc($hash),
+ intval($channel['channel_id'])
+ );
+ if(! $r) {
+ return $ret;
+ }
+
+ $r = q("select * from channel where channel_id = %d",
+ intval($channel['channel_id'])
+ );
+
+ if(! $r) {
+ $ret['message'] = t('Unable to retrieve modified identity');
+ return $ret;
+ }
+
+ $modified = $r[0];
+
+ $h = q("select * from hubloc where hubloc_hash = '%s' and hubloc_url = '%s' ",
+ dbesc($stored['old_hash']),
+ dbesc(z_root())
+ );
+
+ if($h) {
+ foreach($h as $hv) {
+ $hv['hubloc_guid_sig'] = $sig;
+ $hv['hubloc_hash'] = $hash;
+ $hv['hubloc_url_sig'] = base64url_encode(rsa_sign(z_root(),$modifed['channel_prvkey']));
+ hubloc_store_lowlevel($hv);
+ }
+ }
+
+ $x = q("select * from xchan where xchan_hash = '%s' ",
+ dbesc($stored['old_hash'])
+ );
+
+ $check = q("select * from xchan where xchan_hash = '%s'",
+ dbesc($hash)
+ );
+
+ if(($x) && (! $check)) {
+ $oldxchan = $x[0];
+ foreach($x as $xv) {
+ $xv['xchan_guid_sig'] = $sig;
+ $xv['xchan_hash'] = $hash;
+ $xv['xchan_pubkey'] = $key['pubkey'];
+ xchan_store_lowlevel($xv);
+ $newxchan = $xv;
+ }
+ }
+
+ build_sync_packet($channel['channel_id'], [ 'keychange' => $stored ]);
+
+ $a = q("select * from abook where abook_xchan = '%s' and abook_self = 1",
+ dbesc($stored['old_hash'])
+ );
+
+ if($a) {
+ q("update abook set abook_xchan = '%s' where abook_id = %d",
+ dbesc($hash),
+ intval($a[0]['abook_id'])
+ );
+ }
+
+ xchan_change_key($oldxchan,$newxchan,$stored);
+
+ Zotlabs\Daemon\Master::Summon(array('Notifier', 'keychange', $channel['channel_id']));
+
+ $ret['success'] = true;
+ return $ret;
+}
+
+
+
/**
* @brief Set default channel to be used on login.
*
@@ -465,7 +567,6 @@ function create_identity($arr) {
* if true, set this default unconditionally
* if $force is false only do this if there is no existing default
*/
-
function set_default_login_identity($account_id, $channel_id, $force = true) {
$r = q("select account_default_channel from account where account_id = %d limit 1",
intval($account_id)
@@ -480,12 +581,29 @@ function set_default_login_identity($account_id, $channel_id, $force = true) {
}
}
-
+/**
+ * @brief Return an array with default list of sections to export.
+ *
+ * @hooks get_default_export_sections
+ * * \e array \b sections
+ * @return array with default section names to export
+ */
function get_default_export_sections() {
- $sections = [ 'channel', 'connections', 'config', 'apps', 'chatrooms', 'events', 'webpages', 'mail', 'wikis' ];
+ $sections = [
+ 'channel',
+ 'connections',
+ 'config',
+ 'apps',
+ 'chatrooms',
+ 'events',
+ 'webpages',
+ 'mail',
+ 'wikis'
+ ];
$cb = [ 'sections' => $sections ];
call_hooks('get_default_export_sections', $cb);
+
return $cb['sections'];
}
@@ -495,15 +613,17 @@ function get_default_export_sections() {
* which would be necessary to create a nomadic identity clone. This includes
* most channel resources and connection information with the exception of content.
*
+ * @hooks identity_basic_export
+ * * \e int \b channel_id
+ * * \e array \b sections
+ * * \e array \b data
* @param int $channel_id
* Channel_id to export
- * @param boolean $items
- * Include channel posts (wall items), default false
- *
+ * @param array $sections (optional)
+ * Which sections to include in the export, default see get_default_export_sections()
* @returns array
* See function for details
*/
-
function identity_basic_export($channel_id, $sections = null) {
/*
@@ -513,16 +633,16 @@ function identity_basic_export($channel_id, $sections = null) {
if(! $sections) {
$sections = get_default_export_sections();
}
-
+
$ret = [];
// use constants here as otherwise we will have no idea if we can import from a site
// with a non-standard platform and version.
$ret['compatibility'] = [
- 'project' => PLATFORM_NAME,
- 'version' => STD_VERSION,
- 'database' => DB_UPDATE_VERSION,
+ 'project' => PLATFORM_NAME,
+ 'version' => STD_VERSION,
+ 'database' => DB_UPDATE_VERSION,
'server_role' => Zotlabs\Lib\System::get_server_role()
];
@@ -539,6 +659,8 @@ function identity_basic_export($channel_id, $sections = null) {
$ret['relocate'] = [ 'channel_address' => $r[0]['channel_address'], 'url' => z_root()];
if(in_array('channel',$sections)) {
$ret['channel'] = $r[0];
+ unset($ret['channel']['channel_password']);
+ unset($ret['channel']['channel_salt']);
}
}
@@ -549,8 +671,7 @@ function identity_basic_export($channel_id, $sections = null) {
if($r)
$ret['profile'] = $r;
-
- $r = q("select mimetype, content, os_storage from photo
+ $r = q("select mimetype, content, os_storage from photo
where imgscale = 4 and photo_usage = %d and uid = %d limit 1",
intval(PHOTO_PROFILE),
intval($channel_id)
@@ -558,8 +679,8 @@ function identity_basic_export($channel_id, $sections = null) {
if($r) {
$ret['photo'] = [
- 'type' => $r[0]['mimetype'],
- 'data' => (($r[0]['os_storage'])
+ 'type' => $r[0]['mimetype'],
+ 'data' => (($r[0]['os_storage'])
? base64url_encode(file_get_contents($r[0]['content'])) : base64url_encode($r[0]['content']))
];
}
@@ -605,7 +726,6 @@ function identity_basic_export($channel_id, $sections = null) {
);
if($r)
$ret['group_member'] = $r;
-
}
if(in_array('config',$sections)) {
@@ -614,7 +734,7 @@ function identity_basic_export($channel_id, $sections = null) {
);
if($r)
$ret['config'] = $r;
-
+
// All other term types will be included in items, if requested.
$r = q("select * from term where ttype in (%d,%d) and uid = %d",
@@ -641,7 +761,6 @@ function identity_basic_export($channel_id, $sections = null) {
if($r)
$ret['likes'] = $r;
-
}
if(in_array('apps',$sections)) {
@@ -667,7 +786,6 @@ function identity_basic_export($channel_id, $sections = null) {
$ret['chatroom'] = $r;
}
-
if(in_array('events',$sections)) {
$r = q("select * from event where uid = %d",
intval($channel_id)
@@ -697,7 +815,7 @@ function identity_basic_export($channel_id, $sections = null) {
$ret['menu'][] = menu_element($ret['channel'],$m);
}
}
- $r = q("select * from item where item_type in ( "
+ $r = q("select * from item where item_type in ( "
. ITEM_TYPE_BLOCK . "," . ITEM_TYPE_PDL . "," . ITEM_TYPE_WEBPAGE . " ) and uid = %d",
intval($channel_id)
);
@@ -707,7 +825,6 @@ function identity_basic_export($channel_id, $sections = null) {
$r = fetch_post_tags($r,true);
foreach($r as $rr)
$ret['webpages'][] = encode_item($rr,true);
-
}
}
@@ -722,14 +839,14 @@ function identity_basic_export($channel_id, $sections = null) {
$ret['conv'] = $r;
}
- $r = q("select * from mail where mail.uid = %d",
+ $r = q("select * from mail where channel_id = %d",
intval($channel_id)
);
if($r) {
$m = array();
foreach($r as $rr) {
xchan_mail_query($rr);
- $m[] = mail_encode($rr,true);
+ $m[] = encode_mail($rr,true);
}
$ret['mail'] = $m;
}
@@ -758,7 +875,7 @@ function identity_basic_export($channel_id, $sections = null) {
* Don't export linked resource items. we'll have to pull those out separately.
*/
- $r = q("select * from item where item_wall = 1 and item_deleted = 0 and uid = %d
+ $r = q("select * from item where item_wall = 1 and item_deleted = 0 and uid = %d
and created > %s - INTERVAL %s and resource_type = '' order by created",
intval($channel_id),
db_utcnow(),
@@ -1147,31 +1264,16 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa
$location = $reddress = $pdesc = $gender = $marital = $homepage = False;
}
+ if($profile['gender']) {
+ $profile['gender_icon'] = gender_icon($profile['gender']);
+ }
+
$firstname = ((strpos($profile['channel_name'],' '))
? trim(substr($profile['channel_name'],0,strpos($profile['channel_name'],' '))) : $profile['channel_name']);
$lastname = (($firstname === $profile['channel_name']) ? '' : trim(substr($profile['channel_name'],strlen($firstname))));
// @fixme move this to the diaspora plugin itself
- if(plugin_is_installed('diaspora')) {
- $diaspora = array(
- 'podloc' => z_root(),
- 'guid' => $profile['channel_guid'] . str_replace('.','',App::get_hostname()),
- 'pubkey' => pemtorsa($profile['channel_pubkey']),
- 'searchable' => (($block) ? 'false' : 'true'),
- 'nickname' => $profile['channel_address'],
- 'fullname' => $profile['channel_name'],
- 'firstname' => $firstname,
- 'lastname' => $lastname,
- 'photo300' => z_root() . '/photo/profile/300/' . $profile['uid'] . '.jpg',
- 'photo100' => z_root() . '/photo/profile/100/' . $profile['uid'] . '.jpg',
- 'photo50' => z_root() . '/photo/profile/50/' . $profile['uid'] . '.jpg',
- );
- }
- else
- $diaspora = '';
-
-
$contact_block = contact_block();
$channel_menu = false;
@@ -1193,11 +1295,6 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa
else
$tpl = get_markup_template('profile_vcard.tpl');
- require_once('include/widgets.php');
-
-// if(! feature_enabled($profile['uid'],'hide_rating'))
- $z = widget_rating(array('target' => $profile['channel_hash']));
-
$o .= replace_macros($tpl, array(
'$zcard' => $zcard,
'$profile' => $profile,
@@ -1209,9 +1306,8 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa
'$marital' => $marital,
'$homepage' => $homepage,
'$chanmenu' => $channel_menu,
- '$diaspora' => $diaspora,
'$reddress' => $reddress,
- '$rating' => $z,
+ '$rating' => '',
'$contact_block' => $contact_block,
'$editmenu' => profile_edit_menu($profile['uid'])
));
@@ -1220,7 +1316,29 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa
call_hooks('profile_sidebar', $arr);
- return $o;
+ return $arr['entry'];
+
+}
+
+function gender_icon($gender) {
+
+// logger('gender: ' . $gender);
+
+ // This can easily get throw off if the observer language is different
+ // than the channel owner language.
+
+ if(strpos(strtolower($gender),strtolower(t('Female'))) !== false)
+ return 'venus';
+ if(strpos(strtolower($gender),strtolower(t('Male'))) !== false)
+ return 'mars';
+ if(strpos(strtolower($gender),strtolower(t('Trans'))) !== false)
+ return 'transgender';
+ if(strpos(strtolower($gender),strtolower(t('Neuter'))) !== false)
+ return 'neuter';
+ if(strpos(strtolower($gender),strtolower(t('Non-specific'))) !== false)
+ return 'genderless';
+
+ return '';
}
@@ -1399,15 +1517,15 @@ function get_my_address() {
}
/**
- * @brief
+ * @brief Add visitor's zid to our xchan and attempt authentication.
*
- * If somebody arrives at our site using a zid, add their xchan to our DB if we don't have it already.
+ * If somebody arrives at our site using a zid, add their xchan to our DB if we
+ * don't have it already.
* And if they aren't already authenticated here, attempt reverse magic auth.
*
- *
- * @hooks 'zid_init'
- * string 'zid' - their zid
- * string 'url' - the destination url
+ * @hooks zid_init
+ * * \e string \b zid - their zid
+ * * \e string \b url - the destination url
*/
function zid_init() {
$tmp_str = get_my_address();
@@ -1436,12 +1554,9 @@ function zid_init() {
}
/**
- * @brief
- *
- * If somebody arrives at our site using a zat, authenticate them
+ * @brief If somebody arrives at our site using a zat, authenticate them.
*
*/
-
function zat_init() {
if(local_channel() || remote_channel())
return;
@@ -1453,7 +1568,6 @@ function zat_init() {
$xchan = atoken_xchan($r[0]);
atoken_login($xchan);
}
-
}
@@ -1486,7 +1600,7 @@ function get_theme_uid() {
*
* @param int $size
* one of (300, 80, 48)
-* @returns string
+* @returns string with path to profile photo
*/
function get_default_profile_photo($size = 300) {
$scheme = get_config('system','default_profile_photo');
@@ -1608,7 +1722,7 @@ function get_profile_fields_basic($filter = 0) {
$profile_fields_basic = (($filter == 0) ? get_config('system','profile_fields_basic') : null);
if(! $profile_fields_basic)
- $profile_fields_basic = array('fullname','pdesc','chandesc','gender','dob','dob_tz','address','locality','region','postal_code','country_name','marital','sexual','homepage','hometown','keywords','about','contact');
+ $profile_fields_basic = array('fullname','pdesc','chandesc','comms','gender','dob','dob_tz','address','locality','region','postal_code','country_name','marital','sexual','homepage','hometown','keywords','about','contact');
$x = array();
if($profile_fields_basic)
@@ -1976,12 +2090,9 @@ function channel_manual_conv_update($channel_id) {
$x = get_pconfig($channel_id, 'system','manual_conversation_update');
if($x === false)
- $x = get_config('system','manual_conversation_update');
- if($x === false)
- $x = 1;
+ $x = get_config('system','manual_conversation_update', 1);
return intval($x);
-
}
@@ -1996,7 +2107,47 @@ function remote_login() {
}
+function channel_store_lowlevel($arr) {
+ $store = [
+ 'channel_account_id' => ((array_key_exists('channel_account_id',$arr)) ? $arr['channel_account_id'] : '0'),
+ 'channel_primary' => ((array_key_exists('channel_primary',$arr)) ? $arr['channel_primary'] : '0'),
+ 'channel_name' => ((array_key_exists('channel_name',$arr)) ? $arr['channel_name'] : ''),
+ 'channel_address' => ((array_key_exists('channel_address',$arr)) ? $arr['channel_address'] : ''),
+ 'channel_guid' => ((array_key_exists('channel_guid',$arr)) ? $arr['channel_guid'] : ''),
+ 'channel_guid_sig' => ((array_key_exists('channel_guid_sig',$arr)) ? $arr['channel_guid_sig'] : ''),
+ 'channel_hash' => ((array_key_exists('channel_hash',$arr)) ? $arr['channel_hash'] : ''),
+ 'channel_timezone' => ((array_key_exists('channel_timezone',$arr)) ? $arr['channel_timezone'] : 'UTC'),
+ 'channel_location' => ((array_key_exists('channel_location',$arr)) ? $arr['channel_location'] : ''),
+ 'channel_theme' => ((array_key_exists('channel_theme',$arr)) ? $arr['channel_theme'] : ''),
+ 'channel_startpage' => ((array_key_exists('channel_startpage',$arr)) ? $arr['channel_startpage'] : ''),
+ 'channel_pubkey' => ((array_key_exists('channel_pubkey',$arr)) ? $arr['channel_pubkey'] : ''),
+ 'channel_prvkey' => ((array_key_exists('channel_prvkey',$arr)) ? $arr['channel_prvkey'] : ''),
+ 'channel_notifyflags' => ((array_key_exists('channel_notifyflags',$arr)) ? $arr['channel_notifyflags'] : '65535'),
+ 'channel_pageflags' => ((array_key_exists('channel_pageflags',$arr)) ? $arr['channel_pageflags'] : '0'),
+ 'channel_dirdate' => ((array_key_exists('channel_dirdate',$arr)) ? $arr['channel_dirdate'] : NULL_DATE),
+ 'channel_lastpost' => ((array_key_exists('channel_lastpost',$arr)) ? $arr['channel_lastpost'] : NULL_DATE),
+ 'channel_deleted' => ((array_key_exists('channel_deleted',$arr)) ? $arr['channel_deleted'] : NULL_DATE),
+ 'channel_max_anon_mail' => ((array_key_exists('channel_max_anon_mail',$arr)) ? $arr['channel_max_anon_mail'] : '10'),
+ 'channel_max_friend_req' => ((array_key_exists('channel_max_friend_req',$arr)) ? $arr['channel_max_friend_req'] : '10'),
+ 'channel_expire_days' => ((array_key_exists('channel_expire_days',$arr)) ? $arr['channel_expire_days'] : '0'),
+ 'channel_passwd_reset' => ((array_key_exists('channel_passwd_reset',$arr)) ? $arr['channel_passwd_reset'] : ''),
+ 'channel_default_group' => ((array_key_exists('channel_default_group',$arr)) ? $arr['channel_default_group'] : ''),
+ 'channel_allow_cid' => ((array_key_exists('channel_allow_cid',$arr)) ? $arr['channel_allow_cid'] : ''),
+ 'channel_allow_gid' => ((array_key_exists('channel_allow_gid',$arr)) ? $arr['channel_allow_gid'] : ''),
+ 'channel_deny_cid' => ((array_key_exists('channel_deny_cid',$arr)) ? $arr['channel_deny_cid'] : ''),
+ 'channel_deny_gid' => ((array_key_exists('channel_deny_gid',$arr)) ? $arr['channel_deny_gid'] : ''),
+ 'channel_removed' => ((array_key_exists('channel_removed',$arr)) ? $arr['channel_removed'] : '0'),
+ 'channel_system' => ((array_key_exists('channel_system',$arr)) ? $arr['channel_system'] : '0'),
+
+ 'channel_moved' => ((array_key_exists('channel_moved',$arr)) ? $arr['channel_moved'] : ''),
+ 'channel_password' => ((array_key_exists('channel_password',$arr)) ? $arr['channel_password'] : ''),
+ 'channel_salt' => ((array_key_exists('channel_salt',$arr)) ? $arr['channel_salt'] : '')
+
+ ];
+
+ return create_table_from_array('channel',$store);
+}
function profile_store_lowlevel($arr) {
@@ -2048,4 +2199,307 @@ function profile_store_lowlevel($arr) {
];
return create_table_from_array('profile',$store);
-} \ No newline at end of file
+}
+
+
+// Included here for completeness, but this is a very dangerous operation.
+// It is the caller's responsibility to confirm the requestor's intent and
+// authorisation to do this.
+
+function account_remove($account_id,$local = true,$unset_session=true) {
+
+ logger('account_remove: ' . $account_id);
+
+ if(! intval($account_id)) {
+ logger('account_remove: no account.');
+ return false;
+ }
+
+ // Don't let anybody nuke the only admin account.
+
+ $r = q("select account_id from account where (account_roles & %d) > 0",
+ intval(ACCOUNT_ROLE_ADMIN)
+ );
+
+ if($r !== false && count($r) == 1 && $r[0]['account_id'] == $account_id) {
+ logger("Unable to remove the only remaining admin account");
+ return false;
+ }
+
+ $r = q("select * from account where account_id = %d limit 1",
+ intval($account_id)
+ );
+ $account_email=$r[0]['account_email'];
+
+ if(! $r) {
+ logger('account_remove: No account with id: ' . $account_id);
+ return false;
+ }
+
+ $x = q("select channel_id from channel where channel_account_id = %d",
+ intval($account_id)
+ );
+ if($x) {
+ foreach($x as $xx) {
+ channel_remove($xx['channel_id'],$local,false);
+ }
+ }
+
+ $r = q("delete from account where account_id = %d",
+ intval($account_id)
+ );
+
+
+ if ($unset_session) {
+ unset($_SESSION['authenticated']);
+ unset($_SESSION['uid']);
+ notice( sprintf(t("User '%s' deleted"),$account_email) . EOL);
+ goaway(z_root());
+ }
+ return $r;
+
+}
+
+/**
+ * @brief Removes a channel.
+ *
+ * @hooks channel_remove
+ * * \e array \b entry from channel tabel for $channel_id
+ * @param int $channel_id
+ * @param boolean $local default true
+ * @param boolean $unset_session default false
+ */
+function channel_remove($channel_id, $local = true, $unset_session = false) {
+
+ if(! $channel_id)
+ return;
+
+ logger('Removing channel: ' . $channel_id);
+ logger('local only: ' . intval($local));
+
+ $r = q("select * from channel where channel_id = %d limit 1", intval($channel_id));
+ if(! $r) {
+ logger('channel not found: ' . $channel_id);
+ return;
+ }
+
+ $channel = $r[0];
+
+ call_hooks('channel_remove', $r[0]);
+
+ if(! $local) {
+
+ $r = q("update channel set channel_deleted = '%s', channel_removed = 1 where channel_id = %d",
+ dbesc(datetime_convert()),
+ intval($channel_id)
+ );
+
+ q("delete from pconfig where uid = %d",
+ intval($channel_id)
+ );
+
+ logger('deleting hublocs',LOGGER_DEBUG);
+
+ $r = q("update hubloc set hubloc_deleted = 1 where hubloc_hash = '%s'",
+ dbesc($channel['channel_hash'])
+ );
+
+ $r = q("update xchan set xchan_deleted = 1 where xchan_hash = '%s'",
+ dbesc($channel['channel_hash'])
+ );
+
+ Zotlabs\Daemon\Master::Summon(array('Notifier','purge_all',$channel_id));
+ }
+
+
+ $r = q("select * from iconfig left join item on item.id = iconfig.iid
+ where item.uid = %d",
+ intval($channel_id)
+ );
+ if($r) {
+ foreach($r as $rr) {
+ q("delete from iconfig where iid = %d",
+ intval($rr['iid'])
+ );
+ }
+ }
+
+
+ q("DELETE FROM groups WHERE uid = %d", intval($channel_id));
+ q("DELETE FROM group_member WHERE uid = %d", intval($channel_id));
+ q("DELETE FROM event WHERE uid = %d", intval($channel_id));
+ q("DELETE FROM item WHERE uid = %d", intval($channel_id));
+ q("DELETE FROM mail WHERE channel_id = %d", intval($channel_id));
+ q("DELETE FROM notify WHERE uid = %d", intval($channel_id));
+ q("DELETE FROM photo WHERE uid = %d", intval($channel_id));
+ q("DELETE FROM attach WHERE uid = %d", intval($channel_id));
+ q("DELETE FROM profile WHERE uid = %d", intval($channel_id));
+ q("DELETE FROM pconfig WHERE uid = %d", intval($channel_id));
+
+ /// @FIXME At this stage we need to remove the file resources located under /store/$nickname
+
+ q("delete from abook where abook_xchan = '%s' and abook_self = 1 ",
+ dbesc($channel['channel_hash'])
+ );
+
+ $r = q("update channel set channel_deleted = '%s', channel_removed = 1 where channel_id = %d",
+ dbesc(datetime_convert()),
+ intval($channel_id)
+ );
+
+ // if this was the default channel, set another one as default
+ if(App::$account['account_default_channel'] == $channel_id) {
+ $r = q("select channel_id from channel where channel_account_id = %d and channel_removed = 0 limit 1",
+ intval(App::$account['account_id']),
+ intval(PAGE_REMOVED));
+ if ($r) {
+ $rr = q("update account set account_default_channel = %d where account_id = %d",
+ intval($r[0]['channel_id']),
+ intval(App::$account['account_id']));
+ logger("Default channel deleted, changing default to channel_id " . $r[0]['channel_id']);
+ }
+ else {
+ $rr = q("update account set account_default_channel = 0 where account_id = %d",
+ intval(App::$account['account_id'])
+ );
+ }
+ }
+
+ logger('deleting hublocs',LOGGER_DEBUG);
+
+ $r = q("update hubloc set hubloc_deleted = 1 where hubloc_hash = '%s' and hubloc_url = '%s' ",
+ dbesc($channel['channel_hash']),
+ dbesc(z_root())
+ );
+
+ // Do we have any valid hublocs remaining?
+
+ $hublocs = 0;
+
+ $r = q("select hubloc_id from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0",
+ dbesc($channel['channel_hash'])
+ );
+ if($r)
+ $hublocs = count($r);
+
+ if(! $hublocs) {
+ $r = q("update xchan set xchan_deleted = 1 where xchan_hash = '%s' ",
+ dbesc($channel['channel_hash'])
+ );
+ }
+
+ //remove from file system
+ $r = q("select channel_address from channel where channel_id = %d limit 1",
+ intval($channel_id)
+ );
+
+ if($r) {
+ $channel_address = $r[0]['channel_address'] ;
+ }
+ if($channel_address) {
+ $f = 'store/' . $channel_address.'/';
+ logger('delete '. $f);
+ if(is_dir($f)) {
+ @rrmdir($f);
+ }
+ }
+
+ Zotlabs\Daemon\Master::Summon(array('Directory',$channel_id));
+
+ if($channel_id == local_channel() && $unset_session) {
+ App::$session->nuke();
+ goaway(z_root());
+ }
+}
+
+/**
+ * @brief This checks if a channel is allowed to publish executable code.
+ *
+ * It is up to the caller to determine if the observer or local_channel
+ * is in fact the resource owner whose channel_id is being checked.
+ *
+ * @param int $channel_id
+ * @return boolean
+ */
+function channel_codeallowed($channel_id) {
+ if(! intval($channel_id))
+ return false;
+
+ $x = channelx_by_n($channel_id);
+ if(($x) && ($x['channel_pageflags'] & PAGE_ALLOWCODE))
+ return true;
+
+ return false;
+
+}
+
+function anon_identity_init($reqvars) {
+
+ $x = [ 'request_vars' => $reqvars, 'xchan' => null, 'success' => 'unset' ];
+ call_hooks('anon_identity_init',$x);
+ if($x['success'] !== 'unset' && intval($x['success']) && $x['xchan'])
+ return $x['xchan'];
+
+ // allow a captcha handler to over-ride
+ if($x['success'] !== 'unset' && (intval($x['success']) === 0))
+ return false;
+
+
+ $anon_name = strip_tags(trim($reqvars['anonname']));
+ $anon_email = strip_tags(trim($reqvars['anonmail']));
+ $anon_url = strip_tags(trim($reqvars['anonurl']));
+
+ if(! ($anon_name && $anon_email)) {
+ logger('anonymous commenter did not complete form');
+ return false;
+ }
+
+ if(! validate_email($anon_email)) {
+ logger('enonymous email not valid');
+ return false;
+ }
+
+ if(! $anon_url)
+ $anon_url = z_root();
+
+ $hash = hash('md5',$anon_email);
+
+ $x = q("select * from xchan where xchan_guid = '%s' and xchan_hash = '%s' and xchan_network = 'unknown' limit 1",
+ dbesc($anon_email),
+ dbesc($hash)
+ );
+
+ if(! $x) {
+ xchan_store_lowlevel([
+ 'xchan_guid' => $anon_email,
+ 'xchan_hash' => $hash,
+ 'xchan_name' => $anon_name,
+ 'xchan_url' => $anon_url,
+ 'xchan_network' => 'unknown',
+ 'xchan_name_date' => datetime_convert()
+ ]);
+
+
+ $x = q("select * from xchan where xchan_guid = '%s' and xchan_hash = '%s' and xchan_network = 'unknown' limit 1",
+ dbesc($anon_email),
+ dbesc($hash)
+ );
+
+ $photo = z_root() . '/' . get_default_profile_photo(300);
+ $photos = import_xchan_photo($photo,$hash);
+ $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_guid = '%s' and xchan_hash = '%s' and xchan_network = 'unknown' ",
+ dbesc(datetime_convert()),
+ dbesc($photos[0]),
+ dbesc($photos[1]),
+ dbesc($photos[2]),
+ dbesc($photos[3]),
+ dbesc($anon_email),
+ dbesc($hash)
+ );
+
+ }
+
+ return $x[0];
+}
+
+