Merge remote-tracking branch 'upstream/master'

This commit is contained in:
zottel 2015-09-18 09:38:55 +02:00
commit 4d05d477f8
20 changed files with 392 additions and 361 deletions

View file

@ -12,7 +12,7 @@ It is written in the PHP scripting language, thus making it trivial to install o
In other words, $Projectname can run on any computing platform that comes with a web server, a MySQL-compatible database, and the PHP scripting language.
Along the way,$Projectname offers a number of unique goodies:
Along the way, $Projectname offers a number of unique goodies:
[b]Single-click user identification:[/b] meaning you can access sites on $Projectname simply by clicking on links to remote sites. Authentication just happens automagically behind the scenes. Forget about remembering multiple user names with multiple passwords when accessing different sites online.

View file

@ -190,7 +190,7 @@ When creating "Websites", content may be entered in HTML, Markdown, BB
Any content created in $Projectname remains under the control of the member (or channel) that originally created it. At any time, a member can delete a message, or a range of messages. The deletion process ensures that the content is deleted, regardless of whether it was posted on a channel's primary (home) hub, or on another hub, where the channel was remotely authenticated via Zot ($Projectname communication and authentication protocol).
[b]Media[/b]
Similar to any other modern blogging system, social network, or a micro-blogging service,$Projectname supports the uploading of files, embedding of videos, linking web pages.
Similar to any other modern blogging system, social network, or a micro-blogging service, $Projectname supports the uploading of files, embedding of videos, linking web pages.
[b]Previewing/Editing[/b]
Post can be previewed prior to sending and edited after sending.

View file

@ -13,7 +13,7 @@ Zot is a revolutionary protocol which provides [i]decentralised communications[/
Communications and social networking are an integral part of the grid. Any channel (and any services provided by that channel) can make full use of feature-rich social communications on a global scale. These communications may be public or private - and private communications comprise not only fully encrypted transport, but also encrypted storage to help protect against accidental snooping and disclosure by rogue system administrators and internet service providers.
Zot allows a wide array of background services in the grid, from offering friend suggestions, to directory services. You can also perform other things which would typically only be possibly on a centralized provider - such as "Wall to Wall" posts. Priivate/multiple profiles can be easily created, and web content can be tailored to the viewer via the [i]Affinity Slider[/i].
Zot allows a wide array of background services in the grid, from offering friend suggestions, to directory services. You can also perform other things which would typically only be possibly on a centralized provider - such as "Wall to Wall" posts. Private/multiple profiles can be easily created, and web content can be tailored to the viewer via the [i]Affinity Slider[/i].
You won't find these features at all on other decentralized communication services. In addition to providing hub (server) decentralization, perhaps the most innovative and interesting Zot feature is its provision of [i]decentralized identity[/i] services.
@ -27,11 +27,11 @@ The important bits of your identity and relationships can be backed up to a thum
Crucially, these nomadic instances are kept in sync so any instance can take over if another one is compromised or damaged. This protects you against not only major system failure, but also temporary site overloads and governmental manipulation or censorship.
Nomadic identity, single sign-on, and$Projectname's decentralization of hubs, we believe, introduce a high degree of degree of [i]resiliency[/i] and [i]persistence[/i] in internet communications, that are sorely needed amidst global trends towards corporate centralization, as well as mass and indiscriminate government surveillance and censorship.
Nomadic identity, single sign-on, and $Projectname's decentralization of hubs, we believe, introduce a high degree of degree of [i]resiliency[/i] and [i]persistence[/i] in internet communications, that are sorely needed amidst global trends towards corporate centralization, as well as mass and indiscriminate government surveillance and censorship.
As you browse the grid, viewing channels and their unique content, you are seamlessly authenticated as you go, even across completely different server hubs. No passwords to enter. Nothing to type. You're just greeted by name on every new site you visit.
How does Zot do that? We call it [i]magic-auth[/i], because$Projectname hides the details of the complexities that go into single sign-on logins, and nomadic identities, from the experience of browsing on the grid. This is one of the design goals of$Projectname: to increase privacy, and freedom on the web, while reducing the complexity and tedium brought by the need to enter new passwords and user names for every different sight that someone might visit online.
How does Zot do that? We call it [i]magic-auth[/i], because $Projectname hides the details of the complexities that go into single sign-on logins, and nomadic identities, from the experience of browsing on the grid. This is one of the design goals of $Projectname: to increase privacy, and freedom on the web, while reducing the complexity and tedium brought by the need to enter new passwords and user names for every different sight that someone might visit online.
You login only once on your home hub (or any nomadic backup hub you have chosen). This allows you to access any authenticated services provided anywhere in the grid - such as shopping, blogs, forums, and access to private information. This is just like the services offered by large corporate providers with huge user databases; however you can be a member of this community, as well as a server on this network using a $35 Rasberry Pi. Your password isn't stored on a thousand different sites, or even worse, only on a few sites like Google and Facebook, beyond your direct control.

View file

@ -1053,16 +1053,20 @@ function discover_by_webbie($webbie) {
$webbie = strtolower($webbie);
$x = webfinger_rfc7033($webbie);
$x = webfinger_rfc7033($webbie,true);
if($x && array_key_exists('links',$x) && $x['links']) {
foreach($x['links'] as $link) {
if(array_key_exists('rel',$link) && $link['rel'] == 'http://purl.org/zot/protocol') {
logger('discover_by_webbie: zot found for ' . $webbie, LOGGER_DEBUG);
$z = z_fetch_url($link['href']);
if($z['success']) {
$j = json_decode($z['body'],true);
$i = import_xchan($j);
return true;
if(array_key_exists('zot',$x) && $x['zot']['success'])
$i = import_xchan($x['zot']);
else {
$z = z_fetch_url($link['href']);
if($z['success']) {
$j = json_decode($z['body'],true);
$i = import_xchan($j);
return true;
}
}
}
}
@ -1282,7 +1286,7 @@ LSIeXnd14lQYK/uxW/8cTFjcmddsKxeXysoQxbSa9VdDK+KkpZdgYXYrTTofXs6v+
}
function webfinger_rfc7033($webbie) {
function webfinger_rfc7033($webbie,$zot = false) {
if(! strpos($webbie,'@'))
@ -1292,7 +1296,7 @@ function webfinger_rfc7033($webbie) {
$resource = 'acct:' . $webbie;
$s = z_fetch_url('https://' . $rhs . '/.well-known/webfinger?resource=' . $resource);
$s = z_fetch_url('https://' . $rhs . '/.well-known/webfinger?f=&resource=' . $resource . (($zot) ? '&zot=1' : ''));
if($s['success'])
$j = json_decode($s['body'],true);

View file

@ -3404,3 +3404,291 @@ function zot_process_message_request($data) {
return $ret;
}
function zotinfo($arr) {
$ret = array('success' => false);
$zhash = ((x($arr,'guid_hash')) ? $arr['guid_hash'] : '');
$zguid = ((x($arr,'guid')) ? $arr['guid'] : '');
$zguid_sig = ((x($arr,'guid_sig')) ? $arr['guid_sig'] : '');
$zaddr = ((x($arr,'address')) ? $arr['address'] : '');
$ztarget = ((x($arr,'target')) ? $arr['target'] : '');
$zsig = ((x($arr,'target_sig')) ? $arr['target_sig'] : '');
$zkey = ((x($arr,'key')) ? $arr['key'] : '');
$mindate = ((x($arr,'mindate')) ? $arr['mindate'] : '');
$feed = ((x($arr,'feed')) ? intval($arr['feed']) : 0);
if($ztarget) {
if((! $zkey) || (! $zsig) || (! rsa_verify($ztarget,base64url_decode($zsig),$zkey))) {
logger('zfinger: invalid target signature');
$ret['message'] = t("invalid target signature");
return($ret);
}
}
$r = null;
if(strlen($zhash)) {
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
where channel_hash = '%s' limit 1",
dbesc($zhash)
);
}
elseif(strlen($zguid) && strlen($zguid_sig)) {
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
where channel_guid = '%s' and channel_guid_sig = '%s' limit 1",
dbesc($zguid),
dbesc($zguid_sig)
);
}
elseif(strlen($zaddr)) {
if(strpos($zaddr,'[system]') === false) { /* normal address lookup */
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
where ( channel_address = '%s' or xchan_addr = '%s' ) limit 1",
dbesc($zaddr),
dbesc($zaddr)
);
}
else {
/**
* The special address '[system]' will return a system channel if one has been defined,
* Or the first valid channel we find if there are no system channels.
*
* This is used by magic-auth if we have no prior communications with this site - and
* returns an identity on this site which we can use to create a valid hub record so that
* we can exchange signed messages. The precise identity is irrelevant. It's the hub
* information that we really need at the other end - and this will return it.
*
*/
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
where channel_system = 1 order by channel_id limit 1");
if(! $r) {
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
where channel_removed = 0 order by channel_id limit 1");
}
}
}
else {
$ret['message'] = 'Invalid request';
return($ret);
}
if(! $r) {
$ret['message'] = 'Item not found.';
return($ret);
}
$e = $r[0];
$id = $e['channel_id'];
$sys_channel = (intval($e['channel_system']) ? true : false);
$special_channel = (($e['channel_pageflags'] & PAGE_PREMIUM) ? true : false);
$adult_channel = (($e['channel_pageflags'] & PAGE_ADULT) ? true : false);
$censored = (($e['channel_pageflags'] & PAGE_CENSORED) ? true : false);
$searchable = (($e['channel_pageflags'] & PAGE_HIDDEN) ? false : true);
$deleted = (intval($e['xchan_deleted']) ? true : false);
if($deleted || $censored || $sys_channel)
$searchable = false;
$public_forum = false;
$role = get_pconfig($e['channel_id'],'system','permissions_role');
if($role === 'forum' || $role === 'repository') {
$public_forum = true;
}
else {
// check if it has characteristics of a public forum based on custom permissions.
$t = q("select abook_my_perms from abook where abook_channel = %d and abook_self = 1 limit 1",
intval($e['channel_id'])
);
if(($t) && (($t[0]['abook_my_perms'] & PERMS_W_TAGWALL) && (! ($t[0]['abook_my_perms'] & PERMS_W_STREAM))))
$public_forum = true;
}
// This is for birthdays and keywords, but must check access permissions
$p = q("select * from profile where uid = %d and is_default = 1",
intval($e['channel_id'])
);
$profile = array();
if($p) {
if(! intval($p[0]['publish']))
$searchable = false;
$profile['description'] = $p[0]['pdesc'];
$profile['birthday'] = $p[0]['dob'];
if(($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'],$e['channel_timezone'])) !== ''))
$profile['next_birthday'] = $bd;
if($age = age($p[0]['dob'],$e['channel_timezone'],''))
$profile['age'] = $age;
$profile['gender'] = $p[0]['gender'];
$profile['marital'] = $p[0]['marital'];
$profile['sexual'] = $p[0]['sexual'];
$profile['locale'] = $p[0]['locality'];
$profile['region'] = $p[0]['region'];
$profile['postcode'] = $p[0]['postal_code'];
$profile['country'] = $p[0]['country_name'];
$profile['about'] = $p[0]['about'];
$profile['homepage'] = $p[0]['homepage'];
$profile['hometown'] = $p[0]['hometown'];
if($p[0]['keywords']) {
$tags = array();
$k = explode(' ',$p[0]['keywords']);
if($k) {
foreach($k as $kk) {
if(trim($kk," \t\n\r\0\x0B,")) {
$tags[] = trim($kk," \t\n\r\0\x0B,");
}
}
}
if($tags)
$profile['keywords'] = $tags;
}
}
$ret['success'] = true;
// Communication details
$ret['guid'] = $e['xchan_guid'];
$ret['guid_sig'] = $e['xchan_guid_sig'];
$ret['key'] = $e['xchan_pubkey'];
$ret['name'] = $e['xchan_name'];
$ret['name_updated'] = $e['xchan_name_date'];
$ret['address'] = $e['xchan_addr'];
$ret['photo_mimetype'] = $e['xchan_photo_mimetype'];
$ret['photo'] = $e['xchan_photo_l'];
$ret['photo_updated'] = $e['xchan_photo_date'];
$ret['url'] = $e['xchan_url'];
$ret['connections_url']= (($e['xchan_connurl']) ? $e['xchan_connurl'] : z_root() . '/poco/' . $e['channel_address']);
$ret['target'] = $ztarget;
$ret['target_sig'] = $zsig;
$ret['searchable'] = $searchable;
$ret['adult_content'] = $adult_channel;
$ret['public_forum'] = $public_forum;
if($deleted)
$ret['deleted'] = $deleted;
// premium or other channel desiring some contact with potential followers before connecting.
// This is a template - %s will be replaced with the follow_url we discover for the return channel.
if($special_channel)
$ret['connect_url'] = z_root() . '/connect/' . $e['channel_address'];
// This is a template for our follow url, %s will be replaced with a webbie
$ret['follow_url'] = z_root() . '/follow?f=&url=%s';
$ztarget_hash = (($ztarget && $zsig)
? make_xchan_hash($ztarget,$zsig)
: '' );
$permissions = get_all_perms($e['channel_id'],$ztarget_hash,false);
if($ztarget_hash) {
$permissions['connected'] = false;
$b = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc($ztarget_hash),
intval($e['channel_id'])
);
if($b)
$permissions['connected'] = true;
}
$ret['permissions'] = (($ztarget && $zkey) ? crypto_encapsulate(json_encode($permissions),$zkey) : $permissions);
if($permissions['view_profile'])
$ret['profile'] = $profile;
// array of (verified) hubs this channel uses
$x = zot_encode_locations($e);
if($x)
$ret['locations'] = $x;
$ret['site'] = array();
$ret['site']['url'] = z_root();
$ret['site']['url_sig'] = base64url_encode(rsa_sign(z_root(),$e['channel_prvkey']));
$dirmode = get_config('system','directory_mode');
if(($dirmode === false) || ($dirmode == DIRECTORY_MODE_NORMAL))
$ret['site']['directory_mode'] = 'normal';
if($dirmode == DIRECTORY_MODE_PRIMARY)
$ret['site']['directory_mode'] = 'primary';
elseif($dirmode == DIRECTORY_MODE_SECONDARY)
$ret['site']['directory_mode'] = 'secondary';
elseif($dirmode == DIRECTORY_MODE_STANDALONE)
$ret['site']['directory_mode'] = 'standalone';
if($dirmode != DIRECTORY_MODE_NORMAL)
$ret['site']['directory_url'] = z_root() . '/dirsearch';
// hide detailed site information if you're off the grid
if($dirmode != DIRECTORY_MODE_STANDALONE) {
$register_policy = intval(get_config('system','register_policy'));
if($register_policy == REGISTER_CLOSED)
$ret['site']['register_policy'] = 'closed';
if($register_policy == REGISTER_APPROVE)
$ret['site']['register_policy'] = 'approve';
if($register_policy == REGISTER_OPEN)
$ret['site']['register_policy'] = 'open';
$access_policy = intval(get_config('system','access_policy'));
if($access_policy == ACCESS_PRIVATE)
$ret['site']['access_policy'] = 'private';
if($access_policy == ACCESS_PAID)
$ret['site']['access_policy'] = 'paid';
if($access_policy == ACCESS_FREE)
$ret['site']['access_policy'] = 'free';
if($access_policy == ACCESS_TIERED)
$ret['site']['access_policy'] = 'tiered';
$ret['site']['accounts'] = account_total();
require_once('include/identity.php');
$ret['site']['channels'] = channel_total();
$ret['site']['version'] = PLATFORM_NAME . ' ' . RED_VERSION . '[' . DB_UPDATE_VERSION . ']';
$ret['site']['admin'] = get_config('system','admin_email');
$a = get_app();
$visible_plugins = array();
if(is_array($a->plugins) && count($a->plugins)) {
$r = q("select * from addon where hidden = 0");
if($r)
foreach($r as $rr)
$visible_plugins[] = $rr['name'];
}
$ret['site']['plugins'] = $visible_plugins;
$ret['site']['sitehash'] = get_config('system','location_hash');
$ret['site']['sitename'] = get_config('system','sitename');
$ret['site']['sellpage'] = get_config('system','sellpage');
$ret['site']['location'] = get_config('system','site_location');
$ret['site']['realm'] = get_directory_realm();
}
call_hooks('zot_finger',$ret);
return($ret);
}

View file

@ -125,8 +125,7 @@ function mail_content(&$a) {
$tpl = get_markup_template('mail_head.tpl');
$header = replace_macros($tpl, array(
'$messages' => t('Messages'),
'$tab_content' => $tab_content
'$header' => t('Messages'),
));
if((argc() == 3) && (argv(1) === 'drop')) {
@ -160,8 +159,6 @@ function mail_content(&$a) {
if((argc() > 1) && (argv(1) === 'new')) {
$o .= $header;
$plaintext = true;
$tpl = get_markup_template('msg-header.tpl');

View file

@ -25,11 +25,7 @@ function message_content(&$a) {
$cipher = 'aes256';
$tpl = get_markup_template('mail_head.tpl');
$header = replace_macros($tpl, array(
'$messages' => t('Messages'),
'$tab_content' => $tab_content
));
if((argc() == 3) && (argv(1) === 'dropconv')) {
if(! intval(argv(2)))
@ -42,9 +38,6 @@ function message_content(&$a) {
}
if(argc() == 1) {
// list messages
$o .= $header;
// private_messages_list() can do other more complicated stuff, for now keep it simple
@ -55,24 +48,33 @@ function message_content(&$a) {
return $o;
}
$tpl = get_markup_template('mail_list.tpl');
$messages = array();
foreach($r as $rr) {
$o .= replace_macros($tpl, array(
'$id' => $rr['id'],
'$from_name' => $rr['from']['xchan_name'],
'$from_url' => chanlink_hash($rr['from_xchan']),
'$from_photo' => $rr['from']['xchan_photo_s'],
'$to_name' => $rr['to']['xchan_name'],
'$to_url' => chanlink_hash($rr['to_xchan']),
'$to_photo' => $rr['to']['xchan_photo_s'],
'$subject' => (($rr['seen']) ? $rr['title'] : '<strong>' . $rr['title'] . '</strong>'),
'$delete' => t('Delete conversation'),
'$body' => smilies(bbcode($rr['body'])),
'$date' => datetime_convert('UTC',date_default_timezone_get(),$rr['created'], t('D, d M Y - g:i A')),
'$seen' => $rr['seen']
));
$messages[] = array(
'id' => $rr['id'],
'from_name' => $rr['from']['xchan_name'],
'from_url' => chanlink_hash($rr['from_xchan']),
'from_photo' => $rr['from']['xchan_photo_s'],
'to_name' => $rr['to']['xchan_name'],
'to_url' => chanlink_hash($rr['to_xchan']),
'to_photo' => $rr['to']['xchan_photo_s'],
'subject' => (($rr['seen']) ? $rr['title'] : '<strong>' . $rr['title'] . '</strong>'),
'delete' => t('Delete conversation'),
'body' => smilies(bbcode($rr['body'])),
'date' => datetime_convert('UTC',date_default_timezone_get(),$rr['created'], t('D, d M Y - g:i A')),
'seen' => $rr['seen']
);
}
$tpl = get_markup_template('mail_head.tpl');
$o = replace_macros($tpl, array(
'$header' => t('Messages'),
'$messages' => $messages
));
$o .= alt_pager($a,count($r));
return $o;
}

View file

@ -15,7 +15,7 @@ function webfinger_content(&$a) {
if(x($_GET,'addr')) {
$addr = trim($_GET['addr']);
if(strpos($addr,'@') !== false) {
$res = webfinger_rfc7033($addr);
$res = webfinger_rfc7033($addr,true);
if(! $res)
$res = old_webfinger($addr);
}

View file

@ -1,5 +1,7 @@
<?php
require_once('include/zot.php');
function wfinger_init(&$a) {
$result = array();
@ -11,14 +13,13 @@ function wfinger_init(&$a) {
elseif(x($_SERVER,'SERVER_PORT') && (intval($_SERVER['SERVER_PORT']) == 443))
$scheme = 'https';
// Don't complain to me - I'm just implementing the spec.
$zot = intval($_REQUEST['zot']);
if($scheme !== 'https') {
if(($scheme !== 'https') && (! $zot)) {
header($_SERVER["SERVER_PROTOCOL"] . ' ' . 500 . ' ' . 'Webfinger requires HTTPS');
killme();
}
$zot = intval($_REQUEST['zot']);
$resource = $_REQUEST['resource'];
logger('webfinger: ' . $resource,LOGGER_DEBUG);
@ -48,7 +49,6 @@ function wfinger_init(&$a) {
}
header('Access-Control-Allow-Origin: *');
header('Content-type: application/jrd+json');
@ -107,11 +107,8 @@ function wfinger_init(&$a) {
);
if($zot) {
// @FIXME do a lookup straightaway and return the zot-info packet
$_REQUEST['address'] = $r[0]['xchan_address'];
// get a zotinfo packet and return it with webfinger
$result['zot'] = zotinfo(array('address' => $r[0]['xchan_addr']));
}
}
else {

View file

@ -5,286 +5,9 @@ function zfinger_init(&$a) {
require_once('include/zot.php');
require_once('include/crypto.php');
$ret = array('success' => false);
$zhash = ((x($_REQUEST,'guid_hash')) ? $_REQUEST['guid_hash'] : '');
$zguid = ((x($_REQUEST,'guid')) ? $_REQUEST['guid'] : '');
$zguid_sig = ((x($_REQUEST,'guid_sig')) ? $_REQUEST['guid_sig'] : '');
$zaddr = ((x($_REQUEST,'address')) ? $_REQUEST['address'] : '');
$ztarget = ((x($_REQUEST,'target')) ? $_REQUEST['target'] : '');
$zsig = ((x($_REQUEST,'target_sig')) ? $_REQUEST['target_sig'] : '');
$zkey = ((x($_REQUEST,'key')) ? $_REQUEST['key'] : '');
$mindate = ((x($_REQUEST,'mindate')) ? $_REQUEST['mindate'] : '');
$feed = ((x($_REQUEST,'feed')) ? intval($_REQUEST['feed']) : 0);
$x = zotinfo($_REQUEST);
json_return_and_die($x);
if($ztarget) {
if((! $zkey) || (! $zsig) || (! rsa_verify($ztarget,base64url_decode($zsig),$zkey))) {
logger('zfinger: invalid target signature');
$ret['message'] = t("invalid target signature");
json_return_and_die($ret);
}
}
$r = null;
if(strlen($zhash)) {
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
where channel_hash = '%s' limit 1",
dbesc($zhash)
);
}
elseif(strlen($zguid) && strlen($zguid_sig)) {
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
where channel_guid = '%s' and channel_guid_sig = '%s' limit 1",
dbesc($zguid),
dbesc($zguid_sig)
);
}
elseif(strlen($zaddr)) {
if(strpos($zaddr,'[system]') === false) { /* normal address lookup */
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
where ( channel_address = '%s' or xchan_addr = '%s' ) limit 1",
dbesc($zaddr),
dbesc($zaddr)
);
}
else {
/**
* The special address '[system]' will return a system channel if one has been defined,
* Or the first valid channel we find if there are no system channels.
*
* This is used by magic-auth if we have no prior communications with this site - and
* returns an identity on this site which we can use to create a valid hub record so that
* we can exchange signed messages. The precise identity is irrelevant. It's the hub
* information that we really need at the other end - and this will return it.
*
*/
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
where channel_system = 1 order by channel_id limit 1");
if(! $r) {
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
where channel_removed = 0 order by channel_id limit 1");
}
}
}
else {
$ret['message'] = 'Invalid request';
json_return_and_die($ret);
}
if(! $r) {
$ret['message'] = 'Item not found.';
json_return_and_die($ret);
}
$e = $r[0];
$id = $e['channel_id'];
$sys_channel = (intval($e['channel_system']) ? true : false);
$special_channel = (($e['channel_pageflags'] & PAGE_PREMIUM) ? true : false);
$adult_channel = (($e['channel_pageflags'] & PAGE_ADULT) ? true : false);
$censored = (($e['channel_pageflags'] & PAGE_CENSORED) ? true : false);
$searchable = (($e['channel_pageflags'] & PAGE_HIDDEN) ? false : true);
$deleted = (intval($e['xchan_deleted']) ? true : false);
if($deleted || $censored || $sys_channel)
$searchable = false;
$public_forum = false;
$role = get_pconfig($e['channel_id'],'system','permissions_role');
if($role === 'forum' || $role === 'repository') {
$public_forum = true;
}
else {
// check if it has characteristics of a public forum based on custom permissions.
$t = q("select abook_my_perms from abook where abook_channel = %d and abook_self = 1 limit 1",
intval($e['channel_id'])
);
if(($t) && (($t[0]['abook_my_perms'] & PERMS_W_TAGWALL) && (! ($t[0]['abook_my_perms'] & PERMS_W_STREAM))))
$public_forum = true;
}
// This is for birthdays and keywords, but must check access permissions
$p = q("select * from profile where uid = %d and is_default = 1",
intval($e['channel_id'])
);
$profile = array();
if($p) {
if(! intval($p[0]['publish']))
$searchable = false;
$profile['description'] = $p[0]['pdesc'];
$profile['birthday'] = $p[0]['dob'];
if(($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'],$e['channel_timezone'])) !== ''))
$profile['next_birthday'] = $bd;
if($age = age($p[0]['dob'],$e['channel_timezone'],''))
$profile['age'] = $age;
$profile['gender'] = $p[0]['gender'];
$profile['marital'] = $p[0]['marital'];
$profile['sexual'] = $p[0]['sexual'];
$profile['locale'] = $p[0]['locality'];
$profile['region'] = $p[0]['region'];
$profile['postcode'] = $p[0]['postal_code'];
$profile['country'] = $p[0]['country_name'];
$profile['about'] = $p[0]['about'];
$profile['homepage'] = $p[0]['homepage'];
$profile['hometown'] = $p[0]['hometown'];
if($p[0]['keywords']) {
$tags = array();
$k = explode(' ',$p[0]['keywords']);
if($k) {
foreach($k as $kk) {
if(trim($kk," \t\n\r\0\x0B,")) {
$tags[] = trim($kk," \t\n\r\0\x0B,");
}
}
}
if($tags)
$profile['keywords'] = $tags;
}
}
$ret['success'] = true;
// Communication details
$ret['guid'] = $e['xchan_guid'];
$ret['guid_sig'] = $e['xchan_guid_sig'];
$ret['key'] = $e['xchan_pubkey'];
$ret['name'] = $e['xchan_name'];
$ret['name_updated'] = $e['xchan_name_date'];
$ret['address'] = $e['xchan_addr'];
$ret['photo_mimetype'] = $e['xchan_photo_mimetype'];
$ret['photo'] = $e['xchan_photo_l'];
$ret['photo_updated'] = $e['xchan_photo_date'];
$ret['url'] = $e['xchan_url'];
$ret['connections_url']= (($e['xchan_connurl']) ? $e['xchan_connurl'] : z_root() . '/poco/' . $e['channel_address']);
$ret['target'] = $ztarget;
$ret['target_sig'] = $zsig;
$ret['searchable'] = $searchable;
$ret['adult_content'] = $adult_channel;
$ret['public_forum'] = $public_forum;
if($deleted)
$ret['deleted'] = $deleted;
// premium or other channel desiring some contact with potential followers before connecting.
// This is a template - %s will be replaced with the follow_url we discover for the return channel.
if($special_channel)
$ret['connect_url'] = z_root() . '/connect/' . $e['channel_address'];
// This is a template for our follow url, %s will be replaced with a webbie
$ret['follow_url'] = z_root() . '/follow?f=&url=%s';
$ztarget_hash = (($ztarget && $zsig)
? make_xchan_hash($ztarget,$zsig)
: '' );
$permissions = get_all_perms($e['channel_id'],$ztarget_hash,false);
if($ztarget_hash) {
$permissions['connected'] = false;
$b = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc($ztarget_hash),
intval($e['channel_id'])
);
if($b)
$permissions['connected'] = true;
}
$ret['permissions'] = (($ztarget && $zkey) ? crypto_encapsulate(json_encode($permissions),$zkey) : $permissions);
if($permissions['view_profile'])
$ret['profile'] = $profile;
// array of (verified) hubs this channel uses
$x = zot_encode_locations($e);
if($x)
$ret['locations'] = $x;
$ret['site'] = array();
$ret['site']['url'] = z_root();
$ret['site']['url_sig'] = base64url_encode(rsa_sign(z_root(),$e['channel_prvkey']));
$dirmode = get_config('system','directory_mode');
if(($dirmode === false) || ($dirmode == DIRECTORY_MODE_NORMAL))
$ret['site']['directory_mode'] = 'normal';
if($dirmode == DIRECTORY_MODE_PRIMARY)
$ret['site']['directory_mode'] = 'primary';
elseif($dirmode == DIRECTORY_MODE_SECONDARY)
$ret['site']['directory_mode'] = 'secondary';
elseif($dirmode == DIRECTORY_MODE_STANDALONE)
$ret['site']['directory_mode'] = 'standalone';
if($dirmode != DIRECTORY_MODE_NORMAL)
$ret['site']['directory_url'] = z_root() . '/dirsearch';
// hide detailed site information if you're off the grid
if($dirmode != DIRECTORY_MODE_STANDALONE) {
$register_policy = intval(get_config('system','register_policy'));
if($register_policy == REGISTER_CLOSED)
$ret['site']['register_policy'] = 'closed';
if($register_policy == REGISTER_APPROVE)
$ret['site']['register_policy'] = 'approve';
if($register_policy == REGISTER_OPEN)
$ret['site']['register_policy'] = 'open';
$access_policy = intval(get_config('system','access_policy'));
if($access_policy == ACCESS_PRIVATE)
$ret['site']['access_policy'] = 'private';
if($access_policy == ACCESS_PAID)
$ret['site']['access_policy'] = 'paid';
if($access_policy == ACCESS_FREE)
$ret['site']['access_policy'] = 'free';
if($access_policy == ACCESS_TIERED)
$ret['site']['access_policy'] = 'tiered';
$ret['site']['accounts'] = account_total();
require_once('include/identity.php');
$ret['site']['channels'] = channel_total();
$ret['site']['version'] = PLATFORM_NAME . ' ' . RED_VERSION . '[' . DB_UPDATE_VERSION . ']';
$ret['site']['admin'] = get_config('system','admin_email');
$visible_plugins = array();
if(is_array($a->plugins) && count($a->plugins)) {
$r = q("select * from addon where hidden = 0");
if($r)
foreach($r as $rr)
$visible_plugins[] = $rr['name'];
}
$ret['site']['plugins'] = $visible_plugins;
$ret['site']['sitehash'] = get_config('system','location_hash');
$ret['site']['sitename'] = get_config('system','sitename');
$ret['site']['sellpage'] = get_config('system','sellpage');
$ret['site']['location'] = get_config('system','site_location');
$ret['site']['realm'] = get_directory_realm();
}
call_hooks('zot_finger',$ret);
json_return_and_die($ret);
}

View file

@ -79,7 +79,7 @@ function theme_post(&$a) {
function redbasic_form(&$a, $arr) {
$scheme_choices = array();
$scheme_choices["---"] = t("Light (Hubzilla default)");
$scheme_choices["---"] = t("Focus (Hubzilla default)");
$files = glob('view/theme/redbasic/schema/*.php');
if($files) {
foreach($files as $file) {

View file

@ -34,5 +34,8 @@
$toolicon_activecolour = '#fff';
if (! $font_colour)
$font_colour = "#ccc";
if (! $converse_width)
$converse_width = "1024";

View file

@ -34,6 +34,9 @@
$comment_border_colour = "rgba(255,255,255,0.8)";
if (! $font_colour)
$font_colour = "#000";
if (! $converse_width)
$converse_width = "1024";

View file

@ -34,3 +34,5 @@
$comment_border_colour = "rgba(0,0,0,0.8)";
if (! $font_colour)
$font_colour = "#46D43F";
if (! $converse_width)
$converse_width = "1024";

View file

@ -34,3 +34,5 @@
$comment_border_colour = "rgba(0,0,0,0.8)";
if (! $font_colour)
$font_colour = "#fff";
if (! $converse_width)
$converse_width = "1024";

View file

@ -1,4 +1,7 @@
{{include file="field_select.tpl" field=$schema}}
{{include file="field_checkbox.tpl" field=$align_left}}
{{include file="field_checkbox.tpl" field=$narrow_navbar}}
{{include file="field_input.tpl" field=$converse_width}}
{{if $expert}}
{{include file="field_colorinput.tpl" field=$nav_bg}}
{{include file="field_colorinput.tpl" field=$nav_gradient_top}}
@ -26,11 +29,7 @@
{{include file="field_input.tpl" field=$shadow}}
{{include file="field_input.tpl" field=$top_photo}}
{{include file="field_input.tpl" field=$reply_photo}}
{{/if}}
{{include file="field_input.tpl" field=$converse_width}}
{{include file="field_checkbox.tpl" field=$align_left}}
{{include file="field_checkbox.tpl" field=$narrow_navbar}}
{{if $expert}}
<script>
$(function(){
$('#id_redbasic_nav_bg,#id_redbasic_nav_gradient_top,#id_redbasic_nav_gradient_bottom,#id_redbasic_nav_active_gradient_top,#id_redbasic_nav_active_gradient_bottom').colorpicker({format: 'rgba'});

View file

@ -1,12 +1,16 @@
<h3>{{$prvmsg_header}}</h3>
<div class="generic-content-wrapper">
{{foreach $mails as $mail}}
{{include file="mail_conv.tpl"}}
{{/foreach}}
<div class="section-title-wrapper">
<h2>{{$prvmsg_header}}</h2>
</div>
<div class="section-content-wrapper">
{{foreach $mails as $mail}}
{{include file="mail_conv.tpl"}}
{{/foreach}}
{{if $canreply}}
{{include file="prv_message.tpl"}}
{{else}}
{{$unknown_text}}
{{/if}}
{{if $canreply}}
{{include file="prv_message.tpl"}}
{{else}}
{{$unknown_text}}
{{/if}}
</div>
</div>

View file

@ -1,3 +1,10 @@
<h3>{{$messages}}</h3>
{{$tab_content}}
<div class="generic-content-wrapper">
<div class="section-title-wrapper">
<h2>{{$header}}</h2>
</div>
<div class="section-content-wrapper">
{{foreach $messages as $message}}
{{include file="mail_list.tpl"}}
{{/foreach}}
</div>
</div>

View file

@ -1,8 +1,6 @@
<div class="generic-content-wrapper" id="mail-list-wrapper">
<a href="{{$from_url}}" class ="mail-list" ><img class="mail-list-sender-photo" src="{{$from_photo}}" alt="{{$from_name}}" /></a>
<span class="mail-list">{{$from_name}}</span>
<span class="mail-list {{if $seen}}seen{{else}}unseen{{/if}}"><a href="mail/{{$id}}" class="mail-link">{{$subject}}</a></span>
<span class="mail-list" title="{{$date}}">{{$date}}</span>
<span class="mail-list mail-list-remove" class="btn btn-default btn-sm"><a href="message/dropconv/{{$id}}" onclick="return confirmDelete();" title="{{$delete}}" class="btn btn-default btn-sm" ><i class="icon-trash mail-icons drop-icons"></i></a></span>
<div class="clear">&nbsp;</div>
</div>
<a href="{{$message.from_url}}" class ="mail-list" ><img class="mail-list-sender-photo" src="{{$message.from_photo}}" alt="{{$message.from_name}}" /></a>
<span class="mail-list">{{$message.from_name}}</span>
<span class="mail-list {{if $message.seen}}seen{{else}}unseen{{/if}}"><a href="mail/{{$message.id}}" class="mail-link">{{$message.subject}}</a></span>
<span class="mail-list" title="{{$message.date}}">{{$message.date}}</span>
<span class="mail-list mail-list-remove" class="btn btn-default btn-sm"><a href="message/dropconv/{{$message.id}}" onclick="return confirmDelete();" title="{{$message.delete}}" class="btn btn-default btn-sm" ><i class="icon-trash mail-icons drop-icons"></i></a></span>
<div class="clear"></div>

View file

@ -26,6 +26,9 @@
{{include file="field_input.tpl" field=$photo_path}}
{{include file="field_input.tpl" field=$attach_path}}
<div class="settings-submit-wrapper" >
<button type="submit" name="submit" class="btn btn-primary">{{$submit}}</button>
</div>
</div>
</div>
</div>
@ -75,6 +78,9 @@
{{include file="field_checkbox.tpl" field=$blocktags}}
{{include file="field_input.tpl" field=$expire}}
</div>
<div class="settings-submit-wrapper" >
<button type="submit" name="submit" class="btn btn-primary">{{$submit}}</button>
</div>
</div>
</div>
</div>
@ -124,14 +130,10 @@
{{include file="field_input.tpl" field=$evdays}}
</div>
</div>
</div>
</div>
</div>
<div class="panel">
<div class"section-subtitle-wrapper" role="tab" id="form-buttons">
<div class="settings-submit-wrapper" >
<button type="submit" name="submit" class="btn btn-primary">{{$submit}}</button>
</div>
</div>
</div>
</div>
{{if $menus}}