Merge develop into 20180425_-_fix_help_aside

This commit is contained in:
rabuzarus 2018-04-30 14:56:25 +02:00
commit 0c0b715c63
84 changed files with 26334 additions and 25911 deletions

1
.gitignore vendored
View file

@ -9,6 +9,7 @@ include/jquery-1.4.2.min.js
favicon.* favicon.*
home.html home.html
addon addon
*.orig
*~ *~
robots.txt robots.txt

110
boot.php
View file

@ -1018,114 +1018,6 @@ function get_max_import_size()
return (x($a->config, 'max_import_size') ? $a->config['max_import_size'] : 0); return (x($a->config, 'max_import_size') ? $a->config['max_import_size'] : 0);
} }
function current_theme()
{
$app_base_themes = ['duepuntozero', 'dispy', 'quattro'];
$a = get_app();
$page_theme = null;
// Find the theme that belongs to the user whose stuff we are looking at
if ($a->profile_uid && ($a->profile_uid != local_user())) {
$r = q(
"select theme from user where uid = %d limit 1",
intval($a->profile_uid)
);
if (DBM::is_result($r)) {
$page_theme = $r[0]['theme'];
}
}
// Allow folks to over-rule user themes and always use their own on their own site.
// This works only if the user is on the same server
if ($page_theme && local_user() && (local_user() != $a->profile_uid)) {
if (PConfig::get(local_user(), 'system', 'always_my_theme')) {
$page_theme = null;
}
}
// $mobile_detect = new Mobile_Detect();
// $is_mobile = $mobile_detect->isMobile() || $mobile_detect->isTablet();
$is_mobile = $a->is_mobile || $a->is_tablet;
$standard_system_theme = Config::get('system', 'theme', '');
$standard_theme_name = ((isset($_SESSION) && x($_SESSION, 'theme')) ? $_SESSION['theme'] : $standard_system_theme);
if ($is_mobile) {
if (isset($_SESSION['show-mobile']) && !$_SESSION['show-mobile']) {
$theme_name = $standard_theme_name;
} else {
$system_theme = Config::get('system', 'mobile-theme', '');
if ($system_theme == '') {
$system_theme = $standard_system_theme;
}
$theme_name = ((isset($_SESSION) && x($_SESSION, 'mobile-theme')) ? $_SESSION['mobile-theme'] : $system_theme);
if ($theme_name === '---') {
// user has selected to have the mobile theme be the same as the normal one
$theme_name = $standard_theme_name;
if ($page_theme) {
$theme_name = $page_theme;
}
}
}
} else {
$theme_name = $standard_theme_name;
if ($page_theme) {
$theme_name = $page_theme;
}
}
if ($theme_name
&& (file_exists('view/theme/' . $theme_name . '/style.css')
|| file_exists('view/theme/' . $theme_name . '/style.php'))
) {
return($theme_name);
}
foreach ($app_base_themes as $t) {
if (file_exists('view/theme/' . $t . '/style.css')
|| file_exists('view/theme/' . $t . '/style.php')
) {
return($t);
}
}
$fallback = array_merge(glob('view/theme/*/style.css'), glob('view/theme/*/style.php'));
if (count($fallback)) {
return (str_replace('view/theme/', '', substr($fallback[0], 0, -10)));
}
/// @TODO No final return statement?
}
/**
* @brief Return full URL to theme which is currently in effect.
*
* Provide a sane default if nothing is chosen or the specified theme does not exist.
*
* @return string
*/
function current_theme_url()
{
$a = get_app();
$t = current_theme();
$opts = (($a->profile_uid) ? '?f=&puid=' . $a->profile_uid : '');
if (file_exists('view/theme/' . $t . '/style.php')) {
return('view/theme/' . $t . '/style.pcss' . $opts);
}
return('view/theme/' . $t . '/style.css');
}
function feed_birthday($uid, $tz) function feed_birthday($uid, $tz)
{ {
/** /**
@ -1292,7 +1184,7 @@ function get_server()
$server = Config::get("system", "directory"); $server = Config::get("system", "directory");
if ($server == "") { if ($server == "") {
$server = "http://dir.friendica.social"; $server = "https://dir.friendica.social";
} }
return($server); return($server);

View file

@ -470,11 +470,15 @@ These Fields are not added below (yet). They are here to for bug search.
* @brief SQL join for contacts that are needed for displaying items * @brief SQL join for contacts that are needed for displaying items
*/ */
function item_joins() { function item_joins() {
return "STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND return sprintf("STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
(NOT `contact`.`blocked` OR `contact`.`pending`) AND NOT `contact`.`blocked`
AND ((NOT `contact`.`readonly` AND NOT `contact`.`pending` AND (`contact`.`rel` IN (%s, %s)))
OR `contact`.`self` OR (`item`.`id` != `item`.`parent`))
LEFT JOIN `contact` AS `author` ON `author`.`id`=`item`.`author-id` LEFT JOIN `contact` AS `author` ON `author`.`id`=`item`.`author-id`
LEFT JOIN `contact` AS `owner` ON `owner`.`id`=`item`.`owner-id` LEFT JOIN `contact` AS `owner` ON `owner`.`id`=`item`.`owner-id`
LEFT JOIN `event` ON `event-id` = `event`.`id`"; LEFT JOIN `event` ON `event-id` = `event`.`id`",
CONTACT_IS_SHARING, CONTACT_IS_FRIEND
);
} }
/** /**

View file

@ -1,5 +1,6 @@
<?php <?php
use Friendica\App;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Database\DBM; use Friendica\Database\DBM;
@ -24,7 +25,7 @@ class dba {
private static $in_transaction = false; private static $in_transaction = false;
private static $relation = []; private static $relation = [];
public static function connect($serveraddr, $user, $pass, $db, $install = false) { public static function connect($serveraddr, $user, $pass, $db) {
if (!is_null(self::$db)) { if (!is_null(self::$db)) {
return true; return true;
} }
@ -51,7 +52,7 @@ class dba {
return false; return false;
} }
if ($install) { if ($a->mode == App::MODE_INSTALL) {
// server has to be a non-empty string that is not 'localhost' and not an IP // server has to be a non-empty string that is not 'localhost' and not an IP
if (strlen($server) && ($server !== 'localhost') && filter_var($server, FILTER_VALIDATE_IP) === false) { if (strlen($server) && ($server !== 'localhost') && filter_var($server, FILTER_VALIDATE_IP) === false) {
if (! dns_get_record($server, DNS_A + DNS_CNAME)) { if (! dns_get_record($server, DNS_A + DNS_CNAME)) {
@ -93,6 +94,7 @@ class dba {
// No suitable SQL driver was found. // No suitable SQL driver was found.
if (!self::$connected) { if (!self::$connected) {
self::$driver = null;
self::$db = null; self::$db = null;
} }
$a->save_timestamp($stamp1, "network"); $a->save_timestamp($stamp1, "network");

View file

@ -513,7 +513,7 @@ function load_view_file($s) {
return $content; return $content;
} }
$theme = current_theme(); $theme = $a->getCurrentTheme();
if (file_exists("$d/theme/$theme/$b")) { if (file_exists("$d/theme/$theme/$b")) {
$stamp1 = microtime(true); $stamp1 = microtime(true);
@ -637,7 +637,7 @@ function logger($msg, $level = 0) {
// turn off logger in install mode // turn off logger in install mode
if ( if (
$a->module == 'install' $a->mode == App::MODE_INSTALL
|| !dba::$connected || !dba::$connected
) { ) {
return; return;
@ -709,7 +709,7 @@ function dlogger($msg, $level = 0) {
// turn off logger in install mode // turn off logger in install mode
if ( if (
$a->module == 'install' $a->mode == App::MODE_INSTALL
|| !dba::$connected || !dba::$connected
) { ) {
return; return;
@ -1249,7 +1249,7 @@ function prepare_body(array &$item, $attach = false, $is_preview = false)
// Compile eventual content filter reasons // Compile eventual content filter reasons
$filter_reasons = []; $filter_reasons = [];
if (!$is_preview && !($item['self'] && local_user() == $item['uid'])) { if (!$is_preview && public_contact() != $item['author-id']) {
if (!empty($item['content-warning']) && (!local_user() || !PConfig::get(local_user(), 'system', 'disable_cw', false))) { if (!empty($item['content-warning']) && (!local_user() || !PConfig::get(local_user(), 'system', 'disable_cw', false))) {
$filter_reasons[] = L10n::t('Content warning: %s', $item['content-warning']); $filter_reasons[] = L10n::t('Content warning: %s', $item['content-warning']);
} }

View file

@ -31,16 +31,8 @@ BaseObject::setApp($a);
// The value is set to "true" by default in boot.php // The value is set to "true" by default in boot.php
$a->backend = false; $a->backend = false;
/** // Only load config if found, don't suppress errors
* Load the configuration file which contains our DB credentials. if (!$a->mode == App::MODE_INSTALL) {
* Ignore errors. If the file doesn't exist or is empty, we are running in
* installation mode.
*/
$install = ((file_exists('.htconfig.php') && filesize('.htconfig.php')) ? false : true);
// Only load config if found, don't surpress errors
if (!$install) {
include ".htconfig.php"; include ".htconfig.php";
} }
@ -50,7 +42,7 @@ if (!$install) {
require_once "include/dba.php"; require_once "include/dba.php";
if (!$install) { if (!$a->mode == App::MODE_INSTALL) {
$result = dba::connect($db_host, $db_user, $db_pass, $db_data); $result = dba::connect($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data); unset($db_host, $db_user, $db_pass, $db_data);
@ -85,7 +77,7 @@ if (!$install) {
Addon::loadHooks(); Addon::loadHooks();
Addon::callHooks('init_1'); Addon::callHooks('init_1');
$maintenance = Config::get('system', 'maintenance'); $a->checkMaintenanceMode();
} }
$lang = L10n::getBrowserLanguage(); $lang = L10n::getBrowserLanguage();
@ -129,7 +121,7 @@ if ((x($_SESSION, 'language')) && ($_SESSION['language'] !== $lang)) {
L10n::loadTranslationTable($lang); L10n::loadTranslationTable($lang);
} }
if ((x($_GET, 'zrl')) && (!$install && !$maintenance)) { if ((x($_GET, 'zrl')) && $a->mode == App::MODE_NORMAL) {
// Only continue when the given profile link seems valid // Only continue when the given profile link seems valid
// Valid profile links contain a path with "/profile/" and no query parameters // Valid profile links contain a path with "/profile/" and no query parameters
if ((parse_url($_GET['zrl'], PHP_URL_QUERY) == "") if ((parse_url($_GET['zrl'], PHP_URL_QUERY) == "")
@ -181,9 +173,9 @@ $_SESSION['last_updated'] = defaults($_SESSION, 'last_updated', []);
// in install mode, any url loads install module // in install mode, any url loads install module
// but we need "view" module for stylesheet // but we need "view" module for stylesheet
if ($install && $a->module!="view") { if ($a->mode == App::MODE_INSTALL && $a->module!="view") {
$a->module = 'install'; $a->module = 'install';
} elseif ($maintenance && $a->module!="view") { } elseif ($a->mode == App::MODE_MAINTENANCE && $a->module!="view") {
$a->module = 'maintenance'; $a->module = 'maintenance';
} else { } else {
check_url($a); check_url($a);
@ -330,7 +322,7 @@ if (strlen($a->module)) {
/** /**
* Load current theme info * Load current theme info
*/ */
$theme_info_file = "view/theme/".current_theme()."/theme.php"; $theme_info_file = 'view/theme/' . $a->getCurrentTheme() . '/theme.php';
if (file_exists($theme_info_file)) { if (file_exists($theme_info_file)) {
require_once $theme_info_file; require_once $theme_info_file;
} }
@ -342,7 +334,7 @@ if (! x($a->page, 'content')) {
$a->page['content'] = ''; $a->page['content'] = '';
} }
if (!$install && !$maintenance) { if ($a->mode == App::MODE_NORMAL) {
Addon::callHooks('page_content_top', $a->page['content']); Addon::callHooks('page_content_top', $a->page['content']);
} }
@ -363,8 +355,8 @@ if ($a->module_loaded) {
$func($a); $func($a);
} }
if (function_exists(str_replace('-', '_', current_theme()) . '_init')) { if (function_exists(str_replace('-', '_', $a->getCurrentTheme()) . '_init')) {
$func = str_replace('-', '_', current_theme()) . '_init'; $func = str_replace('-', '_', $a->getCurrentTheme()) . '_init';
$func($a); $func($a);
} }
@ -402,8 +394,8 @@ if ($a->module_loaded) {
$a->page['content'] .= $arr['content']; $a->page['content'] .= $arr['content'];
} }
if (function_exists(str_replace('-', '_', current_theme()) . '_content_loaded')) { if (function_exists(str_replace('-', '_', $a->getCurrentTheme()) . '_content_loaded')) {
$func = str_replace('-', '_', current_theme()) . '_content_loaded'; $func = str_replace('-', '_', $a->getCurrentTheme()) . '_content_loaded';
$func($a); $func($a);
} }
} }
@ -478,7 +470,7 @@ if ($a->is_mobile || $a->is_tablet) {
*/ */
if (!$a->theme['stylesheet']) { if (!$a->theme['stylesheet']) {
$stylesheet = current_theme_url(); $stylesheet = $a->getCurrentThemeStylesheetPath();
} else { } else {
$stylesheet = $a->theme['stylesheet']; $stylesheet = $a->theme['stylesheet'];
} }

View file

@ -1120,6 +1120,7 @@ function admin_page_site_post(App $a)
} }
Config::set('system', 'language', $language); Config::set('system', 'language', $language);
Config::set('system', 'theme', $theme); Config::set('system', 'theme', $theme);
Theme::install($theme);
if ($theme_mobile == '---') { if ($theme_mobile == '---') {
Config::delete('system', 'mobile-theme'); Config::delete('system', 'mobile-theme');

View file

@ -5,11 +5,9 @@
use Friendica\App; use Friendica\App;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\Install;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Database\DBStructure;
use Friendica\Object\Image;
use Friendica\Util\Network;
use Friendica\Util\Temporal; use Friendica\Util\Temporal;
$install_wizard_pass = 1; $install_wizard_pass = 1;
@ -27,6 +25,8 @@ function install_init(App $a) {
$a->config['system']['theme'] = "../install"; $a->config['system']['theme'] = "../install";
$a->theme['stylesheet'] = System::baseUrl()."/view/install/style.css"; $a->theme['stylesheet'] = System::baseUrl()."/view/install/style.css";
Install::setInstallMode();
global $install_wizard_pass; global $install_wizard_pass;
if (x($_POST, 'pass')) { if (x($_POST, 'pass')) {
$install_wizard_pass = intval($_POST['pass']); $install_wizard_pass = intval($_POST['pass']);
@ -51,7 +51,7 @@ function install_post(App $a) {
$phpath = notags(trim($_POST['phpath'])); $phpath = notags(trim($_POST['phpath']));
require_once("include/dba.php"); require_once("include/dba.php");
if (!dba::connect($dbhost, $dbuser, $dbpass, $dbdata, true)) { if (!dba::connect($dbhost, $dbuser, $dbpass, $dbdata)) {
$a->data['db_conn_failed'] = true; $a->data['db_conn_failed'] = true;
} }
@ -70,36 +70,9 @@ function install_post(App $a) {
$rino = 1; $rino = 1;
// connect to db // connect to db
dba::connect($dbhost, $dbuser, $dbpass, $dbdata, true); dba::connect($dbhost, $dbuser, $dbpass, $dbdata);
$tpl = get_markup_template('htconfig.tpl'); Install::install($urlpath, $dbhost, $dbuser, $dbpass, $dbdata, $phpath, $timezone, $language, $adminmail, $rino);
$txt = replace_macros($tpl,[
'$dbhost' => $dbhost,
'$dbuser' => $dbuser,
'$dbpass' => $dbpass,
'$dbdata' => $dbdata,
'$timezone' => $timezone,
'$language' => $language,
'$urlpath' => $urlpath,
'$phpath' => $phpath,
'$adminmail' => $adminmail,
'$rino' => $rino
]);
$result = file_put_contents('.htconfig.php', $txt);
if (! $result) {
$a->data['txt'] = $txt;
}
$errors = load_database();
if ($errors) {
$a->data['db_failed'] = $errors;
} else {
$a->data['db_installed'] = true;
}
return; return;
break; break;
@ -167,37 +140,11 @@ function install_content(App $a) {
switch ($install_wizard_pass) { switch ($install_wizard_pass) {
case 1: { // System check case 1: { // System check
$checks = [];
check_funcs($checks);
check_imagik($checks);
check_htconfig($checks);
check_smarty3($checks);
check_keys($checks);
if (x($_POST, 'phpath')) { if (x($_POST, 'phpath')) {
$phpath = notags(trim($_POST['phpath'])); $phpath = notags(trim($_POST['phpath']));
} }
check_php($phpath, $checks); list($checks, $checkspassed) = Install::check($phpath);
check_htaccess($checks);
/// @TODO Maybe move this out?
function check_passed($v, $c) {
if ($c['required']) {
$v = $v && $c['status'];
}
return $v;
}
$checkspassed = array_reduce($checks, "check_passed", true);
$tpl = get_markup_template('install_checks.tpl'); $tpl = get_markup_template('install_checks.tpl');
$o .= replace_macros($tpl, [ $o .= replace_macros($tpl, [
@ -296,238 +243,6 @@ function install_content(App $a) {
} }
} }
/**
* checks : array passed to template
* title : string
* status : boolean
* required : boolean
* help : string optional
*/
function check_add(&$checks, $title, $status, $required, $help) {
$checks[] = [
'title' => $title,
'status' => $status,
'required' => $required,
'help' => $help,
];
}
function check_php(&$phpath, &$checks) {
$passed = $passed2 = $passed3 = false;
if (strlen($phpath)) {
$passed = file_exists($phpath);
} else {
$phpath = trim(shell_exec('which php'));
$passed = strlen($phpath);
}
$help = "";
if (!$passed) {
$help .= L10n::t('Could not find a command line version of PHP in the web server PATH.'). EOL;
$help .= L10n::t("If you don't have a command line version of PHP installed on your server, you will not be able to run the background processing. See <a href='https://github.com/friendica/friendica/blob/master/doc/Install.md#set-up-the-worker'>'Setup the worker'</a>") . EOL;
$help .= EOL . EOL;
$tpl = get_markup_template('field_input.tpl');
$help .= replace_macros($tpl, [
'$field' => ['phpath', L10n::t('PHP executable path'), $phpath, L10n::t('Enter full path to php executable. You can leave this blank to continue the installation.')],
]);
$phpath = "";
}
check_add($checks, L10n::t('Command line PHP').($passed?" (<tt>$phpath</tt>)":""), $passed, false, $help);
if ($passed) {
$cmd = "$phpath -v";
$result = trim(shell_exec($cmd));
$passed2 = ( strpos($result, "(cli)") !== false);
list($result) = explode("\n", $result);
$help = "";
if (!$passed2) {
$help .= L10n::t("PHP executable is not the php cli binary \x28could be cgi-fgci version\x29"). EOL;
$help .= L10n::t('Found PHP version: ')."<tt>$result</tt>";
}
check_add($checks, L10n::t('PHP cli binary'), $passed2, true, $help);
}
if ($passed2) {
$str = autoname(8);
$cmd = "$phpath testargs.php $str";
$result = trim(shell_exec($cmd));
$passed3 = $result == $str;
$help = "";
if (!$passed3) {
$help .= L10n::t('The command line version of PHP on your system does not have "register_argc_argv" enabled.'). EOL;
$help .= L10n::t('This is required for message delivery to work.');
}
check_add($checks, L10n::t('PHP register_argc_argv'), $passed3, true, $help);
}
}
function check_keys(&$checks) {
$help = '';
$res = false;
if (function_exists('openssl_pkey_new')) {
$res = openssl_pkey_new([
'digest_alg' => 'sha1',
'private_key_bits' => 4096,
'encrypt_key' => false
]);
}
// Get private key
if (! $res) {
$help .= L10n::t('Error: the "openssl_pkey_new" function on this system is not able to generate encryption keys'). EOL;
$help .= L10n::t('If running under Windows, please see "http://www.php.net/manual/en/openssl.installation.php".');
}
check_add($checks, L10n::t('Generate encryption keys'), $res, true, $help);
}
function check_funcs(&$checks) {
$ck_funcs = [];
check_add($ck_funcs, L10n::t('libCurl PHP module'), true, true, "");
check_add($ck_funcs, L10n::t('GD graphics PHP module'), true, true, "");
check_add($ck_funcs, L10n::t('OpenSSL PHP module'), true, true, "");
check_add($ck_funcs, L10n::t('PDO or MySQLi PHP module'), true, true, "");
check_add($ck_funcs, L10n::t('mb_string PHP module'), true, true, "");
check_add($ck_funcs, L10n::t('XML PHP module'), true, true, "");
check_add($ck_funcs, L10n::t('iconv PHP module'), true, true, "");
check_add($ck_funcs, L10n::t('POSIX PHP module'), true, true, "");
if (function_exists('apache_get_modules')) {
if (! in_array('mod_rewrite',apache_get_modules())) {
check_add($ck_funcs, L10n::t('Apache mod_rewrite module'), false, true, L10n::t('Error: Apache webserver mod-rewrite module is required but not installed.'));
} else {
check_add($ck_funcs, L10n::t('Apache mod_rewrite module'), true, true, "");
}
}
if (! function_exists('curl_init')) {
$ck_funcs[0]['status'] = false;
$ck_funcs[0]['help'] = L10n::t('Error: libCURL PHP module required but not installed.');
}
if (! function_exists('imagecreatefromjpeg')) {
$ck_funcs[1]['status'] = false;
$ck_funcs[1]['help'] = L10n::t('Error: GD graphics PHP module with JPEG support required but not installed.');
}
if (! function_exists('openssl_public_encrypt')) {
$ck_funcs[2]['status'] = false;
$ck_funcs[2]['help'] = L10n::t('Error: openssl PHP module required but not installed.');
}
if (! function_exists('mysqli_connect') && !class_exists('pdo')) {
$ck_funcs[3]['status'] = false;
$ck_funcs[3]['help'] = L10n::t('Error: PDO or MySQLi PHP module required but not installed.');
}
if (!function_exists('mysqli_connect') && class_exists('pdo') && !in_array('mysql', PDO::getAvailableDrivers())) {
$ck_funcs[3]['status'] = false;
$ck_funcs[3]['help'] = L10n::t('Error: The MySQL driver for PDO is not installed.');
}
if (! function_exists('mb_strlen')) {
$ck_funcs[4]['status'] = false;
$ck_funcs[4]['help'] = L10n::t('Error: mb_string PHP module required but not installed.');
}
if (! function_exists('iconv_strlen')) {
$ck_funcs[6]['status'] = false;
$ck_funcs[6]['help'] = L10n::t('Error: iconv PHP module required but not installed.');
}
if (! function_exists('posix_kill')) {
$ck_funcs[7]['status'] = false;
$ck_funcs[7]['help'] = L10n::t('Error: POSIX PHP module required but not installed.');
}
$checks = array_merge($checks, $ck_funcs);
// check for XML DOM Documents being able to be generated
try {
$xml = new DOMDocument();
} catch (Exception $e) {
$ck_funcs[5]['status'] = false;
$ck_funcs[5]['help'] = L10n::t('Error, XML PHP module required but not installed.');
}
}
function check_htconfig(&$checks) {
$status = true;
$help = "";
if ((file_exists('.htconfig.php') && !is_writable('.htconfig.php')) ||
(!file_exists('.htconfig.php') && !is_writable('.'))) {
$status = false;
$help = L10n::t('The web installer needs to be able to create a file called ".htconfig.php" in the top folder of your web server and it is unable to do so.') .EOL;
$help .= L10n::t('This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can.').EOL;
$help .= L10n::t('At the end of this procedure, we will give you a text to save in a file named .htconfig.php in your Friendica top folder.').EOL;
$help .= L10n::t('You can alternatively skip this procedure and perform a manual installation. Please see the file "INSTALL.txt" for instructions.').EOL;
}
check_add($checks, L10n::t('.htconfig.php is writable'), $status, false, $help);
}
function check_smarty3(&$checks) {
$status = true;
$help = "";
if (!is_writable('view/smarty3')) {
$status = false;
$help = L10n::t('Friendica uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering.') .EOL;
$help .= L10n::t('In order to store these compiled templates, the web server needs to have write access to the directory view/smarty3/ under the Friendica top level folder.').EOL;
$help .= L10n::t("Please ensure that the user that your web server runs as \x28e.g. www-data\x29 has write access to this folder.").EOL;
$help .= L10n::t("Note: as a security measure, you should give the web server write access to view/smarty3/ only--not the template files \x28.tpl\x29 that it contains.").EOL;
}
check_add($checks, L10n::t('view/smarty3 is writable'), $status, true, $help);
}
function check_htaccess(&$checks) {
$status = true;
$help = "";
if (function_exists('curl_init')) {
$test = Network::fetchUrl(System::baseUrl()."/install/testrewrite");
if ($test != "ok") {
$test = Network::fetchUrl(normalise_link(System::baseUrl()."/install/testrewrite"));
}
if ($test != "ok") {
$status = false;
$help = L10n::t('Url rewrite in .htaccess is not working. Check your server configuration.');
}
check_add($checks, L10n::t('Url rewrite is working'), $status, true, $help);
} else {
// cannot check modrewrite if libcurl is not installed
/// @TODO Maybe issue warning here?
}
}
function check_imagik(&$checks) {
$imagick = false;
$gif = false;
if (class_exists('Imagick')) {
$imagick = true;
$supported = Image::supportedTypes();
if (array_key_exists('image/gif', $supported)) {
$gif = true;
}
}
if ($imagick == false) {
check_add($checks, L10n::t('ImageMagick PHP extension is not installed'), $imagick, false, "");
} else {
check_add($checks, L10n::t('ImageMagick PHP extension is installed'), $imagick, false, "");
if ($imagick) {
check_add($checks, L10n::t('ImageMagick supports GIF'), $gif, false, "");
}
}
}
function manual_config(App $a) { function manual_config(App $a) {
$data = htmlentities($a->data['txt'],ENT_COMPAT, 'UTF-8'); $data = htmlentities($a->data['txt'],ENT_COMPAT, 'UTF-8');
$o = L10n::t('The database configuration file ".htconfig.php" could not be written. Please use the enclosed text to create a configuration file in your web server root.'); $o = L10n::t('The database configuration file ".htconfig.php" could not be written. Please use the enclosed text to create a configuration file in your web server root.');
@ -544,12 +259,6 @@ function load_database_rem($v, $i) {
} }
} }
function load_database() {
$errors = DBStructure::update(false, true, true);
return $errors;
}
function what_next() { function what_next() {
$baseurl = System::baseUrl(); $baseurl = System::baseUrl();
return return

View file

@ -836,14 +836,10 @@ function networkThreadedView(App $a, $update, $parent)
STRAIGHT_JOIN (SELECT `oid` FROM `term` WHERE `term` IN STRAIGHT_JOIN (SELECT `oid` FROM `term` WHERE `term` IN
(SELECT SUBSTR(`term`, 2) FROM `search` WHERE `uid` = ? AND `term` LIKE '#%') AND `otype` = ? AND `type` = ? AND `uid` = 0) AS `term` (SELECT SUBSTR(`term`, 2) FROM `search` WHERE `uid` = ? AND `term` LIKE '#%') AND `otype` = ? AND `type` = ? AND `uid` = 0) AS `term`
ON `item`.`id` = `term`.`oid` ON `item`.`id` = `term`.`oid`
STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`author-id` STRAIGHT_JOIN `contact` AS `author` ON `author`.`id` = `item`.`author-id`
AND (`item`.`parent-uri` != `item`.`uri`
OR `contact`.`uid` = `item`.`uid` AND `contact`.`self`
OR `contact`.`rel` IN (?, ?) AND NOT `contact`.`readonly`)
WHERE `item`.`uid` = 0 AND `item`.$ordering < ? AND `item`.$ordering > ? WHERE `item`.`uid` = 0 AND `item`.$ordering < ? AND `item`.$ordering > ?
AND NOT `contact`.`hidden` AND NOT `contact`.`blocked`" . $sql_tag_nets, AND NOT `author`.`hidden` AND NOT `author`.`blocked`" . $sql_tag_nets,
local_user(), TERM_OBJ_POST, TERM_HASHTAG, local_user(), TERM_OBJ_POST, TERM_HASHTAG,
CONTACT_IS_SHARING, CONTACT_IS_FRIEND,
$top_limit, $bottom_limit); $top_limit, $bottom_limit);
$data = dba::inArray($items); $data = dba::inArray($items);
@ -860,8 +856,13 @@ function networkThreadedView(App $a, $update, $parent)
$s[$item['uri']] = $item; $s[$item['uri']] = $item;
} }
foreach ($data as $item) { foreach ($data as $item) {
// Don't show hash tag posts from blocked or ignored contacts
$condition = ["`nurl` = ? AND `uid` = ? AND (`blocked` OR `readonly`)",
normalise_link($item['author-link']), local_user()];
if (!dba::exists('contact', $condition)) {
$s[$item['uri']] = $item; $s[$item['uri']] = $item;
} }
}
$r = $s; $r = $s;
} }
} }

View file

@ -12,6 +12,7 @@ use Friendica\Core\Config;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Theme;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Model\Contact; use Friendica\Model\Contact;
@ -354,6 +355,7 @@ function settings_post(App $a)
theme_post($a); theme_post($a);
} }
} }
Theme::install($theme);
$r = q("UPDATE `user` SET `theme` = '%s' WHERE `uid` = %d", $r = q("UPDATE `user` SET `theme` = '%s' WHERE `uid` = %d",
dbesc($theme), dbesc($theme),

View file

@ -32,6 +32,10 @@ require_once 'include/text.php';
*/ */
class App class App
{ {
const MODE_NORMAL = 0;
const MODE_INSTALL = 1;
const MODE_MAINTENANCE = 2;
public $module_loaded = false; public $module_loaded = false;
public $module_class = null; public $module_class = null;
public $query_string; public $query_string;
@ -52,6 +56,7 @@ class App
public $argv; public $argv;
public $argc; public $argc;
public $module; public $module;
public $mode = App::MODE_NORMAL;
public $pager; public $pager;
public $strings; public $strings;
public $basepath; public $basepath;
@ -288,6 +293,14 @@ class App
// Register template engines // Register template engines
$this->register_template_engine('Friendica\Render\FriendicaSmartyEngine'); $this->register_template_engine('Friendica\Render\FriendicaSmartyEngine');
/**
* Load the configuration file which contains our DB credentials.
* Ignore errors. If the file doesn't exist or is empty, we are running in
* installation mode. *
*/
$this->mode = ((file_exists('.htconfig.php') && filesize('.htconfig.php')) ? App::MODE_NORMAL : App::MODE_INSTALL);
self::$a = $this; self::$a = $this;
} }
@ -1067,4 +1080,100 @@ class App
return $sender_email; return $sender_email;
} }
/**
* @note Checks, if the App is in the Maintenance-Mode
*
* @return boolean
*/
public function checkMaintenanceMode()
{
if (Config::get('system', 'maintenance')) {
$this->mode = App::MODE_MAINTENANCE;
return true;
}
return false;
}
/**
* Returns the current theme name.
*
* @return string
*/
public function getCurrentTheme()
{
if (!$this->current_theme) {
$this->computeCurrentTheme();
}
return $this->current_theme;
}
/**
* Computes the current theme name based on the node settings, the user settings and the device type
*
* @throws Exception
*/
private function computeCurrentTheme()
{
$system_theme = Config::get('system', 'theme');
if (!$system_theme) {
throw new Exception(L10n::t('No system theme config value set.'));
}
// Sane default
$this->current_theme = $system_theme;
$allowed_themes = explode(',', Config::get('system', 'allowed_themes', $system_theme));
$page_theme = null;
// Find the theme that belongs to the user whose stuff we are looking at
if ($this->profile_uid && ($this->profile_uid != local_user())) {
// Allow folks to override user themes and always use their own on their own site.
// This works only if the user is on the same server
$user = dba::selectFirst('user', ['theme'], ['uid' => $this->profile_uid]);
if (DBM::is_result($user) && !PConfig::get(local_user(), 'system', 'always_my_theme')) {
$page_theme = $user['theme'];
}
}
$user_theme = defaults($_SESSION, 'theme', $system_theme);
// Specific mobile theme override
if (($this->is_mobile || $this->is_tablet) && defaults($_SESSION, 'show-mobile', true)) {
$system_mobile_theme = Config::get('system', 'mobile-theme');
$user_mobile_theme = defaults($_SESSION, 'mobile-theme', $system_mobile_theme);
// --- means same mobile theme as desktop
if (!empty($user_mobile_theme) && $user_mobile_theme !== '---') {
$user_theme = $user_mobile_theme;
}
}
if ($page_theme) {
$theme_name = $page_theme;
} else {
$theme_name = $user_theme;
}
if ($theme_name
&& in_array($theme_name, $allowed_themes)
&& (file_exists('view/theme/' . $theme_name . '/style.css')
|| file_exists('view/theme/' . $theme_name . '/style.php'))
) {
$this->current_theme = $theme_name;
}
}
/**
* @brief Return full URL to theme which is currently in effect.
*
* Provide a sane default if nothing is chosen or the specified theme does not exist.
*
* @return string
*/
public function getCurrentThemeStylesheetPath()
{
return Core\Theme::getStylesheetPath($this->getCurrentTheme());
}
} }

View file

@ -228,14 +228,15 @@ class Addon
/** /**
* @brief Calls a single hook. * @brief Calls a single hook.
* *
* @param \Friendica\App $a
* @param string $name of the hook to call * @param string $name of the hook to call
* @param array $hook Hook data * @param array $hook Hook data
* @param string|array &$data to transmit to the callback handler * @param string|array &$data to transmit to the callback handler
*/ */
public static function callSingleHook($a, $name, $hook, &$data = null) public static function callSingleHook(\Friendica\App $a, $name, $hook, &$data = null)
{ {
// Don't run a theme's hook if the user isn't using the theme // Don't run a theme's hook if the user isn't using the theme
if (strpos($hook[0], 'view/theme/') !== false && strpos($hook[0], 'view/theme/'.current_theme()) === false) { if (strpos($hook[0], 'view/theme/') !== false && strpos($hook[0], 'view/theme/' . $a->getCurrentTheme()) === false) {
return; return;
} }

View file

@ -5,6 +5,7 @@ namespace Friendica\Core\Console;
use Asika\SimpleConsole\Console; use Asika\SimpleConsole\Console;
use dba; use dba;
use Friendica\App; use Friendica\App;
use Friendica\Core\Install;
require_once 'mod/install.php'; require_once 'mod/install.php';
require_once 'include/dba.php'; require_once 'include/dba.php';
@ -43,6 +44,8 @@ HELP;
$db_data = ''; $db_data = '';
require_once 'htconfig.php'; require_once 'htconfig.php';
Install::setInstallMode();
$this->out(" Complete!\n\n"); $this->out(" Complete!\n\n");
// Check basic setup // Check basic setup
@ -74,7 +77,7 @@ HELP;
// Install database // Install database
$this->out("Inserting data into database...\n"); $this->out("Inserting data into database...\n");
$checkResults['data'] = load_database(); $checkResults['data'] = Install::installDatabaseStructure();
if ($checkResults['data'] !== '') { if ($checkResults['data'] !== '') {
throw new \RuntimeException("ERROR: DB Database creation error. Is the DB empty?\n"); throw new \RuntimeException("ERROR: DB Database creation error. Is the DB empty?\n");
@ -101,14 +104,14 @@ HELP;
{ {
$checks = []; $checks = [];
check_funcs($checks); Install::checkFunctions($checks);
check_imagik($checks); Install::checkImagick($checks);
check_htconfig($checks); Install::checkHtConfig($checks);
check_smarty3($checks); Install::checkSmarty3($checks);
check_keys($checks); Install::checkKeys($checks);
if (!empty($app->config['php_path'])) { if (!empty($app->config['php_path'])) {
check_php($app->config['php_path'], $checks); Install::checkPHP($app->config['php_path'], $checks);
} else { } else {
throw new \RuntimeException(" ERROR: The php_path is not set in the config. Please check the file .htconfig.php.\n"); throw new \RuntimeException(" ERROR: The php_path is not set in the config. Please check the file .htconfig.php.\n");
} }
@ -135,7 +138,7 @@ HELP;
); );
if (!dba::connect($db_host, $db_user, $db_pass, $db_data, true)) { if (!dba::connect($db_host, $db_user, $db_pass, $db_data)) {
$result['status'] = false; $result['status'] = false;
$result['help'] = 'Failed, please check your MySQL settings and credentials.'; $result['help'] = 'Failed, please check your MySQL settings and credentials.';
} }

428
src/Core/Install.php Normal file
View file

@ -0,0 +1,428 @@
<?php
/**
* @file src/Core/Install.php
*/
namespace Friendica\Core;
use Friendica\BaseObject;
use Friendica\App;
use Friendica\Database\DBStructure;
use Friendica\Object\Image;
use Friendica\Util\Network;
use Exception;
use DOMDocument;
/**
* Contains methods for installation purpose of Friendica
*/
class Install extends BaseObject
{
/**
* Sets the install-mode for further methods
*/
public static function setInstallMode()
{
self::getApp()->mode = App::MODE_INSTALL;
}
/**
* Checks the current installation environment. There are optional and mandatory checks.
*
* @param string $phpath Optional path to the PHP binary (Default is 'php')
*
* @return array First element is a list of all checks and their results,
* the second element is a list of passed checks
*/
public static function check($phpath = 'php')
{
$checks = [];
self::checkFunctions($checks);
self::checkImagick($checks);
self::checkHtConfig($checks);
self::checkSmarty3($checks);
self::checkKeys($checks);
self::checkPHP($phpath, $checks);
self::checkHtAccess($checks);
$checkspassed = array_reduce($checks,
function ($v, $c) {
if ($c['require']) {
$v = $v && $c['status'];
}
return $v;
},
true);
return array($checks, $checkspassed);
}
/**
* Executes the installation of Friendica in the given environment.
* - Creates `.htconfig.php`
* - Installs Database Structure
*
* @param string $urlpath Path based on the URL of Friendica (e.g. '/friendica')
* @param string $dbhost Hostname/IP of the Friendica Database
* @param string $dbuser Username of the Database connection credentials
* @param string $dbpass Password of the Database connection credentials
* @param string $dbdata Name of the Database
* @param string $phpath Path to the PHP-Binary (e.g. 'php' or '/usr/bin/php')
* @param string $timezone Timezone of the Friendica Installaton (e.g. 'Europe/Berlin')
* @param string $language 2-letter ISO 639-1 code (eg. 'en')
* @param string $adminmail Mail-Adress of the administrator
* @param int $rino Rino-enabled (1 = true, 0 = false)
*/
public static function install($urlpath, $dbhost, $dbuser, $dbpass, $dbdata, $phpath, $timezone, $language, $adminmail, $rino = 1)
{
$tpl = get_markup_template('htconfig.tpl');
$txt = replace_macros($tpl,[
'$dbhost' => $dbhost,
'$dbuser' => $dbuser,
'$dbpass' => $dbpass,
'$dbdata' => $dbdata,
'$timezone' => $timezone,
'$language' => $language,
'$urlpath' => $urlpath,
'$phpath' => $phpath,
'$adminmail' => $adminmail,
'$rino' => $rino
]);
$result = file_put_contents('.htconfig.php', $txt);
if (! $result) {
self::getApp()->data['txt'] = $txt;
}
$errors = self::installDatabaseStructure();
if ($errors) {
self::getApp()->data['db_failed'] = $errors;
} else {
self::getApp()->data['db_installed'] = true;
}
}
/**
* Adds new checks to the array $checks
*
* @param array $checks The list of all checks (by-ref parameter!)
* @param string $title The title of the current check
* @param bool $status 1 = check passed, 0 = check not passed
* @param bool $required 1 = check is mandatory, 0 = check is optional
* @param string $help A help-string for the current check
* @param string $error_msg Optional. A error message, if the current check failed
*/
private static function addCheck(&$checks, $title, $status, $required, $help, $error_msg = "")
{
$checks[] = [
'title' => $title,
'status' => $status,
'required' => $required,
'help' => $help,
'error_msg' => $error_msg,
];
}
/**
* PHP Check
*
* Checks the PHP environment.
*
* - Checks if a PHP binary is available
* - Checks if it is the CLI version
* - Checks if "register_argc_argv" is enabled
*
* @param string $phpath Optional. The Path to the PHP-Binary
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkPHP(&$phpath, &$checks)
{
$passed = $passed2 = $passed3 = false;
if (strlen($phpath)) {
$passed = file_exists($phpath);
} else {
$phpath = trim(shell_exec('which php'));
$passed = strlen($phpath);
}
$help = "";
if (!$passed) {
$help .= L10n::t('Could not find a command line version of PHP in the web server PATH.') . EOL;
$help .= L10n::t("If you don't have a command line version of PHP installed on your server, you will not be able to run the background processing. See <a href='https://github.com/friendica/friendica/blob/master/doc/Install.md#set-up-the-worker'>'Setup the worker'</a>") . EOL;
$help .= EOL . EOL;
$tpl = get_markup_template('field_input.tpl');
$help .= replace_macros($tpl, [
'$field' => ['phpath', L10n::t('PHP executable path'), $phpath, L10n::t('Enter full path to php executable. You can leave this blank to continue the installation.')],
]);
$phpath = "";
}
self::addCheck($checks, L10n::t('Command line PHP').($passed?" (<tt>$phpath</tt>)":""), $passed, false, $help);
if ($passed) {
$cmd = "$phpath -v";
$result = trim(shell_exec($cmd));
$passed2 = (strpos($result, "(cli)") !== false);
list($result) = explode("\n", $result);
$help = "";
if (!$passed2) {
$help .= L10n::t("PHP executable is not the php cli binary \x28could be cgi-fgci version\x29") . EOL;
$help .= L10n::t('Found PHP version: ') . "<tt>$result</tt>";
}
self::addCheck($checks, L10n::t('PHP cli binary'), $passed2, true, $help);
}
if ($passed2) {
$str = autoname(8);
$cmd = "$phpath testargs.php $str";
$result = trim(shell_exec($cmd));
$passed3 = $result == $str;
$help = "";
if (!$passed3) {
$help .= L10n::t('The command line version of PHP on your system does not have "register_argc_argv" enabled.') . EOL;
$help .= L10n::t('This is required for message delivery to work.');
}
self::addCheck($checks, L10n::t('PHP register_argc_argv'), $passed3, true, $help);
}
}
/**
* OpenSSL Check
*
* Checks the OpenSSL Environment
*
* - Checks, if the command "openssl_pkey_new" is available
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkKeys(&$checks)
{
$help = '';
$res = false;
if (function_exists('openssl_pkey_new')) {
$res = openssl_pkey_new([
'digest_alg' => 'sha1',
'private_key_bits' => 4096,
'encrypt_key' => false
]);
}
// Get private key
if (!$res) {
$help .= L10n::t('Error: the "openssl_pkey_new" function on this system is not able to generate encryption keys') . EOL;
$help .= L10n::t('If running under Windows, please see "http://www.php.net/manual/en/openssl.installation.php".');
}
self::addCheck($checks, L10n::t('Generate encryption keys'), $res, true, $help);
}
/**
* PHP functions Check
*
* Checks the following PHP functions
* - libCurl
* - GD Graphics
* - OpenSSL
* - PDO or MySQLi
* - mb_string
* - XML
* - iconv
* - POSIX
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkFunctions(&$checks)
{
$ck_funcs = [];
self::addCheck($ck_funcs, L10n::t('libCurl PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('GD graphics PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('OpenSSL PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('PDO or MySQLi PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('mb_string PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('XML PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('iconv PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('POSIX PHP module'), true, true, "");
if (function_exists('apache_get_modules')) {
if (! in_array('mod_rewrite',apache_get_modules())) {
self::addCheck($ck_funcs, L10n::t('Apache mod_rewrite module'), false, true, L10n::t('Error: Apache webserver mod-rewrite module is required but not installed.'));
} else {
self::addCheck($ck_funcs, L10n::t('Apache mod_rewrite module'), true, true, "");
}
}
if (!function_exists('curl_init')) {
$ck_funcs[0]['status'] = false;
$ck_funcs[0]['help'] = L10n::t('Error: libCURL PHP module required but not installed.');
}
if (!function_exists('imagecreatefromjpeg')) {
$ck_funcs[1]['status'] = false;
$ck_funcs[1]['help'] = L10n::t('Error: GD graphics PHP module with JPEG support required but not installed.');
}
if (!function_exists('openssl_public_encrypt')) {
$ck_funcs[2]['status'] = false;
$ck_funcs[2]['help'] = L10n::t('Error: openssl PHP module required but not installed.');
}
if (!function_exists('mysqli_connect') && !class_exists('pdo')) {
$ck_funcs[3]['status'] = false;
$ck_funcs[3]['help'] = L10n::t('Error: PDO or MySQLi PHP module required but not installed.');
}
if (!function_exists('mysqli_connect') && class_exists('pdo') && !in_array('mysql', PDO::getAvailableDrivers())) {
$ck_funcs[3]['status'] = false;
$ck_funcs[3]['help'] = L10n::t('Error: The MySQL driver for PDO is not installed.');
}
if (!function_exists('mb_strlen')) {
$ck_funcs[4]['status'] = false;
$ck_funcs[4]['help'] = L10n::t('Error: mb_string PHP module required but not installed.');
}
if (!function_exists('iconv_strlen')) {
$ck_funcs[6]['status'] = false;
$ck_funcs[6]['help'] = L10n::t('Error: iconv PHP module required but not installed.');
}
if (!function_exists('posix_kill')) {
$ck_funcs[7]['status'] = false;
$ck_funcs[7]['help'] = L10n::t('Error: POSIX PHP module required but not installed.');
}
$checks = array_merge($checks, $ck_funcs);
// check for XML DOM Documents being able to be generated
try {
$xml = new DOMDocument();
} catch (Exception $e) {
$ck_funcs[5]['status'] = false;
$ck_funcs[5]['help'] = L10n::t('Error, XML PHP module required but not installed.');
}
}
/**
* ".htconfig.php" - Check
*
* Checks if it's possible to create the ".htconfig.php"
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkHtConfig(&$checks)
{
$status = true;
$help = "";
if ((file_exists('.htconfig.php') && !is_writable('.htconfig.php')) ||
(!file_exists('.htconfig.php') && !is_writable('.'))) {
$status = false;
$help = L10n::t('The web installer needs to be able to create a file called ".htconfig.php" in the top folder of your web server and it is unable to do so.') . EOL;
$help .= L10n::t('This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can.') . EOL;
$help .= L10n::t('At the end of this procedure, we will give you a text to save in a file named .htconfig.php in your Friendica top folder.') . EOL;
$help .= L10n::t('You can alternatively skip this procedure and perform a manual installation. Please see the file "INSTALL.txt" for instructions.') . EOL;
}
self::addCheck($checks, L10n::t('.htconfig.php is writable'), $status, false, $help);
}
/**
* Smarty3 Template Check
*
* Checks, if the directory of Smarty3 is writable
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkSmarty3(&$checks)
{
$status = true;
$help = "";
if (!is_writable('view/smarty3')) {
$status = false;
$help = L10n::t('Friendica uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering.') . EOL;
$help .= L10n::t('In order to store these compiled templates, the web server needs to have write access to the directory view/smarty3/ under the Friendica top level folder.') . EOL;
$help .= L10n::t("Please ensure that the user that your web server runs as \x28e.g. www-data\x29 has write access to this folder.") . EOL;
$help .= L10n::t("Note: as a security measure, you should give the web server write access to view/smarty3/ only--not the template files \x28.tpl\x29 that it contains.") . EOL;
}
self::addCheck($checks, L10n::t('view/smarty3 is writable'), $status, true, $help);
}
/**
* ".htaccess" - Check
*
* Checks, if "url_rewrite" is enabled in the ".htaccess" file
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkHtAccess(&$checks)
{
$status = true;
$help = "";
$error_msg = "";
if (function_exists('curl_init')) {
$test = Network::fetchUrlFull(System::baseUrl() . "/install/testrewrite");
$url = normalise_link(System::baseUrl() . "/install/testrewrite");
if ($test['body'] != "ok") {
$test = Network::fetchUrlFull($url);
}
if ($test['body'] != "ok") {
$status = false;
$help = L10n::t('Url rewrite in .htaccess is not working. Check your server configuration.');
$error_msg = [];
$error_msg['head'] = L10n::t('Error message from Curl when fetching');
$error_msg['url'] = $test['redirect_url'];
$error_msg['msg'] = $test['error'];
}
self::addCheck($checks, L10n::t('Url rewrite is working'), $status, true, $help, $error_msg);
} else {
// cannot check modrewrite if libcurl is not installed
/// @TODO Maybe issue warning here?
}
}
/**
* Imagick Check
*
* Checks, if the imagick module is available
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkImagick(&$checks)
{
$imagick = false;
$gif = false;
if (class_exists('Imagick')) {
$imagick = true;
$supported = Image::supportedTypes();
if (array_key_exists('image/gif', $supported)) {
$gif = true;
}
}
if ($imagick == false) {
self::addCheck($checks, L10n::t('ImageMagick PHP extension is not installed'), $imagick, false, "");
} else {
self::addCheck($checks, L10n::t('ImageMagick PHP extension is installed'), $imagick, false, "");
if ($imagick) {
self::addCheck($checks, L10n::t('ImageMagick supports GIF'), $gif, false, "");
}
}
}
/**
* Installs the Database structure
*
* @return string A possible error
*/
public static function installDatabaseStructure()
{
$errors = DBStructure::update(false, true, true);
return $errors;
}
}

View file

@ -1,7 +1,9 @@
<?php <?php
/** /**
* @file src/Core/Theme.php * @file src/Core/Theme.php
*/ */
namespace Friendica\Core; namespace Friendica\Core;
use Friendica\Core\System; use Friendica\Core\System;
@ -28,60 +30,53 @@ class Theme
* @param string $theme the name of the theme * @param string $theme the name of the theme
* @return array * @return array
*/ */
public static function getInfo($theme) public static function getInfo($theme)
{ {
$info=[ $info = [
'name' => $theme, 'name' => $theme,
'description' => "", 'description' => "",
'author' => [], 'author' => [],
'maintainer' => [], 'maintainer' => [],
'version' => "", 'version' => "",
'credits' => "", 'credits' => "",
'experimental' => false, 'experimental' => file_exists("view/theme/$theme/experimental"),
'unsupported' => false 'unsupported' => file_exists("view/theme/$theme/unsupported")
]; ];
if (file_exists("view/theme/$theme/experimental")) if (!is_file("view/theme/$theme/theme.php")) {
$info['experimental'] = true; return $info;
if (file_exists("view/theme/$theme/unsupported")) }
$info['unsupported'] = true;
if (!is_file("view/theme/$theme/theme.php")) return $info;
$a = get_app(); $a = get_app();
$stamp1 = microtime(true); $stamp1 = microtime(true);
$f = file_get_contents("view/theme/$theme/theme.php"); $theme_file = file_get_contents("view/theme/$theme/theme.php");
$a->save_timestamp($stamp1, "file"); $a->save_timestamp($stamp1, "file");
$r = preg_match("|/\*.*\*/|msU", $f, $m); $result = preg_match("|/\*.*\*/|msU", $theme_file, $matches);
if ($r) { if ($result) {
$ll = explode("\n", $m[0]); $comment_lines = explode("\n", $matches[0]);
foreach ( $ll as $l ) { foreach ($comment_lines as $comment_line) {
$l = trim($l,"\t\n\r */"); $comment_line = trim($comment_line, "\t\n\r */");
if ($l != "") { if ($comment_line != "") {
list($k, $v) = array_map("trim", explode(":", $l, 2)); list($key, $value) = array_map("trim", explode(":", $comment_line, 2));
$k= strtolower($k); $key = strtolower($key);
if ($k == "author") { if ($key == "author") {
$result = preg_match("|([^<]+)<([^>]+)>|", $value, $matches);
$r=preg_match("|([^<]+)<([^>]+)>|", $v, $m); if ($result) {
if ($r) { $info['author'][] = ['name' => $matches[1], 'link' => $matches[2]];
$info['author'][] = ['name'=>$m[1], 'link'=>$m[2]];
} else { } else {
$info['author'][] = ['name'=>$v]; $info['author'][] = ['name' => $value];
} }
} elseif ($k == "maintainer") { } elseif ($key == "maintainer") {
$r=preg_match("|([^<]+)<([^>]+)>|", $v, $m); $result = preg_match("|([^<]+)<([^>]+)>|", $value, $matches);
if ($r) { if ($result) {
$info['maintainer'][] = ['name'=>$m[1], 'link'=>$m[2]]; $info['maintainer'][] = ['name' => $matches[1], 'link' => $matches[2]];
} else { } else {
$info['maintainer'][] = ['name'=>$v]; $info['maintainer'][] = ['name' => $value];
}
} else {
if (array_key_exists($k, $info)) {
$info[$k] = $v;
} }
} elseif (array_key_exists($key, $info)) {
$info[$key] = $value;
} }
} }
} }
@ -99,7 +94,7 @@ class Theme
*/ */
public static function getScreenshot($theme) public static function getScreenshot($theme)
{ {
$exts = ['.png','.jpg']; $exts = ['.png', '.jpg'];
foreach ($exts as $ext) { foreach ($exts as $ext) {
if (file_exists('view/theme/' . $theme . '/screenshot' . $ext)) { if (file_exists('view/theme/' . $theme . '/screenshot' . $ext)) {
return(System::baseUrl() . '/view/theme/' . $theme . '/screenshot' . $ext); return(System::baseUrl() . '/view/theme/' . $theme . '/screenshot' . $ext);
@ -113,7 +108,7 @@ class Theme
{ {
logger("Addons: uninstalling theme " . $theme); logger("Addons: uninstalling theme " . $theme);
include_once("view/theme/$theme/theme.php"); include_once "view/theme/$theme/theme.php";
if (function_exists("{$theme}_uninstall")) { if (function_exists("{$theme}_uninstall")) {
$func = "{$theme}_uninstall"; $func = "{$theme}_uninstall";
$func(); $func();
@ -124,13 +119,13 @@ class Theme
{ {
// silently fail if theme was removed // silently fail if theme was removed
if (! file_exists("view/theme/$theme/theme.php")) { if (!file_exists("view/theme/$theme/theme.php")) {
return false; return false;
} }
logger("Addons: installing theme $theme"); logger("Addons: installing theme $theme");
include_once("view/theme/$theme/theme.php"); include_once "view/theme/$theme/theme.php";
if (function_exists("{$theme}_install")) { if (function_exists("{$theme}_install")) {
$func = "{$theme}_install"; $func = "{$theme}_install";
@ -140,7 +135,6 @@ class Theme
logger("Addons: FAILED installing theme $theme"); logger("Addons: FAILED installing theme $theme");
return false; return false;
} }
} }
/** /**
@ -159,18 +153,18 @@ class Theme
$file = basename($file); $file = basename($file);
// Make sure $root ends with a slash / if it's not blank // Make sure $root ends with a slash / if it's not blank
if ($root !== '' && $root[strlen($root)-1] !== '/') { if ($root !== '' && $root[strlen($root) - 1] !== '/') {
$root = $root . '/'; $root = $root . '/';
} }
$theme_info = get_app()->theme_info; $theme_info = get_app()->theme_info;
if (is_array($theme_info) && array_key_exists('extends',$theme_info)) { if (is_array($theme_info) && array_key_exists('extends', $theme_info)) {
$parent = $theme_info['extends']; $parent = $theme_info['extends'];
} else { } else {
$parent = 'NOPATH'; $parent = 'NOPATH';
} }
$theme = current_theme(); $theme = get_app()->getCurrentTheme();
$thname = $theme; $thname = $theme;
$ext = substr($file,strrpos($file,'.')+1); $ext = substr($file, strrpos($file, '.') + 1);
$paths = [ $paths = [
"{$root}view/theme/$thname/$ext/$file", "{$root}view/theme/$thname/$ext/$file",
"{$root}view/theme/$parent/$ext/$file", "{$root}view/theme/$parent/$ext/$file",
@ -178,7 +172,7 @@ class Theme
]; ];
foreach ($paths as $p) { foreach ($paths as $p) {
// strpos() is faster than strstr when checking if one string is in another (http://php.net/manual/en/function.strstr.php) // strpos() is faster than strstr when checking if one string is in another (http://php.net/manual/en/function.strstr.php)
if (strpos($p,'NOPATH') !== false) { if (strpos($p, 'NOPATH') !== false) {
continue; continue;
} elseif (file_exists($p)) { } elseif (file_exists($p)) {
return $p; return $p;
@ -186,4 +180,25 @@ class Theme
} }
return ''; return '';
} }
/**
* @brief Return relative path to theme stylesheet file
*
* Provide a sane default if nothing is chosen or the specified theme does not exist.
*
* @param string $theme Theme name
*
* @return string
*/
public static function getStylesheetPath($theme)
{
$a = get_app();
$opts = (($a->profile_uid) ? '?f=&puid=' . $a->profile_uid : '');
if (file_exists('view/theme/' . $theme . '/style.php')) {
return 'view/theme/' . $theme . '/style.pcss' . $opts;
}
return 'view/theme/' . $theme . '/style.css';
}
} }

View file

@ -862,12 +862,32 @@ class Item extends BaseObject
} }
unset($item['id']); unset($item['id']);
unset($item['parent']);
unset($item['mention']);
unset($item['wall']);
unset($item['origin']);
unset($item['starred']);
unset($item['rendered-hash']);
unset($item['rendered-html']);
$condition = ["`nurl` IN (SELECT `nurl` FROM `contact` WHERE `id` = ?) AND `uid` != 0 AND NOT `blocked` AND NOT `readonly` AND `rel` IN (?, ?)", $users = [];
$condition = ["`nurl` IN (SELECT `nurl` FROM `contact` WHERE `id` = ?) AND `uid` != 0 AND NOT `blocked` AND `rel` IN (?, ?)",
$parent['owner-id'], CONTACT_IS_SHARING, CONTACT_IS_FRIEND]; $parent['owner-id'], CONTACT_IS_SHARING, CONTACT_IS_FRIEND];
$contacts = dba::select('contact', ['uid'], $condition); $contacts = dba::select('contact', ['uid'], $condition);
while ($contact = dba::fetch($contacts)) { while ($contact = dba::fetch($contacts)) {
self::storeForUser($itemid, $item, $contact['uid']); $users[$contact['uid']] = $contact['uid'];
}
if ($item['uri'] != $item['parent-uri']) {
$parents = dba::select('item', ['uid'], ["`uri` = ? AND `uid` != 0", $item['parent-uri']]);
while ($parent = dba::fetch($parents)) {
$users[$parent['uid']] = $parent['uid'];
}
}
foreach ($users as $uid) {
self::storeForUser($itemid, $item, $uid);
} }
} }
@ -955,10 +975,15 @@ class Item extends BaseObject
if (!dba::exists('item', ['uri' => $item['uri'], 'uid' => 0])) { if (!dba::exists('item', ['uri' => $item['uri'], 'uid' => 0])) {
// Preparing public shadow (removing user specific data) // Preparing public shadow (removing user specific data)
unset($item['id']);
$item['uid'] = 0; $item['uid'] = 0;
$item['origin'] = 0; unset($item['id']);
$item['wall'] = 0; unset($item['parent']);
unset($item['wall']);
unset($item['mention']);
unset($item['origin']);
unset($item['starred']);
unset($item['rendered-hash']);
unset($item['rendered-html']);
if ($item['uri'] == $item['parent-uri']) { if ($item['uri'] == $item['parent-uri']) {
$item['contact-id'] = Contact::getIdForURL($item['owner-link']); $item['contact-id'] = Contact::getIdForURL($item['owner-link']);
} else { } else {
@ -1012,11 +1037,20 @@ class Item extends BaseObject
return; return;
} }
// Save "origin" and "parent" state
$origin = $item['origin'];
$parent = $item['parent'];
// Preparing public shadow (removing user specific data) // Preparing public shadow (removing user specific data)
unset($item['id']);
$item['uid'] = 0; $item['uid'] = 0;
$item['origin'] = 0; unset($item['id']);
$item['wall'] = 0; unset($item['parent']);
unset($item['wall']);
unset($item['mention']);
unset($item['origin']);
unset($item['starred']);
unset($item['rendered-hash']);
unset($item['rendered-html']);
$item['contact-id'] = Contact::getIdForURL($item['author-link']); $item['contact-id'] = Contact::getIdForURL($item['author-link']);
if (in_array($item['type'], ["net-comment", "wall-comment"])) { if (in_array($item['type'], ["net-comment", "wall-comment"])) {
@ -1028,6 +1062,14 @@ class Item extends BaseObject
$public_shadow = self::insert($item, false, false, true); $public_shadow = self::insert($item, false, false, true);
logger("Stored public shadow for comment ".$item['uri']." under id ".$public_shadow, LOGGER_DEBUG); logger("Stored public shadow for comment ".$item['uri']." under id ".$public_shadow, LOGGER_DEBUG);
// If this was a comment to a Diaspora post we don't get our comment back.
// This means that we have to distribute the comment by ourselves.
if ($origin) {
if (dba::exists('item', ['id' => $parent, 'network' => NETWORK_DIASPORA])) {
self::distribute($public_shadow);
}
}
} }
/** /**

View file

@ -152,7 +152,7 @@ class Profile
$a->set_template_engine(); // reset the template engine to the default in case the user's theme doesn't specify one $a->set_template_engine(); // reset the template engine to the default in case the user's theme doesn't specify one
$theme_info_file = 'view/theme/' . current_theme() . '/theme.php'; $theme_info_file = 'view/theme/' . $a->getCurrentTheme() . '/theme.php';
if (file_exists($theme_info_file)) { if (file_exists($theme_info_file)) {
require_once $theme_info_file; require_once $theme_info_file;
} }
@ -950,7 +950,7 @@ class Profile
]; ];
} }
if ((!$is_owner) && ((count($a->profile)) || (!$a->profile['hide-friends']))) { if (!$is_owner && empty($a->profile['hide-friends'])) {
$tabs[] = [ $tabs[] = [
'label' => L10n::t('Contacts'), 'label' => L10n::t('Contacts'),
'url' => System::baseUrl() . '/viewcontacts/' . $nickname, 'url' => System::baseUrl() . '/viewcontacts/' . $nickname,

View file

@ -1405,6 +1405,7 @@ class DFRN
{ {
$a = get_app(); $a = get_app();
if (!$public_batch) {
if (empty($contact['addr'])) { if (empty($contact['addr'])) {
logger('Empty contact handle for ' . $contact['id'] . ' - ' . $contact['url'] . ' - trying to update it.'); logger('Empty contact handle for ' . $contact['id'] . ' - ' . $contact['url'] . ' - trying to update it.');
if (Contact::updateFromProbe($contact['id'])) { if (Contact::updateFromProbe($contact['id'])) {
@ -1425,6 +1426,7 @@ class DFRN
Contact::markForArchival($contact); Contact::markForArchival($contact);
return -22; return -22;
} }
}
$envelope = Diaspora::buildMessage($atom, $owner, $contact, $owner['uprvkey'], $fcontact['pubkey'], $public_batch); $envelope = Diaspora::buildMessage($atom, $owner, $contact, $owner['uprvkey'], $fcontact['pubkey'], $public_batch);
@ -2797,10 +2799,6 @@ class DFRN
return true; return true;
} }
} else { // $entrytype == DFRN_TOP_LEVEL } else { // $entrytype == DFRN_TOP_LEVEL
if ($importer["readonly"]) {
logger('ignoring read-only contact '.$importer["id"]);
return;
}
if (($importer["uid"] == 0) && ($importer["importer_uid"] != 0)) { if (($importer["uid"] == 0) && ($importer["importer_uid"] != 0)) {
logger("Contact ".$importer["id"]." isn't known to user ".$importer["importer_uid"].". The post will be ignored.", LOGGER_DEBUG); logger("Contact ".$importer["id"]." isn't known to user ".$importer["importer_uid"].". The post will be ignored.", LOGGER_DEBUG);
return; return;

View file

@ -596,9 +596,9 @@ class Diaspora
} }
$importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE]; $importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE];
$message_id = self::dispatch($importer, $msg, $fields); $success = self::dispatch($importer, $msg, $fields);
return $message_id; return $success;
} }
/** /**
@ -832,6 +832,10 @@ class Diaspora
if (isset($parent_author_signature)) { if (isset($parent_author_signature)) {
$key = self::key($msg["author"]); $key = self::key($msg["author"]);
if (empty($key)) {
logger("No key found for parent author ".$msg["author"], LOGGER_DEBUG);
return false;
}
if (!Crypto::rsaVerify($signed_data, $parent_author_signature, $key, "sha256")) { if (!Crypto::rsaVerify($signed_data, $parent_author_signature, $key, "sha256")) {
logger("No valid parent author signature for parent author ".$msg["author"]. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$parent_author_signature, LOGGER_DEBUG); logger("No valid parent author signature for parent author ".$msg["author"]. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$parent_author_signature, LOGGER_DEBUG);
@ -840,6 +844,10 @@ class Diaspora
} }
$key = self::key($fields->author); $key = self::key($fields->author);
if (empty($key)) {
logger("No key found for author ".$fields->author, LOGGER_DEBUG);
return false;
}
if (!Crypto::rsaVerify($signed_data, $author_signature, $key, "sha256")) { if (!Crypto::rsaVerify($signed_data, $author_signature, $key, "sha256")) {
logger("No valid author signature for author ".$fields->author. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$author_signature, LOGGER_DEBUG); logger("No valid author signature for author ".$fields->author. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$author_signature, LOGGER_DEBUG);
@ -1143,7 +1151,7 @@ class Diaspora
//} //}
// We don't seem to like that person // We don't seem to like that person
if ($contact["blocked"] || $contact["readonly"]) { if ($contact["blocked"]) {
// Maybe blocked, don't accept. // Maybe blocked, don't accept.
return false; return false;
// We are following this person? // We are following this person?
@ -2721,10 +2729,15 @@ class Diaspora
*/ */
public static function originalItem($guid, $orig_author) public static function originalItem($guid, $orig_author)
{ {
if (empty($guid)) {
logger('Empty guid. Quitting.');
return false;
}
// Do we already have this item? // Do we already have this item?
$fields = ['body', 'tag', 'app', 'created', 'object-type', 'uri', 'guid', $fields = ['body', 'tag', 'app', 'created', 'object-type', 'uri', 'guid',
'author-name', 'author-link', 'author-avatar']; 'author-name', 'author-link', 'author-avatar'];
$condition = ['guid' => $guid, 'visible' => true, 'deleted' => false]; $condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => false];
$item = dba::selectfirst('item', $fields, $condition); $item = dba::selectfirst('item', $fields, $condition);
if (DBM::is_result($item)) { if (DBM::is_result($item)) {
@ -2734,7 +2747,7 @@ class Diaspora
// Then refetch the content, if it is a reshare from a reshare. // Then refetch the content, if it is a reshare from a reshare.
// If it is a reshared post from another network then reformat to avoid display problems with two share elements // If it is a reshared post from another network then reformat to avoid display problems with two share elements
if (self::isReshare($item["body"], true)) { if (self::isReshare($item["body"], true)) {
$r = []; $item = [];
} elseif (self::isReshare($item["body"], false) || strstr($item["body"], "[share")) { } elseif (self::isReshare($item["body"], false) || strstr($item["body"], "[share")) {
$item["body"] = Markdown::toBBCode(BBCode::toMarkdown($item["body"])); $item["body"] = Markdown::toBBCode(BBCode::toMarkdown($item["body"]));
@ -2749,21 +2762,26 @@ class Diaspora
} }
} }
if (!DBM::is_result($r)) { if (!DBM::is_result($item)) {
$server = "https://".substr($orig_author, strpos($orig_author, "@") + 1); if (empty($orig_author)) {
logger("1st try: reshared message ".$guid." will be fetched via SSL from the server ".$server); logger('Empty author for guid ' . $guid . '. Quitting.');
$item_id = self::storeByGuid($guid, $server); return false;
if (!$item_id) {
$server = "http://".substr($orig_author, strpos($orig_author, "@") + 1);
logger("2nd try: reshared message ".$guid." will be fetched without SLL from the server ".$server);
$item_id = self::storeByGuid($guid, $server);
} }
if ($item_id) { $server = "https://".substr($orig_author, strpos($orig_author, "@") + 1);
logger("1st try: reshared message ".$guid." will be fetched via SSL from the server ".$server);
$stored = self::storeByGuid($guid, $server);
if (!$stored) {
$server = "http://".substr($orig_author, strpos($orig_author, "@") + 1);
logger("2nd try: reshared message ".$guid." will be fetched without SSL from the server ".$server);
$stored = self::storeByGuid($guid, $server);
}
if ($stored) {
$fields = ['body', 'tag', 'app', 'created', 'object-type', 'uri', 'guid', $fields = ['body', 'tag', 'app', 'created', 'object-type', 'uri', 'guid',
'author-name', 'author-link', 'author-avatar']; 'author-name', 'author-link', 'author-avatar'];
$condition = ['id' => $item_id, 'visible' => true, 'deleted' => false]; $condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => false];
$item = dba::selectfirst('item', $fields, $condition); $item = dba::selectfirst('item', $fields, $condition);
if (DBM::is_result($item)) { if (DBM::is_result($item)) {

View file

@ -22,7 +22,7 @@ class FriendicaSmarty extends Smarty
parent::__construct(); parent::__construct();
$a = get_app(); $a = get_app();
$theme = current_theme(); $theme = $a->getCurrentTheme();
// setTemplateDir can be set to an array, which Smarty will parse in order. // setTemplateDir can be set to an array, which Smarty will parse in order.
// The order is thus very important here // The order is thus very important here

View file

@ -62,7 +62,7 @@ class FriendicaSmartyEngine implements ITemplateEngine
$root = $root . '/'; $root = $root . '/';
} }
$theme = current_theme(); $theme = $a->getCurrentTheme();
$filename = $template::SMARTY3_TEMPLATE_FOLDER . '/' . $file; $filename = $template::SMARTY3_TEMPLATE_FOLDER . '/' . $file;
if (file_exists("{$root}view/theme/$theme/$filename")) { if (file_exists("{$root}view/theme/$theme/$filename")) {

View file

@ -36,7 +36,30 @@ class Network
*/ */
public static function fetchUrl($url, $binary = false, &$redirects = 0, $timeout = 0, $accept_content = null, $cookiejar = 0) public static function fetchUrl($url, $binary = false, &$redirects = 0, $timeout = 0, $accept_content = null, $cookiejar = 0)
{ {
$ret = self::curl( $ret = self::fetchUrlFull($url, $binary, $redirects, $timeout, $accept_content, $cookiejar);
return $ret['body'];
}
/**
* @brief Curl wrapper with array of return values.
*
* Inner workings and parameters are the same as @ref fetchUrl but returns an array with
* all the information collected during the fetch.
*
* @param string $url URL to fetch
* @param boolean $binary default false
* TRUE if asked to return binary results (file download)
* @param integer $redirects The recursion counter for internal use - default 0
* @param integer $timeout Timeout in seconds, default system config value or 60 seconds
* @param string $accept_content supply Accept: header with 'accept_content' as the value
* @param string $cookiejar Path to cookie jar file
*
* @return array With all relevant information, 'body' contains the actual fetched content.
*/
public static function fetchUrlFull($url, $binary = false, &$redirects = 0, $timeout = 0, $accept_content = null, $cookiejar = 0)
{
return self::curl(
$url, $url,
$binary, $binary,
$redirects, $redirects,
@ -45,8 +68,6 @@ class Network
'cookiejar'=>$cookiejar 'cookiejar'=>$cookiejar
] ]
); );
return($ret['body']);
} }
/** /**

View file

@ -4,6 +4,7 @@
*/ */
namespace Friendica\Worker; namespace Friendica\Worker;
use Friendica\BaseObject;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\System; use Friendica\Core\System;
@ -19,98 +20,67 @@ use dba;
require_once 'include/items.php'; require_once 'include/items.php';
/// @todo This is some ugly code that needs to be split into several methods class Delivery extends BaseObject
{
const MAIL = 'mail';
const SUGGESTION = 'suggest';
const RELOCATION = 'relocate';
const DELETION = 'drop';
const POST = 'wall-new';
const COMMENT = 'comment-new';
class Delivery { public static function execute($cmd, $item_id, $contact_id)
public static function execute($cmd, $item_id, $contact_id) { {
global $a; logger('Invoked: ' . $cmd . ': ' . $item_id . ' to ' . $contact_id, LOGGER_DEBUG);
logger('delivery: invoked: '.$cmd.': '.$item_id.' to '.$contact_id, LOGGER_DEBUG);
$mail = false;
$fsuggest = false;
$relocate = false;
$top_level = false; $top_level = false;
$recipients = [];
$followup = false; $followup = false;
$public_message = false;
$normal_mode = true; if ($cmd == self::MAIL) {
$target_item = dba::selectFirst('mail', [], ['id' => $item_id]);
$item = null; if (!DBM::is_result($message)) {
$recipients[] = $contact_id;
if ($cmd === 'mail') {
$normal_mode = false;
$mail = true;
$message = q("SELECT * FROM `mail` WHERE `id` = %d LIMIT 1",
intval($item_id)
);
if (!count($message)) {
return; return;
} }
$uid = $message[0]['uid']; $uid = $target_item['uid'];
$recipients[] = $message[0]['contact-id']; } elseif ($cmd == self::SUGGESTION) {
$item = $message[0]; $target_item = dba::selectFirst('fsuggest', [], ['id' => $item_id]);
} elseif ($cmd === 'suggest') { if (!DBM::is_result($message)) {
$normal_mode = false;
$fsuggest = true;
$suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1",
intval($item_id)
);
if (!count($suggest)) {
return; return;
} }
$uid = $suggest[0]['uid']; $uid = $target_item['uid'];
$recipients[] = $suggest[0]['cid']; } elseif ($cmd == self::RELOCATION) {
$item = $suggest[0];
} elseif ($cmd === 'relocate') {
$normal_mode = false;
$relocate = true;
$uid = $item_id; $uid = $item_id;
} else { } else {
// find ancestors $item = dba::selectFirst('item', ['parent'], ['id' => $item_id]);
$target_item = dba::fetch_first("SELECT `item`.*, `contact`.`uid` AS `cuid` FROM `item` if (!DBM::is_result($item) || empty($item['parent'])) {
return;
}
$parent_id = intval($item['parent']);
$itemdata = dba::p("SELECT `item`.*, `contact`.`uid` AS `cuid`,
`sign`.`signed_text`,`sign`.`signature`,`sign`.`signer`
FROM `item`
INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
WHERE `item`.`id` = ? AND `visible` AND NOT `moderated`", $item_id); LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id`
WHERE `item`.`id` IN (?, ?) AND `visible` AND NOT `moderated`
if (!DBM::is_result($target_item) || !intval($target_item['parent'])) { ORDER BY `item`.`id`",
return; $item_id, $parent_id);
$items = [];
while ($item = dba::fetch($itemdata)) {
if ($item['id'] == $parent_id) {
$parent = $item;
} }
if ($item['id'] == $item_id) {
$target_item = $item;
}
$items[] = $item;
}
dba::close($itemdata);
$parent_id = intval($target_item['parent']);
$uid = $target_item['cuid']; $uid = $target_item['cuid'];
$updated = $target_item['edited'];
$items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer`
FROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d AND visible = 1 AND moderated = 0 ORDER BY `id` ASC",
intval($parent_id)
);
if (!count($items)) {
return;
}
$icontacts = null;
$contacts_arr = [];
foreach ($items as $item) {
if (!in_array($item['contact-id'],$contacts_arr)) {
$contacts_arr[] = intval($item['contact-id']);
}
}
if (count($contacts_arr)) {
$str_contacts = implode(',',$contacts_arr);
$icontacts = q("SELECT * FROM `contact`
WHERE `id` IN ( $str_contacts ) "
);
}
if ( !($icontacts && count($icontacts))) {
return;
}
// avoid race condition with deleting entries // avoid race condition with deleting entries
if ($items[0]['deleted']) { if ($items[0]['deleted']) {
foreach ($items as $item) { foreach ($items as $item) {
$item['deleted'] = 1; $item['deleted'] = 1;
@ -120,24 +90,10 @@ class Delivery {
// When commenting too fast after delivery, a post wasn't recognized as top level post. // When commenting too fast after delivery, a post wasn't recognized as top level post.
// The count then showed more than one entry. The additional check should help. // The count then showed more than one entry. The additional check should help.
// The check for the "count" should be superfluous, but I'm not totally sure by now, so we keep it. // The check for the "count" should be superfluous, but I'm not totally sure by now, so we keep it.
if ((($items[0]['id'] == $item_id) || (count($items) == 1)) && ($items[0]['uri'] === $items[0]['parent-uri'])) { if ((($parent['id'] == $item_id) || (count($items) == 1)) && ($parent['uri'] === $parent['parent-uri'])) {
logger('delivery: top level post'); logger('Top level post');
$top_level = true; $top_level = true;
} }
}
$owner = User::getOwnerDataById($uid);
if (!$owner) {
return;
}
// We don't treat Forum posts as "wall-to-wall" to be able to post them via Diaspora
$walltowall = $top_level && ($owner['id'] != $items[0]['contact-id']) & ($owner['account-type'] != ACCOUNT_TYPE_COMMUNITY);
$public_message = true;
if (!$mail && !$fsuggest && !$relocate) {
$parent = $items[0];
// This is IMPORTANT!!!! // This is IMPORTANT!!!!
@ -147,9 +103,9 @@ class Delivery {
// if $parent['wall'] == 1 we will already have the parent message in our array // if $parent['wall'] == 1 we will already have the parent message in our array
// and we will relay the whole lot. // and we will relay the whole lot.
$localhost = $a->get_hostname(); $localhost = self::getApp()->get_hostname();
if (strpos($localhost,':')) { if (strpos($localhost, ':')) {
$localhost = substr($localhost,0,strpos($localhost,':')); $localhost = substr($localhost, 0, strpos($localhost, ':'));
} }
/** /**
* *
@ -159,26 +115,24 @@ class Delivery {
* *
*/ */
$relay_to_owner = false;
if (!$top_level && ($parent['wall'] == 0) && stristr($target_item['uri'], $localhost)) { if (!$top_level && ($parent['wall'] == 0) && stristr($target_item['uri'], $localhost)) {
$relay_to_owner = true; logger('Followup ' . $target_item["guid"], LOGGER_DEBUG);
}
if ($relay_to_owner) {
logger('followup '.$target_item["guid"], LOGGER_DEBUG);
// local followup to remote post // local followup to remote post
$followup = true; $followup = true;
} }
if (strlen($parent['allow_cid']) if (empty($parent['allow_cid'])
|| strlen($parent['allow_gid']) && empty($parent['allow_gid'])
|| strlen($parent['deny_cid']) && empty($parent['deny_cid'])
|| strlen($parent['deny_gid']) && empty($parent['deny_gid'])
|| $parent["private"]) { && !$parent["private"]) {
$public_message = false; // private recipients, not public $public_message = true;
}
} }
$owner = User::getOwnerDataById($uid);
if (!DBM::is_result($owner)) {
return;
} }
// We don't deliver our items to blocked or pending contacts, and not to ourselves either // We don't deliver our items to blocked or pending contacts, and not to ourselves either
@ -189,146 +143,22 @@ class Delivery {
return; return;
} }
$deliver_status = 0; // Transmit via Diaspora if the thread had started as Diaspora post
// This is done since the uri wouldn't match (Diaspora doesn't transmit it)
// Transmit via Diaspora if not possible via Friendica if (isset($parent) && ($parent['network'] == NETWORK_DIASPORA) && ($contact['network'] == NETWORK_DFRN)) {
if (($item['uid'] == 0) && ($contact['network'] == NETWORK_DFRN)) {
$contact['network'] = NETWORK_DIASPORA; $contact['network'] = NETWORK_DIASPORA;
} }
logger("main delivery by delivery: followup=$followup mail=$mail fsuggest=$fsuggest relocate=$relocate - network ".$contact['network']); logger("Delivering " . $cmd . " followup=$followup - via network " . $contact['network']);
switch ($contact['network']) { switch ($contact['network']) {
case NETWORK_DFRN: case NETWORK_DFRN:
logger('notifier: '.$target_item["guid"].' dfrndelivery: '.$contact['name']); self::deliverDFRN($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup);
if ($mail) {
$item['body'] = Item::fixPrivatePhotos($item['body'], $owner['uid'], null, $item['contact-id']);
$atom = DFRN::mail($item, $owner);
} elseif ($fsuggest) {
$atom = DFRN::fsuggest($item, $owner);
dba::delete('fsuggest', ['id' => $item['id']]);
} elseif ($relocate) {
$atom = DFRN::relocate($owner, $uid);
} elseif ($followup) {
$msgitems = [];
foreach ($items as $item) { // there is only one item
if (!$item['parent']) {
return;
}
if ($item['id'] == $item_id) {
logger('followup: item: '. print_r($item,true), LOGGER_DATA);
$msgitems[] = $item;
}
}
$atom = DFRN::entries($msgitems,$owner);
} else {
$msgitems = [];
foreach ($items as $item) {
if (!$item['parent']) {
return;
}
// private emails may be in included in public conversations. Filter them.
if ($public_message && $item['private']) {
return;
}
$item_contact = self::getItemContact($item,$icontacts);
if (!$item_contact) {
return;
}
if ($normal_mode) {
// Only add the parent when we don't delete other items.
if ($item_id == $item['id'] || (($item['id'] == $item['parent']) && ($cmd != 'drop'))) {
$item["entry:comment-allow"] = true;
$item["entry:cid"] = (($top_level) ? $contact['id'] : 0);
$msgitems[] = $item;
}
} else {
$item["entry:comment-allow"] = true;
$msgitems[] = $item;
}
}
$atom = DFRN::entries($msgitems,$owner);
}
logger('notifier entry: '.$contact["url"].' '.$target_item["guid"].' entry: '.$atom, LOGGER_DEBUG);
logger('notifier: '.$atom, LOGGER_DATA);
$basepath = implode('/', array_slice(explode('/',$contact['url']),0,3));
// perform local delivery if we are on the same site
if (link_compare($basepath,System::baseUrl())) {
$nickname = basename($contact['url']);
if ($contact['issued-id']) {
$sql_extra = sprintf(" AND `dfrn-id` = '%s' ", dbesc($contact['issued-id']));
} else {
$sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($contact['dfrn-id']));
}
$x = q("SELECT `contact`.*, `contact`.`uid` AS `importer_uid`,
`contact`.`pubkey` AS `cpubkey`,
`contact`.`prvkey` AS `cprvkey`,
`contact`.`thumb` AS `thumb`,
`contact`.`url` as `url`,
`contact`.`name` as `senderName`,
`user`.*
FROM `contact`
INNER JOIN `user` ON `contact`.`uid` = `user`.`uid`
WHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0
AND `contact`.`network` = '%s' AND `user`.`nickname` = '%s'
$sql_extra
AND `user`.`account_expired` = 0 AND `user`.`account_removed` = 0 LIMIT 1",
dbesc(NETWORK_DFRN),
dbesc($nickname)
);
if ($x && count($x)) {
$write_flag = ((($x[0]['rel']) && ($x[0]['rel'] != CONTACT_IS_SHARING)) ? true : false);
if ((($owner['page-flags'] == PAGE_COMMUNITY) || $write_flag) && !$x[0]['writable']) {
dba::update('contact', ['writable' => true], ['id' => $x[0]['id']]);
$x[0]['writable'] = 1;
}
$ssl_policy = Config::get('system','ssl_policy');
$x[0] = Contact::updateSslPolicy($x[0], $ssl_policy);
// If we are setup as a soapbox we aren't accepting top level posts from this person
if (($x[0]['page-flags'] == PAGE_SOAPBOX) && $top_level) {
break; break;
}
logger('mod-delivery: local delivery');
DFRN::import($atom, $x[0]);
break;
}
}
if (!Queue::wasDelayed($contact['id'])) {
$deliver_status = DFRN::deliver($owner, $contact, $atom);
} else {
$deliver_status = -1;
}
logger('notifier: dfrn_delivery to '.$contact["url"].' with guid '.$target_item["guid"].' returns '.$deliver_status);
if ($deliver_status < 0) {
logger('notifier: delivery failed: queuing message');
Queue::add($contact['id'], NETWORK_DFRN, $atom, false, $target_item['guid']);
}
if (($deliver_status >= 200) && ($deliver_status <= 299)) {
// We successfully delivered a message, the contact is alive
Contact::unmarkForArchival($contact);
} else {
// The message could not be delivered. We mark the contact as "dead"
Contact::markForArchival($contact);
}
case NETWORK_DIASPORA:
self::deliverDiaspora($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup);
break; break;
case NETWORK_OSTATUS: case NETWORK_OSTATUS:
@ -345,156 +175,7 @@ class Delivery {
break; break;
case NETWORK_MAIL: case NETWORK_MAIL:
self::deliverMail($cmd, $contact, $owner, $target_item);
if (Config::get('system','dfrn_only')) {
break;
}
// WARNING: does not currently convert to RFC2047 header encodings, etc.
$addr = $contact['addr'];
if (!strlen($addr)) {
break;
}
if ($cmd === 'wall-new' || $cmd === 'comment-new') {
$it = null;
if ($cmd === 'wall-new') {
$it = $items[0];
} else {
$r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1",
intval($item_id)
);
if (DBM::is_result($r)) {
$it = $r[0];
}
}
if (!$it) {
break;
}
$local_user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
intval($uid)
);
if (!count($local_user)) {
break;
}
$reply_to = '';
$r1 = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1",
intval($uid)
);
if ($r1 && $r1[0]['reply_to']) {
$reply_to = $r1[0]['reply_to'];
}
$subject = (($it['title']) ? Email::encodeHeader($it['title'],'UTF-8') : L10n::t("\x28no subject\x29")) ;
// only expose our real email address to true friends
if (($contact['rel'] == CONTACT_IS_FRIEND) && !$contact['blocked']) {
if ($reply_to) {
$headers = 'From: '.Email::encodeHeader($local_user[0]['username'],'UTF-8').' <'.$reply_to.'>'."\n";
$headers .= 'Sender: '.$local_user[0]['email']."\n";
} else {
$headers = 'From: '.Email::encodeHeader($local_user[0]['username'],'UTF-8').' <'.$local_user[0]['email'].'>'."\n";
}
} else {
$headers = 'From: '. Email::encodeHeader($local_user[0]['username'], 'UTF-8') . ' <noreply@' . $a->get_hostname() . '>' . "\n";
}
//if ($reply_to)
// $headers .= 'Reply-to: '.$reply_to . "\n";
$headers .= 'Message-Id: <'. Email::iri2msgid($it['uri']).'>'. "\n";
//logger("Mail: uri: ".$it['uri']." parent-uri ".$it['parent-uri'], LOGGER_DEBUG);
//logger("Mail: Data: ".print_r($it, true), LOGGER_DEBUG);
//logger("Mail: Data: ".print_r($it, true), LOGGER_DATA);
if ($it['uri'] !== $it['parent-uri']) {
$headers .= "References: <".Email::iri2msgid($it["parent-uri"]).">";
// If Threading is enabled, write down the correct parent
if (($it["thr-parent"] != "") && ($it["thr-parent"] != $it["parent-uri"])) {
$headers .= " <".Email::iri2msgid($it["thr-parent"]).">";
}
$headers .= "\n";
if (!$it['title']) {
$r = q("SELECT `title` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($it['parent-uri']),
intval($uid));
if (DBM::is_result($r) && ($r[0]['title'] != '')) {
$subject = $r[0]['title'];
} else {
$r = q("SELECT `title` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($it['parent-uri']),
intval($uid));
if (DBM::is_result($r) && ($r[0]['title'] != '')) {
$subject = $r[0]['title'];
}
}
}
if (strncasecmp($subject,'RE:',3)) {
$subject = 'Re: '.$subject;
}
}
Email::send($addr, $subject, $headers, $it);
}
break;
case NETWORK_DIASPORA:
if ($public_message) {
$loc = 'public batch '.$contact['batch'];
} else {
$loc = $contact['name'];
}
logger('delivery: diaspora batch deliver: '.$loc);
if (Config::get('system','dfrn_only') || !Config::get('system','diaspora_enabled')) {
break;
}
if ($mail) {
Diaspora::sendMail($item,$owner,$contact);
break;
}
if (!$normal_mode) {
break;
}
if (!$contact['pubkey'] && !$public_message) {
break;
}
if (($target_item['deleted']) && (($target_item['uri'] === $target_item['parent-uri']) || $followup)) {
// top-level retraction
logger('diaspora retract: '.$loc);
Diaspora::sendRetraction($target_item,$owner,$contact,$public_message);
break;
} elseif ($relocate) {
Diaspora::sendAccountMigration($owner, $contact, $uid);
break;
} elseif ($followup) {
// send comments and likes to owner to relay
logger('diaspora followup: '.$loc);
Diaspora::sendFollowup($target_item,$owner,$contact,$public_message);
break;
} elseif ($target_item['uri'] !== $target_item['parent-uri']) {
// we are the relay - send comments, likes and relayable_retractions to our conversants
logger('diaspora relay: '.$loc);
Diaspora::sendRelay($target_item,$owner,$contact,$public_message);
break;
} elseif ($top_level && !$walltowall) {
// currently no workable solution for sending walltowall
logger('diaspora status: '.$loc);
Diaspora::sendStatus($target_item,$owner,$contact,$public_message);
break;
}
logger('delivery: diaspora unknown mode: '.$contact['name']);
break; break;
default: default:
@ -504,16 +185,268 @@ class Delivery {
return; return;
} }
private static function getItemContact($item, $contacts) /**
* @brief Deliver content via DFRN
*
* @param string $cmd Command
* @param array $contact Contact record of the receiver
* @param array $owner Owner record of the sender
* @param array $items Item record of the content and the parent
* @param array $target_item Item record of the content
* @param boolean $public_message Is the content public?
* @param boolean $top_level Is it a thread starter?
* @param boolean $followup Is it an answer to a remote post?
*/
private static function deliverDFRN($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup)
{ {
if (!count($contacts) || !is_array($item)) { logger('Deliver ' . $target_item["guid"] . ' via DFRN to ' . $contact['addr']);
return false;
} if ($cmd == self::MAIL) {
foreach ($contacts as $contact) { $item = $target_item;
if ($contact['id'] == $item['contact-id']) { $item['body'] = Item::fixPrivatePhotos($item['body'], $owner['uid'], null, $item['contact-id']);
return $contact; $atom = DFRN::mail($item, $owner);
} elseif ($cmd == self::SUGGESTION) {
$item = $target_item;
$atom = DFRN::fsuggest($item, $owner);
dba::delete('fsuggest', ['id' => $item['id']]);
} elseif ($cmd == self::RELOCATION) {
$atom = DFRN::relocate($owner, $owner['uid']);
} elseif ($followup) {
$msgitems = [$target_item];
$atom = DFRN::entries($msgitems, $owner);
} else {
$msgitems = [];
foreach ($items as $item) {
// Only add the parent when we don't delete other items.
if (($target_item['id'] == $item['id']) || ($cmd != self::DELETION)) {
$item["entry:comment-allow"] = true;
$item["entry:cid"] = ($top_level ? $contact['id'] : 0);
$msgitems[] = $item;
} }
} }
return false; $atom = DFRN::entries($msgitems, $owner);
}
logger('Notifier entry: ' . $contact["url"] . ' ' . $target_item["guid"] . ' entry: ' . $atom, LOGGER_DATA);
$basepath = implode('/', array_slice(explode('/', $contact['url']), 0, 3));
// perform local delivery if we are on the same site
if (link_compare($basepath, System::baseUrl())) {
$condition = ['nurl' => normalise_link($contact['url']), 'self' => true];
$target_self = dba::selectFirst('contact', ['uid'], $condition);
if (!DBM::is_result($target_self)) {
return;
}
$target_uid = $target_self['uid'];
// Check if the user has got this contact
$cid = Contact::getIdForURL($owner['url'], $target_uid);
if (!$cid) {
// Otherwise there should be a public contact
$cid = Contact::getIdForURL($owner['url']);
if (!$cid) {
return;
}
}
// We now have some contact, so we fetch it
$target_importer = dba::fetch_first("SELECT *, `name` as `senderName`
FROM `contact`
WHERE NOT `blocked` AND `id` = ? LIMIT 1",
$cid);
// This should never fail
if (!DBM::is_result($target_importer)) {
return;
}
// Set the user id. This is important if this is a public contact
$target_importer['importer_uid'] = $target_uid;
DFRN::import($atom, $target_importer);
return;
}
// We don't have a relationship with contacts on a public post.
// Se we transmit with the new method and via Diaspora as a fallback
if ($items[0]['uid'] == 0) {
// Transmit in public if it's a relay post
$public_dfrn = ($contact['contact-type'] == ACCOUNT_TYPE_RELAY);
$deliver_status = DFRN::transmit($owner, $contact, $atom, $public_dfrn);
if (($deliver_status < 200) || ($deliver_status > 299)) {
// Transmit via Diaspora if not possible via Friendica
self::deliverDiaspora($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup);
return;
}
} else {
$deliver_status = DFRN::deliver($owner, $contact, $atom);
}
logger('Delivery to ' . $contact["url"] . ' with guid ' . $target_item["guid"] . ' returns ' . $deliver_status);
if ($deliver_status < 0) {
logger('Delivery failed: queuing message ' . $target_item["guid"] );
Queue::add($contact['id'], NETWORK_DFRN, $atom, false, $target_item['guid']);
}
if (($deliver_status >= 200) && ($deliver_status <= 299)) {
// We successfully delivered a message, the contact is alive
Contact::unmarkForArchival($contact);
} else {
// The message could not be delivered. We mark the contact as "dead"
Contact::markForArchival($contact);
}
}
/**
* @brief Deliver content via Diaspora
*
* @param string $cmd Command
* @param array $contact Contact record of the receiver
* @param array $owner Owner record of the sender
* @param array $items Item record of the content and the parent
* @param array $target_item Item record of the content
* @param boolean $public_message Is the content public?
* @param boolean $top_level Is it a thread starter?
* @param boolean $followup Is it an answer to a remote post?
*/
private static function deliverDiaspora($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup)
{
// We don't treat Forum posts as "wall-to-wall" to be able to post them via Diaspora
$walltowall = $top_level && ($owner['id'] != $items[0]['contact-id']) & ($owner['account-type'] != ACCOUNT_TYPE_COMMUNITY);
if ($public_message) {
$loc = 'public batch ' . $contact['batch'];
} else {
$loc = $contact['addr'];
}
logger('Deliver ' . $target_item["guid"] . ' via Diaspora to ' . $loc);
if (Config::get('system', 'dfrn_only') || !Config::get('system', 'diaspora_enabled')) {
return;
}
if ($cmd == self::MAIL) {
Diaspora::sendMail($target_item, $owner, $contact);
return;
}
if ($cmd == self::SUGGESTION) {
return;
}
if (!$contact['pubkey'] && !$public_message) {
return;
}
if (($target_item['deleted']) && (($target_item['uri'] === $target_item['parent-uri']) || $followup)) {
// top-level retraction
logger('diaspora retract: ' . $loc);
Diaspora::sendRetraction($target_item, $owner, $contact, $public_message);
return;
} elseif ($cmd == self::RELOCATION) {
Diaspora::sendAccountMigration($owner, $contact, $owner['uid']);
return;
} elseif ($followup) {
// send comments and likes to owner to relay
logger('diaspora followup: ' . $loc);
Diaspora::sendFollowup($target_item, $owner, $contact, $public_message);
return;
} elseif ($target_item['uri'] !== $target_item['parent-uri']) {
// we are the relay - send comments, likes and relayable_retractions to our conversants
logger('diaspora relay: ' . $loc);
Diaspora::sendRelay($target_item, $owner, $contact, $public_message);
return;
} elseif ($top_level && !$walltowall) {
// currently no workable solution for sending walltowall
logger('diaspora status: ' . $loc);
Diaspora::sendStatus($target_item, $owner, $contact, $public_message);
return;
}
logger('Unknown mode ' . $cmd . ' for ' . $loc);
}
/**
* @brief Deliver content via mail
*
* @param string $cmd Command
* @param array $contact Contact record of the receiver
* @param array $owner Owner record of the sender
* @param array $target_item Item record of the content
*/
private static function deliverMail($cmd, $contact, $owner, $target_item)
{
if (Config::get('system','dfrn_only')) {
return;
}
// WARNING: does not currently convert to RFC2047 header encodings, etc.
$addr = $contact['addr'];
if (!strlen($addr)) {
return;
}
if (!in_array($cmd, [self::POST, self::COMMENT])) {
return;
}
$local_user = dba::selectFirst('user', [], ['uid' => $owner['uid']]);
if (!DBM::is_result($local_user)) {
return;
}
logger('Deliver ' . $target_item["guid"] . ' via mail to ' . $contact['addr']);
$reply_to = '';
$mailacct = dba::selectFirst('mailacct', ['reply_to'], ['uid' => $owner['uid']]);
if (DBM::is_result($mailacct) && !empty($mailacct['reply_to'])) {
$reply_to = $mailacct['reply_to'];
}
$subject = ($target_item['title'] ? Email::encodeHeader($target_item['title'], 'UTF-8') : L10n::t("\x28no subject\x29"));
// only expose our real email address to true friends
if (($contact['rel'] == CONTACT_IS_FRIEND) && !$contact['blocked']) {
if ($reply_to) {
$headers = 'From: ' . Email::encodeHeader($local_user['username'],'UTF-8') . ' <' . $reply_to.'>' . "\n";
$headers .= 'Sender: ' . $local_user['email'] . "\n";
} else {
$headers = 'From: ' . Email::encodeHeader($local_user['username'],'UTF-8').' <' . $local_user['email'] . '>' . "\n";
}
} else {
$headers = 'From: '. Email::encodeHeader($local_user['username'], 'UTF-8') . ' <noreply@' . self::getApp()->get_hostname() . '>' . "\n";
}
$headers .= 'Message-Id: <' . Email::iri2msgid($target_item['uri']) . '>' . "\n";
if ($target_item['uri'] !== $target_item['parent-uri']) {
$headers .= "References: <" . Email::iri2msgid($target_item["parent-uri"]) . ">";
// If Threading is enabled, write down the correct parent
if (($target_item["thr-parent"] != "") && ($target_item["thr-parent"] != $target_item["parent-uri"])) {
$headers .= " <".Email::iri2msgid($target_item["thr-parent"]).">";
}
$headers .= "\n";
if (empty($target_item['title'])) {
$condition = ['uri' => $target_item['parent-uri'], 'uid' => $owner['uid']];
$title = dba::selectFirst('item', ['title'], $condition);
if (DBM::is_result($title) && ($title['title'] != '')) {
$subject = $title['title'];
} else {
$condition = ['parent-uri' => $target_item['parent-uri'], 'uid' => $owner['uid']];
$title = dba::selectFirst('item', ['title'], $condition);
if (DBM::is_result($title) && ($title['title'] != '')) {
$subject = $title['title'];
}
}
}
if (strncasecmp($subject, 'RE:', 3)) {
$subject = 'Re: ' . $subject;
}
}
Email::send($addr, $subject, $headers, $target_item);
} }
} }

View file

@ -309,7 +309,7 @@ class OnePoll
// Are we allowed to import from this person? // Are we allowed to import from this person?
if ($contact['rel'] == CONTACT_IS_FOLLOWER || $contact['blocked'] || $contact['readonly']) { if ($contact['rel'] == CONTACT_IS_FOLLOWER || $contact['blocked']) {
// set the last-update so we don't keep polling // set the last-update so we don't keep polling
dba::update('contact', ['last-update' => DateTimeFormat::utcNow()], ['id' => $contact['id']]); dba::update('contact', ['last-update' => DateTimeFormat::utcNow()], ['id' => $contact['id']]);
return; return;
@ -590,7 +590,7 @@ class OnePoll
} }
$hubmode = 'subscribe'; $hubmode = 'subscribe';
if ($contact['network'] === NETWORK_DFRN || $contact['blocked'] || $contact['readonly']) { if ($contact['network'] === NETWORK_DFRN || $contact['blocked']) {
$hubmode = 'unsubscribe'; $hubmode = 'unsubscribe';
} }

View file

@ -68,7 +68,7 @@ class PubSubPublish {
$rr['topic']), $rr['topic']),
"X-Hub-Signature: sha1=".$hmac_sig]; "X-Hub-Signature: sha1=".$hmac_sig];
logger('POST '.print_r($headers, true)."\n".$params, LOGGER_DEBUG); logger('POST '.print_r($headers, true)."\n".$params, LOGGER_DATA);
Network::post($rr['callback_url'], $params, $headers); Network::post($rr['callback_url'], $params, $headers);
$ret = $a->get_curl_code(); $ret = $a->get_curl_code();

View file

@ -65,7 +65,7 @@ $a->config['system']['no_regfullname'] = true;
//$a->config['system']['block_local_dir'] = false; //$a->config['system']['block_local_dir'] = false;
// Location of the global directory // Location of the global directory
$a->config['system']['directory'] = 'http://dir.friendica.social'; $a->config['system']['directory'] = 'https://dir.friendica.social';
// turn on friendica's log // turn on friendica's log
$a->config['system']['debugging'] = true; $a->config['system']['debugging'] = true;

File diff suppressed because it is too large Load diff

View file

@ -32,6 +32,9 @@ td.help {
td.help blockquote { td.help blockquote {
margin-left: 60px; margin-left: 60px;
} }
.error_header {
margin-left: 60px;
}
input[type="submit"] { input[type="submit"] {
margin: 2em 0; margin: 2em 0;
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,8 @@
<div class="field checkbox" id="div_id_{{$field.0}}"> <div class="field checkbox" id="div_id_{{$field.0}}">
<label for="id_{{$field.0}}">{{$field.1}}</label> <label id="id_{{$field.0}}_label" for="id_{{$field.0}}">{{$field.1}}</label>
<input type="hidden" name="{{$field.0}}" value="0"> <input type="hidden" name="{{$field.0}}" value="0">
<input type="checkbox" name="{{$field.0}}" id="id_{{$field.0}}" aria-describedby="{{$field.0}}_tip" value="1" {{if $field.2}}checked="checked"{{/if}} {{if $field.4}}{{$field.4}}{{/if}}> <input type="checkbox" name="{{$field.0}}" id="id_{{$field.0}}" aria-describedby="{{$field.0}}_tip" value="1" {{if $field.2}}checked="checked"{{/if}} {{if $field.4}}{{$field.4}}{{/if}}>
{{if $field.3}}
<span class="field_help" role="tooltip" id="{{$field.0}}_tip">{{$field.3}}</span> <span class="field_help" role="tooltip" id="{{$field.0}}_tip">{{$field.3}}</span>
{{/if}}
</div> </div>

View file

@ -13,6 +13,8 @@
{{foreach $field.4 as $opt=>$val}}<option value="{{$val|escape:'html'}}">{{$val}}</option>{{/foreach}} {{foreach $field.4 as $opt=>$val}}<option value="{{$val|escape:'html'}}">{{$val}}</option>{{/foreach}}
</select> </select>
<span class='field_help' role='tooltip' id='{{$field.0}}_tip'>{{$field.3}}</span> {{if $field.3}}
<span class="field_help" role="tooltip" id="{{$field.0}}_tip">{{$field.3}}</span>
{{/if}}
</div> </div>

View file

@ -3,5 +3,7 @@
<div class='field custom'> <div class='field custom'>
<label for='{{$field.0}}'>{{$field.1}}</label> <label for='{{$field.0}}'>{{$field.1}}</label>
{{$field.2}} {{$field.2}}
<span class='field_help'>{{$field.3}}</span> {{if $field.3}}
<span class="field_help" role="tooltip" id="{{$field.0}}_tip">{{$field.3}}</span>
{{/if}}
</div> </div>

View file

@ -2,5 +2,7 @@
<div class='field input' id='wrapper_{{$field.0}}'> <div class='field input' id='wrapper_{{$field.0}}'>
<label for='id_{{$field.0}}'>{{$field.1}}</label> <label for='id_{{$field.0}}'>{{$field.1}}</label>
<input{{if $field.6 eq 'email'}} type='email'{{elseif $field.6 eq 'url'}} type='url'{{else}} type="text"{{/if}} name='{{$field.0}}' id='id_{{$field.0}}' value="{{$field.2|escape:'html'}}"{{if $field.4 eq 'required'}} required{{/if}}{{if $field.5 eq "autofocus"}} autofocus{{elseif $field.5}} {{$field.5}}{{/if}} aria-describedby='{{$field.0}}_tip'> <input{{if $field.6 eq 'email'}} type='email'{{elseif $field.6 eq 'url'}} type='url'{{else}} type="text"{{/if}} name='{{$field.0}}' id='id_{{$field.0}}' value="{{$field.2|escape:'html'}}"{{if $field.4 eq 'required'}} required{{/if}}{{if $field.5 eq "autofocus"}} autofocus{{elseif $field.5}} {{$field.5}}{{/if}} aria-describedby='{{$field.0}}_tip'>
{{if $field.3}}
<span class='field_help' role='tooltip' id='{{$field.0}}_tip'>{{$field.3}}</span> <span class='field_help' role='tooltip' id='{{$field.0}}_tip'>{{$field.3}}</span>
{{/if}}
</div> </div>

View file

@ -3,5 +3,7 @@
<div class='field checkbox'> <div class='field checkbox'>
<label for='id_{{$field.0}}'>{{$field.1}}</label> <label for='id_{{$field.0}}'>{{$field.1}}</label>
<input type="checkbox" name='{{$field.0}}' id='id_{{$field.0}}' value="{{$field.3|escape:'html'}}" {{if $field.2}}checked="true"{{/if}} aria-describedby='{{$field.0}}_tip'> <input type="checkbox" name='{{$field.0}}' id='id_{{$field.0}}' value="{{$field.3|escape:'html'}}" {{if $field.2}}checked="true"{{/if}} aria-describedby='{{$field.0}}_tip'>
{{if $field.4}}
<span class='field_help' role='tooltip' id='{{$field.0}}_tip'>{{$field.4}}</span> <span class='field_help' role='tooltip' id='{{$field.0}}_tip'>{{$field.4}}</span>
{{/if}}
</div> </div>

View file

@ -2,5 +2,7 @@
<div class='field input openid' id='wrapper_{{$field.0}}'> <div class='field input openid' id='wrapper_{{$field.0}}'>
<label for='id_{{$field.0}}'>{{$field.1}}</label> <label for='id_{{$field.0}}'>{{$field.1}}</label>
<input name='{{$field.0}}' id='id_{{$field.0}}' type="text" value="{{$field.2|escape:'html'}}" aria-describedby='{{$field.0}}_tip'> <input name='{{$field.0}}' id='id_{{$field.0}}' type="text" value="{{$field.2|escape:'html'}}" aria-describedby='{{$field.0}}_tip'>
<span class='field_help' role='tooltip' id='{{$field.0}}_tip'>{{$field.3}}</span> {{if $field.3}}
<span class="field_help" role="tooltip" id="{{$field.0}}_tip">{{$field.3}}</span>
{{/if}}
</div> </div>

View file

@ -2,5 +2,7 @@
<div class='field password' id='wrapper_{{$field.0}}'> <div class='field password' id='wrapper_{{$field.0}}'>
<label for='id_{{$field.0}}'>{{$field.1}}</label> <label for='id_{{$field.0}}'>{{$field.1}}</label>
<input type='password' name='{{$field.0}}' id='id_{{$field.0}}' value="{{$field.2|escape:'html'}}"{{if $field.4 eq 'required'}} required{{/if}}{{if $field.5 eq 'autofocus'}} autofocus{{/if}} aria-describedby='{{$field.0}}_tip'> <input type='password' name='{{$field.0}}' id='id_{{$field.0}}' value="{{$field.2|escape:'html'}}"{{if $field.4 eq 'required'}} required{{/if}}{{if $field.5 eq 'autofocus'}} autofocus{{/if}} aria-describedby='{{$field.0}}_tip'>
{{if $field.3}}
<span class='field_help' role='tooltip' id='{{$field.0}}_tip'>{{$field.3}}</span> <span class='field_help' role='tooltip' id='{{$field.0}}_tip'>{{$field.3}}</span>
{{/if}}
</div> </div>

View file

@ -1,5 +1,7 @@
<div class='field radio'> <div class='field radio'>
<label for='id_{{$field.0}}_{{$field.2}}'>{{$field.1}}</label> <label for='id_{{$field.0}}_{{$field.2}}'>{{$field.1}}</label>
<input type="radio" name='{{$field.0}}' id='id_{{$field.0}}_{{$field.2}}' value="{{$field.2|escape:'html'}}" {{if $field.4}}checked{{/if}} aria-describedby={{$field.0}}_{{$field.2}}_tip'> <input type="radio" name='{{$field.0}}' id='id_{{$field.0}}_{{$field.2}}' value="{{$field.2|escape:'html'}}" {{if $field.4}}checked{{/if}} aria-describedby={{$field.0}}_{{$field.2}}_tip'>
{{if $field.3}}
<span class='field_help' role='tooltip' id='{{$field.0}}_{{$field.2}}_tip'>{{$field.3}}</span> <span class='field_help' role='tooltip' id='{{$field.0}}_{{$field.2}}_tip'>{{$field.3}}</span>
{{/if}}
</div> </div>

View file

@ -3,5 +3,7 @@
<div class='field richtext'> <div class='field richtext'>
<label for='id_{{$field.0}}'>{{$field.1}}</label> <label for='id_{{$field.0}}'>{{$field.1}}</label>
<textarea name='{{$field.0}}' id='id_{{$field.0}}' class="fieldRichtext" aria-describedby='{{$field.0}}_tip'>{{$field.2}}</textarea> <textarea name='{{$field.0}}' id='id_{{$field.0}}' class="fieldRichtext" aria-describedby='{{$field.0}}_tip'>{{$field.2}}</textarea>
<span class='field_help' role='tooltip' id='{{$field.0}}_tip'>{{$field.3}}</span> {{if $field.3}}
<span class="field_help" role="tooltip" id="{{$field.0}}_tip">{{$field.3}}</span>
{{/if}}
</div> </div>

View file

@ -5,5 +5,7 @@
<select name='{{$field.0}}' id='id_{{$field.0}}' aria-describedby='{{$field.0}}_tip'> <select name='{{$field.0}}' id='id_{{$field.0}}' aria-describedby='{{$field.0}}_tip'>
{{foreach $field.4 as $opt=>$val}}<option value="{{$opt|escape:'html'}}" {{if $opt==$field.2}}selected="selected"{{/if}}>{{$val}}</option>{{/foreach}} {{foreach $field.4 as $opt=>$val}}<option value="{{$opt|escape:'html'}}" {{if $opt==$field.2}}selected="selected"{{/if}}>{{$val}}</option>{{/foreach}}
</select> </select>
<span class='field_help' role='tooltip' id='{{$field.0}}_tip'>{{$field.3}}</span> {{if $field.3}}
<span class="field_help" role="tooltip" id="{{$field.0}}_tip">{{$field.3}}</span>
{{/if}}
</div> </div>

View file

@ -5,5 +5,7 @@
<select name='{{$field.0}}' id='id_{{$field.0}}' aria-describedby='{{$field.0}}_tip'> <select name='{{$field.0}}' id='id_{{$field.0}}' aria-describedby='{{$field.0}}_tip'>
{{$field.4}} {{$field.4}}
</select> </select>
<span class='field_help' role='tooltip' id='{{$field.0}}_tip'>{{$field.3}}</span> {{if $field.3}}
<span class="field_help" role="tooltip" id="{{$field.0}}_tip">{{$field.3}}</span>
{{/if}}
</div> </div>

View file

@ -3,5 +3,7 @@
<div class='field textarea'> <div class='field textarea'>
<label for='id_{{$field.0}}'>{{$field.1}}</label> <label for='id_{{$field.0}}'>{{$field.1}}</label>
<textarea name='{{$field.0}}' id='id_{{$field.0}}' aria-describedby='{{$field.0}}_tip'>{{$field.2}}</textarea> <textarea name='{{$field.0}}' id='id_{{$field.0}}' aria-describedby='{{$field.0}}_tip'>{{$field.2}}</textarea>
<span class='field_help' role='tooltip' id='{{$field.0}}_tip'>{{$field.3}}</span> {{if $field.3}}
<span class="field_help" role="tooltip" id="{{$field.0}}_tip">{{$field.3}}</span>
{{/if}}
</div> </div>

View file

@ -5,6 +5,8 @@
<select name='{{$field.0}}' id='id_{{$field.0}}' {{if $field.5}}onchange="previewTheme(this);"{{/if}} aria-describedby='{{$field.0}}_tip'> <select name='{{$field.0}}' id='id_{{$field.0}}' {{if $field.5}}onchange="previewTheme(this);"{{/if}} aria-describedby='{{$field.0}}_tip'>
{{foreach $field.4 as $opt=>$val}}<option value="{{$opt|escape:'html'}}" {{if $opt==$field.2}}selected="selected"{{/if}}>{{$val}}</option>{{/foreach}} {{foreach $field.4 as $opt=>$val}}<option value="{{$opt|escape:'html'}}" {{if $opt==$field.2}}selected="selected"{{/if}}>{{$val}}</option>{{/foreach}}
</select> </select>
<span class='field_help' role='tooltip' id='{{$field.0}}_tip'>{{$field.3}}</span> {{if $field.3}}
<span class="field_help" role="tooltip" id="{{$field.0}}_tip">{{$field.3}}</span>
{{/if}}
{{if $field.5}}<div id="theme-preview"></div>{{/if}} {{if $field.5}}<div id="theme-preview"></div>{{/if}}
</div> </div>

View file

@ -10,5 +10,7 @@
{{if $field.4}}{{$field.4.1}}{{else}}ON{{/if}} {{if $field.4}}{{$field.4.1}}{{else}}ON{{/if}}
</a> </a>
</div> </div>
<span class='field_help' role='tooltip' id='{{$field.0}}_tip'>{{$field.3}}</span> {{if $field.3}}
<span class="field_help" role="tooltip" id="{{$field.0}}_tip">{{$field.3}}</span>
{{/if}}
</div> </div>

View file

@ -107,7 +107,7 @@ $a->config['system']['no_regfullname'] = true;
//$a->config['system']['block_local_dir'] = false; //$a->config['system']['block_local_dir'] = false;
// Location of the global directory // Location of the global directory
$a->config['system']['directory'] = 'http://dir.friendica.social'; $a->config['system']['directory'] = 'https://dir.friendica.social';
// Authentication cookie lifetime, in days // Authentication cookie lifetime, in days
$a->config['system']['auth_cookie_lifetime'] = 7; $a->config['system']['auth_cookie_lifetime'] = 7;

View file

@ -16,7 +16,13 @@
{{/if}} {{/if}}
</td><td>{{if $check.required}}(required){{/if}}</td></tr> </td><td>{{if $check.required}}(required){{/if}}</td></tr>
{{if $check.help}} {{if $check.help}}
<tr><td class="help" colspan="3"><blockquote>{{$check.help}}</blockquote></td></tr> <tr><td class="help" colspan="3">
<blockquote>{{$check.help}}</blockquote>
{{if $check.error_msg}}
<div class="error_header"><b>{{$check.error_msg.head}}</br><a href="{{$check.error_msg.url}}">{{$check.error_msg.url}}</a></b></div>
<blockquote>{{$check.error_msg.msg}}</blockquote>
{{/if}}
</td></tr>
{{/if}} {{/if}}
{{/foreach}} {{/foreach}}
</table> </table>

View file

@ -4,11 +4,14 @@
<div id="login-group" role="group" aria-labelledby="login-head"> <div id="login-group" role="group" aria-labelledby="login-head">
<input type="hidden" name="auth-params" value="login" /> <input type="hidden" name="auth-params" value="login" />
<div id="login-head" class="sr-only">{{$login}}</div> <h3 id="login-head" class="sr-only">{{$login}}</h3>
<div id="login_standard"> <div id="login_standard">
{{include file="field_input.tpl" field=$lname}} {{include file="field_input.tpl" field=$lname}}
{{include file="field_password.tpl" field=$lpassword}} {{include file="field_password.tpl" field=$lpassword}}
<div id="login-lost-password-link">
<a href="lostpass" title="{{$lostpass|escape:'html'}}" id="lost-password-link" >{{$lostlink}}</a>
</div>
</div> </div>
{{if $openid}} {{if $openid}}
@ -17,17 +20,12 @@
</div> </div>
{{/if}} {{/if}}
{{include file="field_checkbox.tpl" field=$lremember}}
<div id="login-extra-links">
{{if $register}}<a href="register" title="{{$register.title|escape:'html'}}" id="register-link">{{$register.desc}}</a>{{/if}}
<a href="lostpass" title="{{$lostpass|escape:'html'}}" id="lost-password-link" >{{$lostlink}}</a>
</div>
<div id="login-submit-wrapper" > <div id="login-submit-wrapper" >
<input type="submit" name="submit" id="login-submit-button" value="{{$login|escape:'html'}}" /> <input type="submit" name="submit" id="login-submit-button" value="{{$login|escape:'html'}}" />
</div> </div>
{{include file="field_checkbox.tpl" field=$lremember}}
{{foreach $hiddens as $k=>$v}} {{foreach $hiddens as $k=>$v}}
<input type="hidden" name="{{$k}}" value="{{$v|escape:'html'}}" /> <input type="hidden" name="{{$k}}" value="{{$v|escape:'html'}}" />
{{/foreach}} {{/foreach}}
@ -35,5 +33,11 @@
</div> </div>
</form> </form>
{{if $register}}
<div id="login-extra-links">
<h3 id="login-head" class="sr-only">{{$register.title|escape:'html'}}</h3>
<a href="register" title="{{$register.title|escape:'html'}}" id="register-link">{{$register.desc}}</a>
</div>
{{/if}}
<script type="text/javascript"> $(document).ready(function() { $("#id_{{$lname.0}}").focus();} );</script> <script type="text/javascript"> $(document).ready(function() { $("#id_{{$lname.0}}").focus();} );</script>

View file

@ -37,11 +37,11 @@ Don't blame me too much for ugly code and hacks. Fix it ;-)
**Theme - Settings** **Theme - Settings**
![Theme - Settings](https://github.com/rabuzarus/frio/blob/master/img/screenshots/screenshot-settings.png) ![Theme - Settings](https://github.com/rabuzarus/frio/blob/master/img/screenshots/screenshot-settings.png)
**Red schema** **Red scheme**
![Red schema](https://github.com/rabuzarus/frio/blob/master/img/screenshots/screenshot-schema-red.png) ![Red scheme](https://github.com/rabuzarus/frio/blob/master/img/screenshots/screenshot-scheme-red.png)
**Love Music schema** **Love Music scheme**
![Love Music schema](https://github.com/rabuzarus/frio/blob/master/img/screenshots/screenshot-schema-love-music.png) ![Love Music scheme](https://github.com/rabuzarus/frio/blob/master/img/screenshots/screenshot-scheme-love-music.png)
**frio on mobile** **frio on mobile**

View file

@ -8,129 +8,135 @@ use Friendica\Core\System;
require_once 'view/theme/frio/php/Image.php'; require_once 'view/theme/frio/php/Image.php';
function theme_post(App $a) { function theme_post(App $a)
{
if (!local_user()) { if (!local_user()) {
return; return;
} }
if (isset($_POST['frio-settings-submit'])) { if (isset($_POST['frio-settings-submit'])) {
PConfig::set(local_user(), 'frio', 'schema', $_POST["frio_schema"]); PConfig::set(local_user(), 'frio', 'scheme', $_POST['frio_scheme']);
PConfig::set(local_user(), 'frio', 'nav_bg', $_POST["frio_nav_bg"]); PConfig::set(local_user(), 'frio', 'nav_bg', $_POST['frio_nav_bg']);
PConfig::set(local_user(), 'frio', 'nav_icon_color', $_POST["frio_nav_icon_color"]); PConfig::set(local_user(), 'frio', 'nav_icon_color', $_POST['frio_nav_icon_color']);
PConfig::set(local_user(), 'frio', 'link_color', $_POST["frio_link_color"]); PConfig::set(local_user(), 'frio', 'link_color', $_POST['frio_link_color']);
PConfig::set(local_user(), 'frio', 'background_color', $_POST["frio_background_color"]); PConfig::set(local_user(), 'frio', 'background_color', $_POST['frio_background_color']);
PConfig::set(local_user(), 'frio', 'contentbg_transp', $_POST["frio_contentbg_transp"]); PConfig::set(local_user(), 'frio', 'contentbg_transp', $_POST['frio_contentbg_transp']);
PConfig::set(local_user(), 'frio', 'background_image', $_POST["frio_background_image"]); PConfig::set(local_user(), 'frio', 'background_image', $_POST['frio_background_image']);
PConfig::set(local_user(), 'frio', 'bg_image_option', $_POST["frio_bg_image_option"]); PConfig::set(local_user(), 'frio', 'bg_image_option', $_POST['frio_bg_image_option']);
PConfig::set(local_user(), 'frio', 'css_modified', time()); PConfig::set(local_user(), 'frio', 'css_modified', time());
} }
} }
function theme_admin_post(App $a) { function theme_admin_post(App $a)
{
if (!local_user()) { if (!local_user()) {
return; return;
} }
if (isset($_POST['frio-settings-submit'])) { if (isset($_POST['frio-settings-submit'])) {
Config::set('frio', 'schema', $_POST["frio_schema"]); Config::set('frio', 'scheme', $_POST['frio_scheme']);
Config::set('frio', 'nav_bg', $_POST["frio_nav_bg"]); Config::set('frio', 'nav_bg', $_POST['frio_nav_bg']);
Config::set('frio', 'nav_icon_color', $_POST["frio_nav_icon_color"]); Config::set('frio', 'nav_icon_color', $_POST['frio_nav_icon_color']);
Config::set('frio', 'link_color', $_POST["frio_link_color"]); Config::set('frio', 'link_color', $_POST['frio_link_color']);
Config::set('frio', 'background_color', $_POST["frio_background_color"]); Config::set('frio', 'background_color', $_POST['frio_background_color']);
Config::set('frio', 'contentbg_transp', $_POST["frio_contentbg_transp"]); Config::set('frio', 'contentbg_transp', $_POST['frio_contentbg_transp']);
Config::set('frio', 'background_image', $_POST["frio_background_image"]); Config::set('frio', 'background_image', $_POST['frio_background_image']);
Config::set('frio', 'bg_image_option', $_POST["frio_bg_image_option"]); Config::set('frio', 'bg_image_option', $_POST['frio_bg_image_option']);
Config::set('frio', 'login_bg_image', $_POST["frio_login_bg_image"]); Config::set('frio', 'login_bg_image', $_POST['frio_login_bg_image']);
Config::set('frio', 'login_bg_color', $_POST["frio_login_bg_color"]); Config::set('frio', 'login_bg_color', $_POST['frio_login_bg_color']);
Config::set('frio', 'css_modified', time()); Config::set('frio', 'css_modified', time());
} }
} }
function theme_content(App $a) { function theme_content(App $a)
{
if (!local_user()) { if (!local_user()) {
return; return;
} }
$arr = []; $arr = [];
$arr["schema"] = PConfig::get(local_user(), 'frio', 'schema'); $arr['scheme'] = PConfig::get(local_user(), 'frio', 'scheme', PConfig::get(local_user(), 'frio', 'schema'));
$arr["nav_bg"] = PConfig::get(local_user(), 'frio', 'nav_bg'); $arr['nav_bg'] = PConfig::get(local_user(), 'frio', 'nav_bg');
$arr["nav_icon_color"] = PConfig::get(local_user(), 'frio', 'nav_icon_color'); $arr['nav_icon_color'] = PConfig::get(local_user(), 'frio', 'nav_icon_color');
$arr["link_color"] = PConfig::get(local_user(), 'frio', 'link_color'); $arr['link_color'] = PConfig::get(local_user(), 'frio', 'link_color');
$arr["bgcolor"] = PConfig::get(local_user(), 'frio', 'background_color'); $arr['background_color'] = PConfig::get(local_user(), 'frio', 'background_color');
$arr["contentbg_transp"] = PConfig::get(local_user(), 'frio', 'contentbg_transp'); $arr['contentbg_transp'] = PConfig::get(local_user(), 'frio', 'contentbg_transp');
$arr["background_image"] = PConfig::get(local_user(), 'frio', 'background_image'); $arr['background_image'] = PConfig::get(local_user(), 'frio', 'background_image');
$arr["bg_image_option"] = PConfig::get(local_user(), 'frio', 'bg_image_option'); $arr['bg_image_option'] = PConfig::get(local_user(), 'frio', 'bg_image_option');
return frio_form($arr); return frio_form($arr);
} }
function theme_admin(App $a) { function theme_admin(App $a)
{
if (!local_user()) { if (!local_user()) {
return; return;
} }
$arr = []; $arr = [];
$arr["schema"] = Config::get('frio', 'schema'); $arr['scheme'] = Config::get('frio', 'scheme', Config::get('frio', 'scheme'));
$arr["nav_bg"] = Config::get('frio', 'nav_bg'); $arr['nav_bg'] = Config::get('frio', 'nav_bg');
$arr["nav_icon_color"] = Config::get('frio', 'nav_icon_color'); $arr['nav_icon_color'] = Config::get('frio', 'nav_icon_color');
$arr["link_color"] = Config::get('frio', 'link_color'); $arr['link_color'] = Config::get('frio', 'link_color');
$arr["bgcolor"] = Config::get('frio', 'background_color'); $arr['background_color'] = Config::get('frio', 'background_color');
$arr["contentbg_transp"] = Config::get('frio', 'contentbg_transp'); $arr['contentbg_transp'] = Config::get('frio', 'contentbg_transp');
$arr["background_image"] = Config::get('frio', 'background_image'); $arr['background_image'] = Config::get('frio', 'background_image');
$arr["bg_image_option"] = Config::get('frio', 'bg_image_option'); $arr['bg_image_option'] = Config::get('frio', 'bg_image_option');
$arr["login_bg_image"] = Config::get('frio', 'login_bg_image'); $arr['login_bg_image'] = Config::get('frio', 'login_bg_image');
$arr["login_bg_color"] = Config::get('frio', 'login_bg_color'); $arr['login_bg_color'] = Config::get('frio', 'login_bg_color');
return frio_form($arr); return frio_form($arr);
} }
function frio_form($arr) { function frio_form($arr)
require_once("view/theme/frio/php/schema.php"); {
require_once 'view/theme/frio/php/scheme.php';
$scheme_info = get_schema_info($arr["schema"]); $scheme_info = get_scheme_info($arr['scheme']);
$disable = $scheme_info["overwrites"]; $disable = $scheme_info['overwrites'];
if (!is_array($disable)) { if (!is_array($disable)) {
$disable = []; $disable = [];
} }
$scheme_choices = []; $scheme_choices = [];
$scheme_choices["---"] = L10n::t("Default"); $scheme_choices['---'] = L10n::t('Custom');
$files = glob('view/theme/frio/schema/*.php'); $files = glob('view/theme/frio/scheme/*.php');
if ($files) { if ($files) {
foreach ($files as $file) { foreach ($files as $file) {
$f = basename($file, ".php"); $f = basename($file, '.php');
if ($f != 'default') { if ($f != 'default') {
$scheme_name = $f; $scheme_name = ucfirst($f);
$scheme_choices[$f] = $scheme_name; $scheme_choices[$f] = $scheme_name;
} }
} }
} }
$background_image_help = "<strong>" . L10n::t("Note"). ": </strong>".L10n::t("Check image permissions if all users are allowed to visit the image"); $background_image_help = '<strong>' . L10n::t('Note') . ': </strong>' . L10n::t('Check image permissions if all users are allowed to see the image');
$t = get_markup_template('theme_settings.tpl'); $t = get_markup_template('theme_settings.tpl');
$ctx = [ $ctx = [
'$submit' => L10n::t('Submit'), '$submit' => L10n::t('Submit'),
'$baseurl' => System::baseUrl(), '$baseurl' => System::baseUrl(),
'$title' => L10n::t("Theme settings"), '$title' => L10n::t('Theme settings'),
'$schema' => ['frio_schema', L10n::t("Select scheme"), $arr["schema"], '', $scheme_choices], '$scheme' => ['frio_scheme', L10n::t('Select color scheme'), $arr['scheme'], '', $scheme_choices],
'$nav_bg' => array_key_exists("nav_bg", $disable) ? "" : ['frio_nav_bg', L10n::t('Navigation bar background color'), $arr['nav_bg'], '', false], '$nav_bg' => array_key_exists('nav_bg', $disable) ? '' : ['frio_nav_bg', L10n::t('Navigation bar background color'), $arr['nav_bg'], '', false],
'$nav_icon_color' => array_key_exists("nav_icon_color", $disable) ? "" : ['frio_nav_icon_color', L10n::t('Navigation bar icon color '), $arr['nav_icon_color'], '', false], '$nav_icon_color' => array_key_exists('nav_icon_color', $disable) ? '' : ['frio_nav_icon_color', L10n::t('Navigation bar icon color '), $arr['nav_icon_color'], '', false],
'$link_color' => array_key_exists("link_color", $disable) ? "" : ['frio_link_color', L10n::t('Link color'), $arr['link_color'], '', false], '$link_color' => array_key_exists('link_color', $disable) ? '' : ['frio_link_color', L10n::t('Link color'), $arr['link_color'], '', false],
'$bgcolor' => array_key_exists("bgcolor", $disable) ? "" : ['frio_background_color', L10n::t('Set the background color'), $arr['bgcolor'], '', false], '$background_color' => array_key_exists('background_color', $disable) ? '' : ['frio_background_color', L10n::t('Set the background color'), $arr['background_color'], '', false],
'$contentbg_transp' => array_key_exists("contentbg_transp", $disable) ? "" : ['frio_contentbg_transp', L10n::t("Content background opacity"), ((isset($arr["contentbg_transp"]) && $arr["contentbg_transp"] != "") ? $arr["contentbg_transp"] : 100), ''], '$contentbg_transp' => array_key_exists('contentbg_transp', $disable) ? '' : ['frio_contentbg_transp', L10n::t('Content background opacity'), defaults($arr, 'contentbg_transp', 100), ''],
'$background_image' => array_key_exists("background_image", $disable) ? "" : ['frio_background_image', L10n::t('Set the background image'), $arr['background_image'], $background_image_help, false], '$background_image' => array_key_exists('background_image', $disable) ? '' : ['frio_background_image', L10n::t('Set the background image'), $arr['background_image'], $background_image_help, false],
'$bg_image_options_title' => L10n::t('Background image style'),
'$bg_image_options' => Image::get_options($arr), '$bg_image_options' => Image::get_options($arr),
]; ];
if (array_key_exists("login_bg_image", $arr) && !array_key_exists("login_bg_image", $disable)) { if (array_key_exists('login_bg_image', $arr) && !array_key_exists('login_bg_image', $disable)) {
$ctx['$login_bg_image'] = ['frio_login_bg_image', L10n::t('Login page background image'), $arr['login_bg_image'], $background_image_help, false]; $ctx['$login_bg_image'] = ['frio_login_bg_image', L10n::t('Login page background image'), $arr['login_bg_image'], $background_image_help, false];
} }
if (array_key_exists("login_bg_color", $arr) && !array_key_exists("login_bg_color", $disable)) {
if (array_key_exists('login_bg_color', $arr) && !array_key_exists('login_bg_color', $disable)) {
$ctx['$login_bg_color'] = ['frio_login_bg_color', L10n::t('Login page background color'), $arr['login_bg_color'], L10n::t('Leave background image and color empty for theme defaults'), false]; $ctx['$login_bg_color'] = ['frio_login_bg_color', L10n::t('Login page background color'), $arr['login_bg_color'], L10n::t('Leave background image and color empty for theme defaults'), false];
} }
$o = replace_macros($t, $ctx); $o = replace_macros($t, $ctx);
return $o; return $o;

View file

@ -24,9 +24,10 @@ and open the template in the editor.
body { body {
padding-top: 110px; padding-top: 110px;
background-color: $bgcolor; background-color: $background_color;
background-image: url("$background_image"); background-image: url("$background_image");
background-size: $background_size_img; background-size: $background_size_img;
background-repeat: $background_repeat;
background-attachment: fixed; background-attachment: fixed;
color: #777; color: #777;
/*color: #555;*/ /*color: #555;*/
@ -3154,12 +3155,30 @@ section .profile-match-wrapper {
* Login page * Login page
*/ */
#login-submit-wrapper { #login-submit-wrapper {
display: flex; float: right;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
} }
#lost-password-link { flex-grow: 2; } #lost-password-link { flex-grow: 2; }
#login-lost-password-link {
margin-bottom: 10px;
float: right;
}
#div_id_remember {
float: left;
}
#id_password_wrapper {
margin-bottom: unset;
}
#login_openid {
clear: both;
}
#register-link {
color: white;
background: #8ad0a1;
width: 100%;
}
#login-end {
clear: both;
}
.mod-home.is-not-singleuser, .mod-home.is-not-singleuser,
.mod-login { .mod-login {
@ -3184,12 +3203,15 @@ section .profile-match-wrapper {
margin-top: 2.5%; margin-top: 2.5%;
} }
.mod-home.is-not-singleuser .login-form > #login-extra-links {
margin-top: 4em;
}
.mod-home.is-not-singleuser .login-form > #login-form label, .mod-home.is-not-singleuser .login-form > #login-form label,
.mod-login #content #login-form label { .mod-login #content #login-form label {
color: #eee; color: #eee;
} }
.mod-home.is-not-singleuser .login-panel-content, .mod-home.is-not-singleuser .login-panel-content,
.mod-login .login-panel-content { .mod-login .login-panel-content {
background-color: rgba(255,255,255,.85); background-color: rgba(255,255,255,.85);
@ -3203,11 +3225,15 @@ section .profile-match-wrapper {
} }
.mod-home.is-not-singleuser .login-form > #login-form, .mod-home.is-not-singleuser .login-form > #login-form,
.mod-home.is-not-singleuser .login-form > #login-extra-links,
.mod-login #content #login-form { .mod-login #content #login-form {
background-color: #fff; background-color: #fff;
padding: 1em; padding: 1em;
position: relative; position: relative;
margin-top: 4em; }
.mod-home.is-not-singleuser .login-form > #login-extra-links {
margin-top: unset;
background-color: white;
} }
.mod-home.is-not-singleuser .login-form > #login-form label, .mod-home.is-not-singleuser .login-form > #login-form label,
@ -3215,7 +3241,7 @@ section .profile-match-wrapper {
color: #444; color: #444;
} }
.mod-home.is-not-singleuser .login-form > #login-form::before, .mod-home.is-not-singleuser .login-form::before,
.mod-login #content #login-form::before { .mod-login #content #login-form::before {
display: block; display: block;
position: absolute; position: absolute;
@ -3228,7 +3254,7 @@ section .profile-match-wrapper {
z-index: -1; z-index: -1;
} }
.mod-home.is-not-singleuser .login-form > #login-form::after, .mod-home.is-not-singleuser .login-form::after,
.mod-login #content #login-form::after { .mod-login #content #login-form::after {
display: block; display: block;
position: absolute; position: absolute;

View file

Before

Width:  |  Height:  |  Size: 239 KiB

After

Width:  |  Height:  |  Size: 239 KiB

View file

Before

Width:  |  Height:  |  Size: 750 KiB

After

Width:  |  Height:  |  Size: 750 KiB

View file

@ -21,14 +21,10 @@ class Image
public static function get_options($arr) public static function get_options($arr)
{ {
$bg_image_options = [ $bg_image_options = [
'repeat' => [ 'stretch' => ['frio_bg_image_option', L10n::t('Top Banner'), 'stretch', L10n::t('Resize image to the width of the screen and show background color below on long pages.'), ($arr['bg_image_option'] == 'stretch')],
'frio_bg_image_option', L10n::t("Repeat the image"), "repeat", L10n::t("Will repeat your image to fill the background."), ($arr["bg_image_option"] == "repeat")], 'cover' => ['frio_bg_image_option', L10n::t('Full screen'), 'cover', L10n::t('Resize image to fill entire screen, clipping either the right or the bottom.'), ($arr['bg_image_option'] == 'cover')],
'stretch' => [ 'contain' => ['frio_bg_image_option', L10n::t('Single row mosaic'), 'contain', L10n::t('Resize image to repeat it on a single row, either vertical or horizontal.'), ($arr['bg_image_option'] == 'contain')],
'frio_bg_image_option', L10n::t("Stretch"), "stretch", L10n::t("Will stretch to width/height of the image."), ($arr["bg_image_option"] == "stretch")], 'repeat' => ['frio_bg_image_option', L10n::t('Mosaic'), 'repeat', L10n::t('Repeat image to fill the screen.'), ($arr['bg_image_option'] == 'repeat')],
'cover' => [
'frio_bg_image_option', L10n::t("Resize fill and-clip"), "cover", L10n::t("Resize to fill and retain aspect ratio."), ($arr["bg_image_option"] == "cover")],
'contain' => [
'frio_bg_image_option', L10n::t("Resize best fit"), "contain", L10n::t("Resize to best fit and retain aspect ratio."), ($arr["bg_image_option"] == "contain")],
]; ];
return $bg_image_options; return $bg_image_options;

View file

@ -43,10 +43,10 @@ if (!isset($minimal)) {
if (is_null($uid)) { if (is_null($uid)) {
$uid = Profile::getThemeUid(); $uid = Profile::getThemeUid();
} }
$schema = PConfig::get($uid, 'frio', 'schema'); $scheme = PConfig::get($uid, 'frio', 'scheme', PConfig::get($uid, 'frio', 'schema'));
if (($schema) && ($schema != '---')) { if (($scheme) && ($scheme != '---')) {
if (file_exists('view/theme/frio/schema/' . $schema . '.php')) { if (file_exists('view/theme/frio/scheme/' . $scheme . '.php')) {
$schemefile = 'view/theme/frio/schema/' . $schema . '.php'; $schemefile = 'view/theme/frio/scheme/' . $scheme . '.php';
require_once $schemefile; require_once $schemefile;
} }
} else { } else {

View file

@ -14,24 +14,23 @@ use Friendica\App;
* *
* @todo Check if this is really needed. * @todo Check if this is really needed.
*/ */
function load_page(App $a) { function load_page(App $a)
if(isset($_GET["mode"]) && ($_GET["mode"] == "minimal")) { {
require "view/theme/frio/minimal.php"; if (isset($_GET['mode']) && ($_GET['mode'] == 'minimal')) {
} elseif((isset($_GET["mode"]) && ($_GET["mode"] == "none"))) { require 'view/theme/frio/minimal.php';
require "view/theme/frio/none.php"; } elseif ((isset($_GET['mode']) && ($_GET['mode'] == 'none'))) {
require 'view/theme/frio/none.php';
} else { } else {
$template = 'view/theme/' . current_theme() . '/' $template = 'view/theme/' . $a->getCurrentTheme() . '/'
. ((x($a->page,'template')) ? $a->page['template'] : 'default' ) . '.php'; . ((x($a->page, 'template')) ? $a->page['template'] : 'default' ) . '.php';
if(file_exists($template)) if (file_exists($template)) {
require_once($template); require_once $template;
else } else {
require_once(str_replace('theme/' . current_theme() . '/', '', $template)); require_once str_replace('theme/' . $a->getCurrentTheme() . '/', '', $template);
}
} }
} }
/** /**
* @brief Check if page is a modal page * @brief Check if page is a modal page
* *

View file

@ -1,74 +0,0 @@
<?php
/**
* @brief: Get info header of the shema
*
* This function parses the header of the shemename.php file for inormations like
* Author, Description and Overwrites. Most of the code comes from the Addon::getInfo()
* function. We use this to get the variables which get overwritten through the shema.
* All color variables which get overwritten through the theme have to be
* listed (comma seperated) in the shema header under Overwrites:
* This seemst not to be the best solution. We need to investigate further.
*
* @param string $schema Name of the shema
* @return array With theme information
* 'author' => Author Name
* 'description' => Schema description
* 'version' => Schema version
* 'overwrites' => Variables which overwriting custom settings
*/
use Friendica\Core\PConfig;
function get_schema_info($schema){
$theme = current_theme();
$themepath = "view/theme/" . $theme . "/";
$schema = PConfig::get(local_user(),'frio', 'schema');
$info=[
'name' => $schema,
'description' => "",
'author' => [],
'version' => "",
'overwrites' => []
];
if (!is_file($themepath . "schema/" . $schema . ".php")) return $info;
$f = file_get_contents($themepath . "schema/" . $schema . ".php");
$r = preg_match("|/\*.*\*/|msU", $f, $m);
if ($r){
$ll = explode("\n", $m[0]);
foreach( $ll as $l ) {
$l = trim($l,"\t\n\r */");
if ($l!=""){
list($k,$v) = array_map("trim", explode(":",$l,2));
$k= strtolower($k);
if ($k=="author"){
$r=preg_match("|([^<]+)<([^>]+)>|", $v, $m);
if ($r) {
$info['author'][] = ['name'=>$m[1], 'link'=>$m[2]];
} else {
$info['author'][] = ['name'=>$v];
}
} elseif ($k == "overwrites") {
$theme_settings = explode(',',str_replace(' ','', $v));
foreach ($theme_settings as $key => $value) {
$info["overwrites"][$value] = true;
}
} else {
if (array_key_exists($k,$info)){
$info[$k]=$v;
}
}
}
}
}
return $info;
}

View file

@ -0,0 +1,73 @@
<?php
/**
* @brief: Get info header of the scheme
*
* This function parses the header of the schemename.php file for informations like
* Author, Description and Overwrites. Most of the code comes from the Addon::getInfo()
* function. We use this to get the variables which get overwritten through the scheme.
* All color variables which get overwritten through the theme have to be
* listed (comma separated) in the scheme header under Overwrites:
* This seems not to be the best solution. We need to investigate further.
*
* @param string $scheme Name of the scheme
* @return array With theme information
* 'author' => Author Name
* 'description' => Scheme description
* 'version' => Scheme version
* 'overwrites' => Variables which overwriting custom settings
*/
use Friendica\Core\PConfig;
require_once 'boot.php';
function get_scheme_info($scheme)
{
$theme = get_app()->getCurrentTheme();
$themepath = 'view/theme/' . $theme . '/';
$scheme = PConfig::get(local_user(), 'frio', 'scheme', PConfig::get(local_user(), 'frio', 'scheme'));
$info = [
'name' => $scheme,
'description' => '',
'author' => [],
'version' => '',
'overwrites' => []
];
if (!is_file($themepath . 'scheme/' . $scheme . '.php')) return $info;
$f = file_get_contents($themepath . 'scheme/' . $scheme . '.php');
$r = preg_match('|/\*.*\*/|msU', $f, $m);
if ($r) {
$ll = explode("\n", $m[0]);
foreach ($ll as $l) {
$l = trim($l, "\t\n\r */");
if ($l != '') {
list($k, $v) = array_map('trim', explode(':', $l, 2));
$k = strtolower($k);
if ($k == 'author') {
$r = preg_match('|([^<]+)<([^>]+)>|', $v, $m);
if ($r) {
$info['author'][] = ['name' => $m[1], 'link' => $m[2]];
} else {
$info['author'][] = ['name' => $v];
}
} elseif ($k == 'overwrites') {
$theme_settings = explode(',', str_replace(' ', '', $v));
foreach ($theme_settings as $key => $value) {
$info['overwrites'][$value] = true;
}
} else {
if (array_key_exists($k, $info)) {
$info[$k] = $v;
}
}
}
}
}
return $info;
}

View file

@ -16,7 +16,7 @@
<?php $frio = "view/theme/frio"; ?> <?php $frio = "view/theme/frio"; ?>
<?php if(x($page,'htmlhead')) echo $page['htmlhead']; ?> <?php if(x($page,'htmlhead')) echo $page['htmlhead']; ?>
</head> </head>
<body id=\"top\">"; <body id="top">
<?php if($_SERVER['REQUEST_URI'] == "/"){header('Location: /login');} ?> <?php if($_SERVER['REQUEST_URI'] == "/"){header('Location: /login');} ?>
<a href="#content" class="sr-only sr-only-focusable">Skip to main content</a> <a href="#content" class="sr-only sr-only-focusable">Skip to main content</a>
<?php <?php

View file

@ -0,0 +1,16 @@
<?php
/*
* Name: Blue
* Author: Rabuzarus
*
* List here all variables which will get overwritten through this scheme
* Overwrites: nav_bg, nav_icon_color, link_color, background_color, login_bg_color, contentbg_transp
*/
$nav_bg = "#708fa0";
$nav_icon_color = "#fff";
$link_color = "#6fdbe8";
$background_color = "#ededed";
$login_bg_color = "#ededed";
$contentbg_transp = 100;

View file

@ -1,13 +1,13 @@
<?php <?php
/* Licence: AGP /* Licence: AGP
* Author: rabuzarus * Author: rabuzarus
* Overwrites: nav_bg, nav_icon_color, link_color, bgcolor, contentbg_transp, background_image, bg_image_option, link_hover_color * Overwrites: nav_bg, nav_icon_color, link_color, background_color, contentbg_transp, background_image, bg_image_option, link_hover_color
*/ */
$nav_bg = "#000"; $nav_bg = "#000";
$nav_icon_color = "#e355e0"; $nav_icon_color = "#e355e0";
$link_color = "#e355e0"; $link_color = "#e355e0";
$bgcolor = "#fff"; $background_color = "#fff";
$contentbg_transp = 100; $contentbg_transp = 100;
$background_image = "img/bg_circle.png"; $background_image = "img/bg_circle.png";
$bg_image_option = "repeat"; $bg_image_option = "repeat";

View file

@ -3,13 +3,13 @@
* Name: Red * Name: Red
* Author: Rabuzarus * Author: Rabuzarus
* *
* List here all variables which will get overwritten through this schema * List here all variables which will get overwritten through this scheme
* Overwrites: nav_bg, nav_icon_color, link_color, bgcolor, contentbg_transp * Overwrites: nav_bg, nav_icon_color, link_color, background_color, contentbg_transp
*/ */
$nav_bg = "#870000"; $nav_bg = "#870000";
$nav_icon_color = "#f5f5f5"; $nav_icon_color = "#f5f5f5";
$link_color = "#b50404"; $link_color = "#b50404";
$bgcolor = "#ededed"; $background_color = "#ededed";
$contentbg_transp = 95; $contentbg_transp = 95;

View file

@ -8,7 +8,7 @@ use Friendica\Model\Profile;
require_once 'view/theme/frio/php/PHPColors/Color.php'; require_once 'view/theme/frio/php/PHPColors/Color.php';
$schemecss = ""; $schemecss = '';
$schemecssfile = false; $schemecssfile = false;
$scheme_modified = 0; $scheme_modified = 0;
@ -19,15 +19,15 @@ if ($a->module !== 'install') {
PConfig::load($uid, 'frio'); PConfig::load($uid, 'frio');
// Load the profile owners pconfig. // Load the profile owners pconfig.
$schema = PConfig::get($uid, "frio", "schema"); $scheme = PConfig::get($uid, 'frio', 'scheme', PConfig::get($uid, 'frio', 'schema'));
$nav_bg = PConfig::get($uid, "frio", "nav_bg"); $nav_bg = PConfig::get($uid, 'frio', 'nav_bg');
$nav_icon_color = PConfig::get($uid, "frio", "nav_icon_color"); $nav_icon_color = PConfig::get($uid, 'frio', 'nav_icon_color');
$link_color = PConfig::get($uid, "frio", "link_color"); $link_color = PConfig::get($uid, 'frio', 'link_color');
$bgcolor = PConfig::get($uid, "frio", "background_color"); $background_color = PConfig::get($uid, 'frio', 'background_color');
$contentbg_transp = PConfig::get($uid, "frio", "contentbg_transp"); $contentbg_transp = PConfig::get($uid, 'frio', 'contentbg_transp');
$background_image = PConfig::get($uid, "frio", "background_image"); $background_image = PConfig::get($uid, 'frio', 'background_image');
$bg_image_option = PConfig::get($uid, "frio", "bg_image_option"); $bg_image_option = PConfig::get($uid, 'frio', 'bg_image_option');
$modified = PConfig::get($uid, "frio", "css_modified"); $modified = PConfig::get($uid, 'frio', 'css_modified');
// There is maybe the case that the user did never modify the theme settings. // There is maybe the case that the user did never modify the theme settings.
// In this case we store the present time. // In this case we store the present time.
@ -38,17 +38,17 @@ if ($a->module !== 'install') {
Config::load('frio'); Config::load('frio');
// Load frios system config. // Load frios system config.
$schema = Config::get("frio", "schema"); $scheme = Config::get('frio', 'scheme', Config::get('frio', 'schema'));
$nav_bg = Config::get("frio", "nav_bg"); $nav_bg = Config::get('frio', 'nav_bg');
$nav_icon_color = Config::get("frio", "nav_icon_color"); $nav_icon_color = Config::get('frio', 'nav_icon_color');
$link_color = Config::get("frio", "link_color"); $link_color = Config::get('frio', 'link_color');
$bgcolor = Config::get("frio", "background_color"); $background_color = Config::get('frio', 'background_color');
$contentbg_transp = Config::get("frio", "contentbg_transp"); $contentbg_transp = Config::get('frio', 'contentbg_transp');
$background_image = Config::get("frio", "background_image"); $background_image = Config::get('frio', 'background_image');
$bg_image_option = Config::get("frio", "bg_image_option"); $bg_image_option = Config::get('frio', 'bg_image_option');
$login_bg_image = Config::get("frio", "login_bg_image"); $login_bg_image = Config::get('frio', 'login_bg_image');
$login_bg_color = Config::get("frio", "login_bg_color"); $login_bg_color = Config::get('frio', 'login_bg_color');
$modified = Config::get("frio", "css_modified"); $modified = Config::get('frio', 'css_modified');
// There is maybe the case that the user did never modify the theme settings. // There is maybe the case that the user did never modify the theme settings.
// In this case we store the present time. // In this case we store the present time.
@ -59,60 +59,59 @@ if ($a->module !== 'install') {
} }
// Now load the scheme. If a value is changed above, we'll keep the settings // Now load the scheme. If a value is changed above, we'll keep the settings
// If not, we'll keep those defined by the schema // If not, we'll keep those defined by the scheme
// Setting $schema to '' wasn't working for some reason, so we'll check it's // Setting $scheme to '' wasn't working for some reason, so we'll check it's
// not --- like the mobile theme does instead. // not --- like the mobile theme does instead.
// Allow layouts to over-ride the schema. // Allow layouts to over-ride the scheme.
if (x($_REQUEST, 'schema')) { if (x($_REQUEST, 'scheme')) {
$schema = $_REQUEST['schema']; $scheme = $_REQUEST['scheme'];
} }
// Sanitize the data. // Sanitize the data.
$schema = !empty($schema) ? basename($schema) : ""; $scheme = !empty($scheme) ? basename($scheme) : '';
if (($schema) && ($schema != '---')) { if (($scheme) && ($scheme != '---')) {
if (file_exists('view/theme/frio/schema/' . $schema . '.php')) { if (file_exists('view/theme/frio/scheme/' . $scheme . '.php')) {
$schemefile = 'view/theme/frio/schema/' . $schema . '.php'; $schemefile = 'view/theme/frio/scheme/' . $scheme . '.php';
require_once $schemefile; require_once $schemefile;
} }
if (file_exists('view/theme/frio/schema/' . $schema . '.css')) { if (file_exists('view/theme/frio/scheme/' . $scheme . '.css')) {
$schemecssfile = 'view/theme/frio/schema/' . $schema . '.css'; $schemecssfile = 'view/theme/frio/scheme/' . $scheme . '.css';
} }
} }
// If we haven't got a schema, load the default. We shouldn't touch this - we // If we haven't got a scheme, load the default. We shouldn't touch this - we
// should leave it for admins to define for themselves. // should leave it for admins to define for themselves.
// default.php and default.css MUST be symlinks to existing schema files. // default.php and default.css MUST be symlinks to existing scheme files.
if (! $schema) { if (!$scheme) {
if (file_exists('view/theme/frio/schema/default.php')) { if (file_exists('view/theme/frio/scheme/default.php')) {
$schemefile = 'view/theme/frio/schema/default.php'; $schemefile = 'view/theme/frio/scheme/default.php';
require_once $schemefile; require_once $schemefile;
} }
if (file_exists('view/theme/frio/schema/default.css')) { if (file_exists('view/theme/frio/scheme/default.css')) {
$schemecssfile = 'view/theme/frio/schema/default.css'; $schemecssfile = 'view/theme/frio/scheme/default.css';
} }
} }
//Set some defaults - we have to do this after pulling owner settings, and we have to check for each setting //Set some defaults - we have to do this after pulling owner settings, and we have to check for each setting
//individually. If we don't, we'll have problems if a user has set one, but not all options. //individually. If we don't, we'll have problems if a user has set one, but not all options.
$nav_bg = (empty($nav_bg) ? "#708fa0" : $nav_bg); $nav_bg = (empty($nav_bg) ? '#708fa0' : $nav_bg);
$nav_icon_color = (empty($nav_icon_color) ? "#fff" : $nav_icon_color); $nav_icon_color = (empty($nav_icon_color) ? '#fff' : $nav_icon_color);
$link_color = (empty($link_color) ? "#6fdbe8" : $link_color); $link_color = (empty($link_color) ? '#6fdbe8' : $link_color);
$bgcolor = (empty($bgcolor) ? "#ededed" : $bgcolor); $background_color = (empty($background_color) ? '#ededed' : $background_color);
// The background image can not be empty. So we use a dummy jpg if no image was set. // The background image can not be empty. So we use a dummy jpg if no image was set.
$background_image = (empty($background_image) ? 'img/none.jpg' : $background_image); $background_image = (empty($background_image) ? 'img/none.jpg' : $background_image);
$modified = (empty($modified) ? time() :$modified); $modified = (empty($modified) ? time() : $modified);
// set a default login bg image if no custom image and no custom bg color are set. // set a default login bg image if no custom image and no custom bg color are set.
if (empty($login_bg_image) && empty($login_bg_color)) { if (empty($login_bg_image) && empty($login_bg_color)) {
$login_bg_image = (empty($login_bg_image) ? 'img/login_bg.jpg' : $login_bg_image); $login_bg_image = 'img/login_bg.jpg';
} }
$login_bg_color = (empty($login_bg_color) ? "#ededed" : $login_bg_color); $login_bg_color = (empty($login_bg_color) ? '#ededed' : $login_bg_color);
$contentbg_transp = ((isset($contentbg_transp) && $contentbg_transp != '') ? $contentbg_transp : 100);
$contentbg_transp = ((isset($contentbg_transp) && $contentbg_transp != "") ? $contentbg_transp : 100);
// Calculate some colors in dependance of existing colors. // Calculate some colors in dependance of existing colors.
// Some colors are calculated to don't have too many selection // Some colors are calculated to don't have too many selection
@ -153,22 +152,28 @@ if (!isset($link_hover_color)) {
if (!isset($bg_image_option)) { if (!isset($bg_image_option)) {
$bg_image_option = null; $bg_image_option = null;
} }
switch ($bg_image_option) { switch ($bg_image_option) {
case "stretch": case 'stretch':
$background_size_img = "100%"; $background_size_img = '100%';
$background_repeat = 'no-repeat';
break; break;
case "cover": case 'cover':
$background_size_img ="cover"; $background_size_img = 'cover';
$background_repeat = 'no-repeat';
break; break;
case "repeat": case 'repeat':
$background_size_img = "auto"; $background_size_img = 'auto';
$background_repeat = 'repeat';
break; break;
case "contain": case 'contain':
$background_size_img = "contain"; $background_size_img = 'contain';
$background_repeat = 'repeat';
break; break;
default: default:
$background_size_img = "auto"; $background_size_img = 'auto';
$background_repeat = 'no-repeat';
break; break;
} }
@ -184,10 +189,11 @@ $options = [
'$menu_background_hover_color' => $menu_background_hover_color, '$menu_background_hover_color' => $menu_background_hover_color,
'$btn_primary_color' => $nav_icon_color, '$btn_primary_color' => $nav_icon_color,
'$btn_primary_hover_color' => $menu_background_hover_color, '$btn_primary_hover_color' => $menu_background_hover_color,
'$bgcolor' => $bgcolor, '$background_color' => $background_color,
'$contentbg_transp' => $contentbg_transp, '$contentbg_transp' => $contentbg_transp,
'$background_image' => $background_image, '$background_image' => $background_image,
'$background_size_img' => $background_size_img, '$background_size_img' => $background_size_img,
'$background_repeat' => $background_repeat,
'$login_bg_image' => $login_bg_image, '$login_bg_image' => $login_bg_image,
'$login_bg_color' => $login_bg_color '$login_bg_color' => $login_bg_color
]; ];
@ -214,13 +220,13 @@ $etag = md5($css);
// Set a header for caching. // Set a header for caching.
header('Cache-Control: public'); header('Cache-Control: public');
header('ETag: "'.$etag.'"'); header('ETag: "' . $etag . '"');
header('Last-Modified: '.$modified); header('Last-Modified: ' . $modified);
// Only send the CSS file if it was changed. // Only send the CSS file if it was changed.
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || isset($_SERVER['HTTP_IF_NONE_MATCH'])) { if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
$cached_modified = gmdate('r', strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])); $cached_modified = gmdate('r', strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']));
$cached_etag = str_replace(['"', "-gzip"], ['', ''], $cached_etag = str_replace(['"', '-gzip'], ['', ''],
stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])); stripslashes($_SERVER['HTTP_IF_NONE_MATCH']));
if (($cached_modified == $modified) && ($cached_etag == $etag)) { if (($cached_modified == $modified) && ($cached_etag == $etag)) {

View file

@ -4,6 +4,8 @@
<input type="checkbox" name="{{$field.0}}" id="id_{{$field.0}}" value="1" {{if $field.2}}checked="checked"{{/if}} aria-checked="{{if $field.2}}true{{else}}false{{/if}}" aria-describedby="{{$field.0}}_tip" {{if $field.4}}{{$field.4}}{{/if}}> <input type="checkbox" name="{{$field.0}}" id="id_{{$field.0}}" value="1" {{if $field.2}}checked="checked"{{/if}} aria-checked="{{if $field.2}}true{{else}}false{{/if}}" aria-describedby="{{$field.0}}_tip" {{if $field.4}}{{$field.4}}{{/if}}>
<label for="id_{{$field.0}}"> <label for="id_{{$field.0}}">
{{$field.1}} {{$field.1}}
{{if $field.3}}
<span class="help-block" id="{{$field.0}}_tip" role="tooltip">{{$field.3}}</span> <span class="help-block" id="{{$field.0}}_tip" role="tooltip">{{$field.3}}</span>
{{/if}}
</label> </label>
</div> </div>

View file

@ -6,6 +6,8 @@
{{if $field.4}}<span class="required">{{$field.4}}</span>{{/if}} {{if $field.4}}<span class="required">{{$field.4}}</span>{{/if}}
<span class="input-group-addon"><i></i></span> <span class="input-group-addon"><i></i></span>
</div> </div>
<span id="{{$field.0}}_tip" class="help-block" role="tooltip">{{$field.3}}</span> {{if $field.3}}
<span class="help-block" id="{{$field.0}}_tip" role="tooltip">{{$field.3}}</span>
{{/if}}
<div id="end_{{$field.0}}" class="field_end"></div> <div id="end_{{$field.0}}" class="field_end"></div>
</div> </div>

View file

@ -2,5 +2,7 @@
<div class="form-group field custom"> <div class="form-group field custom">
<label for="{{$field.0}}">{{$field.1}}</label> <label for="{{$field.0}}">{{$field.1}}</label>
{{$field.2}} {{$field.2}}
<span class="help-block" id="{{$field.0}}_tip">{{$field.3}}</span> {{if $field.3}}
<span class="help-block" id="{{$field.0}}_tip" role="tooltip">{{$field.3}}</span>
{{/if}}
</div> </div>

View file

@ -6,6 +6,8 @@
{{if $field.4}}<span class="required">{{$field.4}}</span>{{/if}} {{if $field.4}}<span class="required">{{$field.4}}</span>{{/if}}
<span class="input-group-addon image-select"><i class="fa fa-picture-o"></i></span> <span class="input-group-addon image-select"><i class="fa fa-picture-o"></i></span>
</div> </div>
<span id="{{$field.0}}_tip" class="help-block" role="tooltip">{{$field.3}}</span> {{if $field.3}}
<span class="help-block" id="{{$field.0}}_tip" role="tooltip">{{$field.3}}</span>
{{/if}}
<div id="end_{{$field.0}}" class="field_end"></div> <div id="end_{{$field.0}}" class="field_end"></div>
</div> </div>

View file

@ -2,6 +2,8 @@
<div id="id_{{$field.0}}_wrapper" class="form-group field input"> <div id="id_{{$field.0}}_wrapper" class="form-group field input">
<label for="id_{{$field.0}}" id="label_{{$field.0}}">{{$field.1}}{{if $field.4}}<span class="required"> {{$field.4}}</span>{{/if}}</label> <label for="id_{{$field.0}}" id="label_{{$field.0}}">{{$field.1}}{{if $field.4}}<span class="required"> {{$field.4}}</span>{{/if}}</label>
<input class="form-control" name="{{$field.0}}" id="id_{{$field.0}}"{{if $field.6 eq "email"}} type="email"{{elseif $field.6 eq "url"}} type="url"{{else}} type="text"{{/if}} value="{{$field.2|escape:'html'}}"{{if $field.4 eq "required"}} required{{/if}}{{if $field.5 eq "autofocus"}} autofocus{{elseif $field.5}} {{$field.5}}{{/if}} aria-describedby="{{$field.0}}_tip"> <input class="form-control" name="{{$field.0}}" id="id_{{$field.0}}"{{if $field.6 eq "email"}} type="email"{{elseif $field.6 eq "url"}} type="url"{{else}} type="text"{{/if}} value="{{$field.2|escape:'html'}}"{{if $field.4 eq "required"}} required{{/if}}{{if $field.5 eq "autofocus"}} autofocus{{elseif $field.5}} {{$field.5}}{{/if}} aria-describedby="{{$field.0}}_tip">
<span id="{{$field.0}}_tip" class="help-block" role="tooltip">{{$field.3}}</span> {{if $field.3}}
<span class="help-block" id="{{$field.0}}_tip" role="tooltip">{{$field.3}}</span>
{{/if}}
<div class="clear"></div> <div class="clear"></div>
</div> </div>

View file

@ -2,6 +2,8 @@
<div class="form-group field checkbox"> <div class="form-group field checkbox">
<input type="checkbox" name="{{$field.0}}" id="id_{{$field.0}}" value="{{$field.3|escape:'html'}}" {{if $field.2}}checked="checked"{{/if}} aria-checked="{{if $field.2}}true{{else}}false{{/if}}" aria-describedby="{{$field.0}}_tip"> <input type="checkbox" name="{{$field.0}}" id="id_{{$field.0}}" value="{{$field.3|escape:'html'}}" {{if $field.2}}checked="checked"{{/if}} aria-checked="{{if $field.2}}true{{else}}false{{/if}}" aria-describedby="{{$field.0}}_tip">
<label for="id_{{$field.0}}">{{$field.1}}</label> <label for="id_{{$field.0}}">{{$field.1}}</label>
<span class="help-block" role="tooltip" id="{{$field.0}}_tip">{{$field.4}}</span> {{if $field.4}}
<span class="help-block" id="{{$field.0}}_tip" role="tooltip">{{$field.4}}</span>
{{/if}}
</div> </div>
<div class="clear"></div> <div class="clear"></div>

View file

@ -2,6 +2,8 @@
<div id="id_{{$field.0}}_wrapper" class="form-group field input openid"> <div id="id_{{$field.0}}_wrapper" class="form-group field input openid">
<label for="id_{{$field.0}}" id="label_{{$field.0}}">{{$field.1}}</label> <label for="id_{{$field.0}}" id="label_{{$field.0}}">{{$field.1}}</label>
<input class="form-control" name="{{$field.0}}" id="id_{{$field.0}}" type="text" value="{{$field.2|escape:'html'}}" aria-describedby="{{$field.0}}_tip"> <input class="form-control" name="{{$field.0}}" id="id_{{$field.0}}" type="text" value="{{$field.2|escape:'html'}}" aria-describedby="{{$field.0}}_tip">
<span id="{{$field.0}}_tip" class="help-block" role="tooltip">{{$field.3}}</span> {{if $field.3}}
<span class="help-block" id="{{$field.0}}_tip" role="tooltip">{{$field.3}}</span>
{{/if}}
<div class="clear"></div> <div class="clear"></div>
</div> </div>

View file

@ -2,6 +2,8 @@
<div id="id_{{$field.0}}_wrapper" class="form-group field input password"> <div id="id_{{$field.0}}_wrapper" class="form-group field input password">
<label for="id_{{$field.0}}" id="label_{{$field.0}}">{{$field.1}}{{if $field.4}}<span class="required"> {{$field.4}}</span>{{/if}}</label> <label for="id_{{$field.0}}" id="label_{{$field.0}}">{{$field.1}}{{if $field.4}}<span class="required"> {{$field.4}}</span>{{/if}}</label>
<input class="form-control" name="{{$field.0}}" id="id_{{$field.0}}" type="password" value="{{$field.2|escape:'html'}}" {{if $field.4 eq "required"}} required{{/if}}{{if $field.5 eq "autofocus"}} autofocus{{elseif $field.5}} {{$field.5}}{{/if}} aria-describedby="{{$field.0}}_tip"> <input class="form-control" name="{{$field.0}}" id="id_{{$field.0}}" type="password" value="{{$field.2|escape:'html'}}" {{if $field.4 eq "required"}} required{{/if}}{{if $field.5 eq "autofocus"}} autofocus{{elseif $field.5}} {{$field.5}}{{/if}} aria-describedby="{{$field.0}}_tip">
<span id="{{$field.0}}_tip" class="help-block" role="tooltip">{{$field.3}}</span> {{if $field.3}}
<span class="help-block" id="{{$field.0}}_tip" role="tooltip">{{$field.3}}</span>
{{/if}}
<div class="clear"></div> <div class="clear"></div>
</div> </div>

View file

@ -4,7 +4,9 @@
<input type="radio" name="{{$field.0}}" id="id_{{$field.0}}_{{$field.2}}" value="{{$field.2}}" {{if $field.4}}checked{{/if}} aria-checked="{{if $field.4}}true{{else}}false{{/if}}" aria-describedby="{{$field.0}}_{{$field.2}}_tip"> <input type="radio" name="{{$field.0}}" id="id_{{$field.0}}_{{$field.2}}" value="{{$field.2}}" {{if $field.4}}checked{{/if}} aria-checked="{{if $field.4}}true{{else}}false{{/if}}" aria-describedby="{{$field.0}}_{{$field.2}}_tip">
<label for="id_{{$field.0}}_{{$field.2}}"> <label for="id_{{$field.0}}_{{$field.2}}">
{{$field.1}} {{$field.1}}
{{if $field.3}}
<span class="help-block" id="{{$field.0}}_{{$field.2}}_tip" role="tooltip">{{$field.3}}</span> <span class="help-block" id="{{$field.0}}_{{$field.2}}_tip" role="tooltip">{{$field.3}}</span>
{{/if}}
</label> </label>
</div> </div>
</div> </div>

View file

@ -4,5 +4,7 @@
<select name="{{$field.0}}" id="id_{{$field.0}}" class="form-control" aria-describedby="{{$field.0}}_tip"> <select name="{{$field.0}}" id="id_{{$field.0}}" class="form-control" aria-describedby="{{$field.0}}_tip">
{{foreach $field.4 as $opt=>$val}}<option value="{{$opt|escape:'html'}}" {{if $opt==$field.2}}selected="selected"{{/if}}>{{$val}}</option>{{/foreach}} {{foreach $field.4 as $opt=>$val}}<option value="{{$opt|escape:'html'}}" {{if $opt==$field.2}}selected="selected"{{/if}}>{{$val}}</option>{{/foreach}}
</select> </select>
<span class="help-block" id="{{$field.0}}_tip">{{$field.3}}</span> {{if $field.3}}
<span class="help-block" id="{{$field.0}}_tip" role="tooltip">{{$field.3}}</span>
{{/if}}
</div> </div>

View file

@ -4,5 +4,7 @@
<select class="form-control" name="{{$field.0}}" id="id_{{$field.0}}" aria-describedby="{{$field.0}}_tip"> <select class="form-control" name="{{$field.0}}" id="id_{{$field.0}}" aria-describedby="{{$field.0}}_tip">
{{$field.4}} {{$field.4}}
</select> </select>
<span class="help-block" id="{{$field.0}}_tip">{{$field.3}}</span> {{if $field.3}}
<span class="help-block" id="{{$field.0}}_tip" role="tooltip">{{$field.3}}</span>
{{/if}}
</div> </div>

View file

@ -2,6 +2,8 @@
<div class="form-group field textarea"> <div class="form-group field textarea">
<label for="id_{{$field.0}}">{{$field.1}}</label> <label for="id_{{$field.0}}">{{$field.1}}</label>
<textarea class="form-control text-autosize" name="{{$field.0}}" id="id_{{$field.0}}" {{if $field.4}}{{$field.4}}{{/if}} aria-describedby="{{$field.0}}_tip">{{$field.2}}</textarea> <textarea class="form-control text-autosize" name="{{$field.0}}" id="id_{{$field.0}}" {{if $field.4}}{{$field.4}}{{/if}} aria-describedby="{{$field.0}}_tip">{{$field.2}}</textarea>
<span id="{{$field.0}}_tip" class="help-block" role="tooltip">{{$field.3}}</span> {{if $field.3}}
<span class="help-block" id="{{$field.0}}_tip" role="tooltip">{{$field.3}}</span>
{{/if}}
<div class="clear"></div> <div class="clear"></div>
</div> </div>

View file

@ -5,6 +5,8 @@
<select class="form-control" name="{{$field.0}}" id="id_{{$field.0}}" {{if $field.5=="preview"}}onchange="previewTheme(this);"{{/if}} aria-describedby="{{$field.0}}_tip" > <select class="form-control" name="{{$field.0}}" id="id_{{$field.0}}" {{if $field.5=="preview"}}onchange="previewTheme(this);"{{/if}} aria-describedby="{{$field.0}}_tip" >
{{foreach $field.4 as $opt=>$val}}<option value="{{$opt}}" {{if $opt==$field.2}}selected="selected"{{/if}}>{{$val}}</option>{{/foreach}} {{foreach $field.4 as $opt=>$val}}<option value="{{$opt}}" {{if $opt==$field.2}}selected="selected"{{/if}}>{{$val}}</option>{{/foreach}}
</select> </select>
{{if $field.3}}
<span class="help-block" id="{{$field.0}}_tip" role="tooltip">{{$field.3}}</span> <span class="help-block" id="{{$field.0}}_tip" role="tooltip">{{$field.3}}</span>
{{/if}}
{{if $field.5=="preview"}}<div id="theme-preview"></div>{{/if}} {{if $field.5=="preview"}}<div id="theme-preview"></div>{{/if}}
</div> </div>

View file

@ -14,6 +14,8 @@
<span class="toggle-handle btn btn-default btn-xs"></span> <span class="toggle-handle btn btn-default btn-xs"></span>
</div> </div>
</div> </div>
{{if $field.3}}
<span class="help-block" id="{{$field.0}}_tip" role="tooltip">{{$field.3}}</span> <span class="help-block" id="{{$field.0}}_tip" role="tooltip">{{$field.3}}</span>
{{/if}}
</div> </div>
<div class="clear"></div> <div class="clear"></div>

View file

@ -8,6 +8,10 @@
<div id="login_standard"> <div id="login_standard">
{{include file="field_input.tpl" field=$lname}} {{include file="field_input.tpl" field=$lname}}
{{include file="field_password.tpl" field=$lpassword}} {{include file="field_password.tpl" field=$lpassword}}
<div id="login-lost-password-link">
<a href="lostpass" title="{{$lostpass|escape:'html'}}" id="lost-password-link" >{{$lostlink}}</a>
</div>
<div id="login-end"></div>
</div> </div>
{{if $openid}} {{if $openid}}
@ -19,10 +23,7 @@
{{include file="field_checkbox.tpl" field=$lremember}} {{include file="field_checkbox.tpl" field=$lremember}}
<div id="login-submit-wrapper"> <div id="login-submit-wrapper">
<a href="lostpass" title="{{$lostpass|escape:'html'}}" id="lost-password-link">{{$lostlink}}</a>
<div class="pull-right" > <div class="pull-right" >
{{if $register}}<a href="register" title="{{$register.title|escape:'html'}}" id="register-link" class="btn btn-default">{{$register.desc}}</a>{{/if}}
<button type="submit" name="submit" id="login-submit-button" class="btn btn-primary" value="{{$login|escape:'html'}}">{{$login|escape:'html'}}</button> <button type="submit" name="submit" id="login-submit-button" class="btn btn-primary" value="{{$login|escape:'html'}}">{{$login|escape:'html'}}</button>
</div> </div>
</div> </div>
@ -32,7 +33,15 @@
<input type="hidden" name="{{$k}}" value="{{$v|escape:'html'}}" /> <input type="hidden" name="{{$k}}" value="{{$v|escape:'html'}}" />
{{/foreach}} {{/foreach}}
<div id="login-end"></div>
</div> </div>
</form> </form>
{{if $register}}
<div id="login-extra-links">
<h3 id="login-head" class="sr-only">{{$register.title|escape:'html'}}</h3>
<a href="register" title="{{$register.title|escape:'html'}}" id="register-link" class="btn btn-default">{{$register.desc}}</a>
</div>
{{/if}}
<script type="text/javascript"> $(document).ready(function() { $("#id_{{$lname.0}}").focus();} );</script> <script type="text/javascript"> $(document).ready(function() { $("#id_{{$lname.0}}").focus();} );</script>

View file

@ -4,13 +4,13 @@
<script src="{{$baseurl}}/view/theme/frio/frameworks/jRange/jquery.range.js"></script> <script src="{{$baseurl}}/view/theme/frio/frameworks/jRange/jquery.range.js"></script>
<script type="text/javascript" src="{{$baseurl}}/view/js/ajaxupload.js" ></script> <script type="text/javascript" src="{{$baseurl}}/view/js/ajaxupload.js" ></script>
{{include file="field_select.tpl" field=$schema}} {{include file="field_select.tpl" field=$scheme}}
{{if $nav_bg}}{{include file="field_colorinput.tpl" field=$nav_bg}}{{/if}} {{if $nav_bg}}{{include file="field_colorinput.tpl" field=$nav_bg}}{{/if}}
{{if $nav_icon_color}}{{include file="field_colorinput.tpl" field=$nav_icon_color}}{{/if}} {{if $nav_icon_color}}{{include file="field_colorinput.tpl" field=$nav_icon_color}}{{/if}}
{{if $link_color}}{{include file="field_colorinput.tpl" field=$link_color}}{{/if}} {{if $link_color}}{{include file="field_colorinput.tpl" field=$link_color}}{{/if}}
{{if $bgcolor}}{{include file="field_colorinput.tpl" field=$bgcolor}}{{/if}} {{if $background_color}}{{include file="field_colorinput.tpl" field=$background_color}}{{/if}}
{{* The slider for the content opacity - We use no template for this since it is only used at this page *}} {{* The slider for the content opacity - We use no template for this since it is only used at this page *}}
{{if $contentbg_transp}} {{if $contentbg_transp}}
@ -25,6 +25,7 @@
{{if $background_image}}{{include file="field_fileinput.tpl" field=$background_image}}{{/if}} {{if $background_image}}{{include file="field_fileinput.tpl" field=$background_image}}{{/if}}
<div id="frio_bg_image_options" style="display: none;"> <div id="frio_bg_image_options" style="display: none;">
<label>{{$bg_image_options_title}}:</label>
{{foreach $bg_image_options as $options}} {{foreach $bg_image_options as $options}}
{{include file="field_radio.tpl" field=$options}} {{include file="field_radio.tpl" field=$options}}
{{/foreach}} {{/foreach}}

View file

@ -18,7 +18,7 @@ use Friendica\Core\System;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Model\Profile; use Friendica\Model\Profile;
$frio = "view/theme/frio"; $frio = 'view/theme/frio';
global $frio; global $frio;
@ -34,21 +34,21 @@ function frio_init(App $a)
$style = PConfig::get(local_user(), 'frio', 'style'); $style = PConfig::get(local_user(), 'frio', 'style');
$frio = "view/theme/frio"; $frio = 'view/theme/frio';
global $frio; global $frio;
// if the device is a mobile device set js is_mobile // if the device is a mobile device set js is_mobile
// variable so the js scripts can use this information // variable so the js scripts can use this information
if ($a->is_mobile || $a->is_tablet) { if ($a->is_mobile || $a->is_tablet) {
$a->page["htmlhead"] .= <<< EOT $a->page['htmlhead'] .= <<< EOT
<script type="text/javascript"> <script type="text/javascript">
var is_mobile = 1; var is_mobile = 1;
</script> </script>
EOT; EOT;
} }
if ($style == "") { if ($style == '') {
$style = Config::get('frio', 'style'); $style = Config::get('frio', 'style');
} }
} }
@ -62,7 +62,7 @@ function frio_install()
Addon::registerHook('acl_lookup_end', 'view/theme/frio/theme.php', 'frio_acl_lookup'); Addon::registerHook('acl_lookup_end', 'view/theme/frio/theme.php', 'frio_acl_lookup');
Addon::registerHook('display_item', 'view/theme/frio/theme.php', 'frio_display_item'); Addon::registerHook('display_item', 'view/theme/frio/theme.php', 'frio_display_item');
logger("installed theme frio"); logger('installed theme frio');
} }
function frio_uninstall() function frio_uninstall()
@ -74,7 +74,7 @@ function frio_uninstall()
Addon::unregisterHook('acl_lookup_end', 'view/theme/frio/theme.php', 'frio_acl_lookup'); Addon::unregisterHook('acl_lookup_end', 'view/theme/frio/theme.php', 'frio_acl_lookup');
Addon::unregisterHook('display_item', 'view/theme/frio/theme.php', 'frio_display_item'); Addon::unregisterHook('display_item', 'view/theme/frio/theme.php', 'frio_display_item');
logger("uninstalled theme frio"); logger('uninstalled theme frio');
} }
/** /**
@ -92,26 +92,26 @@ function frio_uninstall()
function frio_item_photo_links(App $a, &$body_info) function frio_item_photo_links(App $a, &$body_info)
{ {
$occurence = 0; $occurence = 0;
$p = Plaintext::getBoundariesPosition($body_info['html'], "<a", ">"); $p = Plaintext::getBoundariesPosition($body_info['html'], '<a', '>');
while ($p !== false && ($occurence++ < 500)) { while ($p !== false && ($occurence++ < 500)) {
$link = substr($body_info['html'], $p['start'], $p['end'] - $p['start']); $link = substr($body_info['html'], $p['start'], $p['end'] - $p['start']);
$matches = []; $matches = [];
preg_match("/\/photos\/[\w]+\/image\/([\w]+)/", $link, $matches); preg_match('/\/photos\/[\w]+\/image\/([\w]+)/', $link, $matches);
if ($matches) { if ($matches) {
// Replace the link for the photo's page with a direct link to the photo itself // Replace the link for the photo's page with a direct link to the photo itself
$newlink = str_replace($matches[0], "/photo/{$matches[1]}", $link); $newlink = str_replace($matches[0], "/photo/{$matches[1]}", $link);
// Add a "quiet" parameter to any redir links to prevent the "XX welcomes YY" info boxes // Add a "quiet" parameter to any redir links to prevent the "XX welcomes YY" info boxes
$newlink = preg_replace("/href=\"([^\"]+)\/redir\/([^\"]+)&url=([^\"]+)\"/", 'href="$1/redir/$2&quiet=1&url=$3"', $newlink); $newlink = preg_replace('/href="([^"]+)\/redir\/([^"]+)&url=([^"]+)"/', 'href="$1/redir/$2&quiet=1&url=$3"', $newlink);
// Having any arguments to the link for Colorbox causes it to fetch base64 code instead of the image // Having any arguments to the link for Colorbox causes it to fetch base64 code instead of the image
$newlink = preg_replace("/\/[?&]zrl=([^&\"]+)/", '', $newlink); $newlink = preg_replace('/\/[?&]zrl=([^&"]+)/', '', $newlink);
$body_info['html'] = str_replace($link, $newlink, $body_info['html']); $body_info['html'] = str_replace($link, $newlink, $body_info['html']);
} }
$p = Plaintext::getBoundariesPosition($body_info['html'], "<a", ">", $occurence); $p = Plaintext::getBoundariesPosition($body_info['html'], '<a', '>', $occurence);
} }
} }
@ -127,10 +127,10 @@ function frio_item_photo_links(App $a, &$body_info)
*/ */
function frio_item_photo_menu(App $a, &$arr) function frio_item_photo_menu(App $a, &$arr)
{ {
foreach ($arr["menu"] as $k => $v) { foreach ($arr['menu'] as $k => $v) {
if (strpos($v, 'poke/?f=&c=') === 0 || strpos($v, 'message/new/') === 0) { if (strpos($v, 'poke/?f=&c=') === 0 || strpos($v, 'message/new/') === 0) {
$v = "javascript:addToModal('" . $v . "'); return false;"; $v = 'javascript:addToModal(\'' . $v . '\'); return false;';
$arr["menu"][$k] = $v; $arr['menu'][$k] = $v;
} }
} }
} }
@ -149,9 +149,9 @@ function frio_item_photo_menu(App $a, &$arr)
*/ */
function frio_contact_photo_menu(App $a, &$args) function frio_contact_photo_menu(App $a, &$args)
{ {
$cid = $args["contact"]["id"]; $cid = $args['contact']['id'];
$pokelink = $args["menu"]["poke"][1]; $pokelink = $args['menu']['poke'][1];
$pmlink = $args["menu"]["pm"][1]; $pmlink = $args['menu']['pm'][1];
// Set the the indicator for opening the status, profile and photo pages // Set the the indicator for opening the status, profile and photo pages
// in a new tab to false if the contact a dfrn (friendica) contact // in a new tab to false if the contact a dfrn (friendica) contact
@ -160,12 +160,12 @@ function frio_contact_photo_menu(App $a, &$args)
// friendica servers as remote user or visitor // friendica servers as remote user or visitor
// //
// The value for opening in a new tab is e.g. when // The value for opening in a new tab is e.g. when
// $args["menu"]["status"][2] is true. If the value of the [2] key is true // $args['menu']['status'][2] is true. If the value of the [2] key is true
// and if it's a friendica contact we set it to false // and if it's a friendica contact we set it to false
foreach ($args["menu"] as $k => $v) { foreach ($args['menu'] as $k => $v) {
if ($k === "status" || $k === "profile" || $k === "photos") { if ($k === 'status' || $k === 'profile' || $k === 'photos') {
$v[2] = (($args["contact"]["network"] === "dfrn") ? false : true); $v[2] = (($args['contact']['network'] === 'dfrn') ? false : true);
$args["menu"][$k][2] = $v[2]; $args['menu'][$k][2] = $v[2];
} }
} }
@ -173,11 +173,11 @@ function frio_contact_photo_menu(App $a, &$args)
// Later we can make conditions in the corresponing templates (e.g. // Later we can make conditions in the corresponing templates (e.g.
// contact_template.tpl) // contact_template.tpl)
if (strpos($pokelink, 'poke/?f=&c=' . $cid) !== false) { if (strpos($pokelink, 'poke/?f=&c=' . $cid) !== false) {
$args["menu"]["poke"][3] = "modal"; $args['menu']['poke'][3] = 'modal';
} }
if (strpos($pmlink, 'message/new/' . $cid) !== false) { if (strpos($pmlink, 'message/new/' . $cid) !== false) {
$args["menu"]["pm"][3] = "modal"; $args['menu']['pm'][3] = 'modal';
} }
} }
@ -231,43 +231,43 @@ function frio_remote_nav($a, &$nav)
// user info // user info
$r = q("SELECT `micro` FROM `contact` WHERE `uid` = %d AND `self`", intval($a->user['uid'])); $r = q("SELECT `micro` FROM `contact` WHERE `uid` = %d AND `self`", intval($a->user['uid']));
$r[0]['photo'] = (DBM::is_result($r) ? $a->remove_baseurl($r[0]['micro']) : "images/person-48.jpg"); $r[0]['photo'] = (DBM::is_result($r) ? $a->remove_baseurl($r[0]['micro']) : 'images/person-48.jpg');
$r[0]['name'] = $a->user['username']; $r[0]['name'] = $a->user['username'];
} elseif (!local_user() && remote_user()) { } elseif (!local_user() && remote_user()) {
$r = q("SELECT `name`, `nick`, `micro` AS `photo` FROM `contact` WHERE `id` = %d", intval(remote_user())); $r = q("SELECT `name`, `nick`, `micro` AS `photo` FROM `contact` WHERE `id` = %d", intval(remote_user()));
$nav['remote'] = L10n::t("Guest"); $nav['remote'] = L10n::t('Guest');
} elseif (Profile::getMyURL()) { } elseif (Profile::getMyURL()) {
$r = q("SELECT `name`, `nick`, `photo` FROM `gcontact` $r = q("SELECT `name`, `nick`, `photo` FROM `gcontact`
WHERE `addr` = '%s' AND `network` = 'dfrn'", WHERE `addr` = '%s' AND `network` = 'dfrn'",
dbesc($webbie)); dbesc($webbie));
$nav['remote'] = L10n::t("Visitor"); $nav['remote'] = L10n::t('Visitor');
} else { } else {
$r = false; $r = false;
} }
if (DBM::is_result($r)) { if (DBM::is_result($r)) {
$nav['userinfo'] = [ $nav['userinfo'] = [
'icon' => (DBM::is_result($r) ? $r[0]['photo'] : "images/person-48.jpg"), 'icon' => (DBM::is_result($r) ? $r[0]['photo'] : 'images/person-48.jpg'),
'name' => $r[0]['name'], 'name' => $r[0]['name'],
]; ];
} }
if (!local_user() && !empty($server_url)) { if (!local_user() && !empty($server_url)) {
$nav['logout'] = [$server_url . '/logout', L10n::t('Logout'), "", L10n::t('End this session')]; $nav['logout'] = [$server_url . '/logout', L10n::t('Logout'), '', L10n::t('End this session')];
// user menu // user menu
$nav['usermenu'][] = [$server_url . '/profile/' . $a->user['nickname'], L10n::t('Status'), "", L10n::t('Your posts and conversations')]; $nav['usermenu'][] = [$server_url . '/profile/' . $a->user['nickname'], L10n::t('Status'), '', L10n::t('Your posts and conversations')];
$nav['usermenu'][] = [$server_url . '/profile/' . $a->user['nickname'] . '?tab=profile', L10n::t('Profile'), "", L10n::t('Your profile page')]; $nav['usermenu'][] = [$server_url . '/profile/' . $a->user['nickname'] . '?tab=profile', L10n::t('Profile'), '', L10n::t('Your profile page')];
$nav['usermenu'][] = [$server_url . '/photos/' . $a->user['nickname'], L10n::t('Photos'), "", L10n::t('Your photos')]; $nav['usermenu'][] = [$server_url . '/photos/' . $a->user['nickname'], L10n::t('Photos'), '', L10n::t('Your photos')];
$nav['usermenu'][] = [$server_url . '/videos/' . $a->user['nickname'], L10n::t('Videos'), "", L10n::t('Your videos')]; $nav['usermenu'][] = [$server_url . '/videos/' . $a->user['nickname'], L10n::t('Videos'), '', L10n::t('Your videos')];
$nav['usermenu'][] = [$server_url . '/events/', L10n::t('Events'), "", L10n::t('Your events')]; $nav['usermenu'][] = [$server_url . '/events/', L10n::t('Events'), '', L10n::t('Your events')];
// navbar links // navbar links
$nav['network'] = [$server_url . '/network', L10n::t('Network'), "", L10n::t('Conversations from your friends')]; $nav['network'] = [$server_url . '/network', L10n::t('Network'), '', L10n::t('Conversations from your friends')];
$nav['events'] = [$server_url . '/events', L10n::t('Events'), "", L10n::t('Events and Calendar')]; $nav['events'] = [$server_url . '/events', L10n::t('Events'), '', L10n::t('Events and Calendar')];
$nav['messages'] = [$server_url . '/message', L10n::t('Messages'), "", L10n::t('Private mail')]; $nav['messages'] = [$server_url . '/message', L10n::t('Messages'), '', L10n::t('Private mail')];
$nav['settings'] = [$server_url . '/settings', L10n::t('Settings'), "", L10n::t('Account settings')]; $nav['settings'] = [$server_url . '/settings', L10n::t('Settings'), '', L10n::t('Account settings')];
$nav['contacts'] = [$server_url . '/contacts', L10n::t('Contacts'), "", L10n::t('Manage/edit friends and contacts')]; $nav['contacts'] = [$server_url . '/contacts', L10n::t('Contacts'), '', L10n::t('Manage/edit friends and contacts')];
$nav['sitename'] = $a->config['sitename']; $nav['sitename'] = $a->config['sitename'];
} }
} }
@ -289,18 +289,18 @@ function frio_acl_lookup(App $a, &$results)
{ {
require_once 'mod/contacts.php'; require_once 'mod/contacts.php';
$nets = x($_GET, "nets") ? notags(trim($_GET["nets"])) : ""; $nets = x($_GET, 'nets') ? notags(trim($_GET['nets'])) : '';
// we introduce a new search type, r should do the same query like it's // we introduce a new search type, r should do the same query like it's
// done in /mod/contacts for connections // done in /mod/contacts for connections
if ($results["type"] !== "r") { if ($results['type'] !== 'r') {
return; return;
} }
$sql_extra = ''; $sql_extra = '';
if ($results["search"]) { if ($results['search']) {
$search_txt = dbesc(protect_sprintf(preg_quote($results["search"]))); $search_txt = dbesc(protect_sprintf(preg_quote($results['search'])));
$sql_extra .= " AND (`attag` LIKE '%%" . dbesc($search_txt) . "%%' OR `name` LIKE '%%" . dbesc($search_txt) . "%%' OR `nick` LIKE '%%" . dbesc($search_txt) . "%%' OR `addr` LIKE '%%" . dbesc($search_txt) . "%%') "; $sql_extra .= " AND (`attag` LIKE '%%" . dbesc($search_txt) . "%%' OR `name` LIKE '%%" . dbesc($search_txt) . "%%' OR `nick` LIKE '%%" . dbesc($search_txt) . "%%') ";
} }
if ($nets) { if ($nets) {
@ -311,7 +311,7 @@ function frio_acl_lookup(App $a, &$results)
$r = q("SELECT COUNT(*) AS `total` FROM `contact` $r = q("SELECT COUNT(*) AS `total` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `pending` $sql_extra ", intval($_SESSION['uid'])); WHERE `uid` = %d AND NOT `self` AND NOT `pending` $sql_extra ", intval($_SESSION['uid']));
if (DBM::is_result($r)) { if (DBM::is_result($r)) {
$total = $r[0]["total"]; $total = $r[0]['total'];
} }
$sql_extra3 = Widget::unavailableNetworks(); $sql_extra3 = Widget::unavailableNetworks();
@ -328,8 +328,8 @@ function frio_acl_lookup(App $a, &$results)
} }
} }
$results["items"] = $contacts; $results['items'] = $contacts;
$results["tot"] = $total; $results['tot'] = $total;
} }
/** /**

View file

@ -91,6 +91,13 @@ nav ul {
width: 100% !important; height: 110px !important; width: 100% !important; height: 110px !important;
} }
#login-extra-links, #login-form {
/* width: 341px; */
width: 100%;
}
#id_remember_label {
width: unset;
}
} }
@media screen and (max-width: 480px) { @media screen and (max-width: 480px) {

View file

@ -2422,10 +2422,60 @@ aside #div_id_remember label {
float: inherit; float: inherit;
} }
#login-group {
overflow: hidden;
}
#login-head {
position: unset;
width: unset;
height: unset;
margin-bottom: 10px;
}
div #wrapper_username {
padding: 0px;
}
div #wrapper_password {
padding: 0px;
margin-bottom: 0px;
}
#div_id_remember {
float: left;
width: unset;
}
#remember_tip {
display: none;
}
#login-submit-wrapper {
float: right;
}
#login-form {
margin-top: 20px;
}
#login-extra-links, #login-form {
/* width: 341px; */
width: 341px;
clear: both;
border-top: 3px solid white;
padding-top: 20px;
}
aside div #login-submit-button { aside div #login-submit-button {
margin-left:0px; margin-left:0px;
} }
#login-lost-password-link {
margin-bottom: 10px;
float: right;
}
aside #register-link, aside #lost-password-link { aside #register-link, aside #lost-password-link {
display: block; display: block;
} }