Add Install Mode

- merged `friendica/develop` to `nupplaPhil/install_mode`
- content merged `mod/install.php` to `src/Class/`
This commit is contained in:
Philipp Holzer 2018-04-28 15:11:01 +02:00
commit 1ab965c944
128 changed files with 34290 additions and 33303 deletions

3
.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
@ -57,4 +58,4 @@ venv/
/view/asset /view/asset
#ignore config files from JetBrains #ignore config files from JetBrains
/.idea /.idea

View file

@ -1,4 +1,10 @@
--- ---
language: php language: php
php: 5.6 ## Friendica supports PHP version >= 5.6
php:
- 5.6
- 7.0
- 7.1
- 7.2
install: composer install install: composer install

View file

@ -232,10 +232,11 @@ define('ACCOUNT_TYPE_RELAY', 4);
* Type of the community page * Type of the community page
* @{ * @{
*/ */
define('CP_NO_COMMUNITY_PAGE', -1); define('CP_NO_INTERNAL_COMMUNITY', -2);
define('CP_USERS_ON_SERVER', 0); define('CP_NO_COMMUNITY_PAGE', -1);
define('CP_GLOBAL_COMMUNITY', 1); define('CP_USERS_ON_SERVER', 0);
define('CP_USERS_AND_GLOBAL', 2); define('CP_GLOBAL_COMMUNITY', 1);
define('CP_USERS_AND_GLOBAL', 2);
/** /**
* @} * @}
*/ */
@ -1291,7 +1292,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

@ -16,19 +16,19 @@ If you'd like to have your own server, you can do that too.
Visit [the Friendica website](http://friendi.ca/) to download the code with setup instructions. Visit [the Friendica website](http://friendi.ca/) to download the code with setup instructions.
It's a very simple installation process that anybody experienced in hosting websites, or with basic Linux experience can handle easily. It's a very simple installation process that anybody experienced in hosting websites, or with basic Linux experience can handle easily.
###OpenID ### OpenID
The first field on the Registration page is for an OpenID address. The first field on the Registration page is for an OpenID address.
If you do not have an OpenID address or do not wish to use OpenID, leave this field blank. If you do not have an OpenID address or do not wish to use OpenID, leave this field blank.
If you have an OpenID account elsewhere and wish to use it, enter the address into this field and click 'Register'. If you have an OpenID account elsewhere and wish to use it, enter the address into this field and click 'Register'.
Friendica will attempt to extract as much information as possible from your OpenID provider and return to this page with those items already filled in. Friendica will attempt to extract as much information as possible from your OpenID provider and return to this page with those items already filled in.
###Your Full Name ### Your Full Name
Please provide your full name **as you would like it to be displayed on this system**. Please provide your full name **as you would like it to be displayed on this system**.
Most people use their real name for this, but you're under no obligation to do so yourself. Most people use their real name for this, but you're under no obligation to do so yourself.
###Email Address ### Email Address
Please provide a valid email address. Please provide a valid email address.
Your email address is **never** published. Your email address is **never** published.
@ -38,7 +38,7 @@ This doesn't have to be your primary email address, but it does need to be a rea
You can't get your initial password, or reset a lost password later without it. You can't get your initial password, or reset a lost password later without it.
This is the only bit of personal information that has to be accurate. This is the only bit of personal information that has to be accurate.
###Nickname ### Nickname
A nickname is used to generate web addresses for many of your personal pages, and is also treated like an email address when establishing communications with others. A nickname is used to generate web addresses for many of your personal pages, and is also treated like an email address when establishing communications with others.
Due to the way that the nickname is used, it has some limitations. Due to the way that the nickname is used, it has some limitations.
@ -47,7 +47,7 @@ It also must be unique on this system.
This is used in many places to identify your account, and once set it cannot be changed. This is used in many places to identify your account, and once set it cannot be changed.
###Directory Publishing ### Directory Publishing
The registration form also allows you to choose whether or not to list your account in the online directory of your node. The registration form also allows you to choose whether or not to list your account in the online directory of your node.
This is like a "phone book" and you may choose to be unlisted. This is like a "phone book" and you may choose to be unlisted.
@ -55,7 +55,7 @@ We recommend that you select 'Yes' so that other people (friends, family, etc.)
If you choose 'No', you will essentially be invisible and have few opportunities for interaction. If you choose 'No', you will essentially be invisible and have few opportunities for interaction.
Whichever you choose, this can be changed any time from your Settings page after you login. Whichever you choose, this can be changed any time from your Settings page after you login.
###Register ### Register
Once you have provided the necessary details, click the 'Register' button. Once you have provided the necessary details, click the 'Register' button.
An email will be sent to you providing your account login details. An email will be sent to you providing your account login details.

View file

@ -126,8 +126,8 @@ $b contains the $a->user array.
'display_item' is called when formatting a post for display. 'display_item' is called when formatting a post for display.
$b is an array: $b is an array:
'item' => The item (array) details pulled from the database 'item' => The item (array) details pulled from the database
'output' => the (string) HTML representation of this item prior to adding it to the page 'output' => the (string) HTML representation of this item prior to adding it to the page
### 'post_local' ### 'post_local'
* called when a status post or comment is entered on the local system * called when a status post or comment is entered on the local system
@ -167,8 +167,8 @@ $b is an array:
'profile_edit' is called prior to output of profile edit page. 'profile_edit' is called prior to output of profile edit page.
$b is an array containing: $b is an array containing:
'profile' => profile (array) record from the database 'profile' => profile (array) record from the database
'entry' => the (string) HTML of the generated entry 'entry' => the (string) HTML of the generated entry
### 'profile_advanced' ### 'profile_advanced'
* called when the HTML is generated for the 'Advanced profile', corresponding to the 'Profile' tab within a person's profile page * called when the HTML is generated for the 'Advanced profile', corresponding to the 'Profile' tab within a person's profile page
@ -179,7 +179,7 @@ $b is an array containing:
'directory_item' is called from the Directory page when formatting an item for display. 'directory_item' is called from the Directory page when formatting an item for display.
$b is an array: $b is an array:
'contact' => contact (array) record for the person from the database 'contact' => contact (array) record for the person from the database
'entry' => the (string) HTML of the generated entry 'entry' => the (string) HTML of the generated entry
### 'profile_sidebar_enter' ### 'profile_sidebar_enter'
@ -190,15 +190,15 @@ $b is an array:
'profile_sidebar is called when generating the sidebar "short" profile for a page. 'profile_sidebar is called when generating the sidebar "short" profile for a page.
$b is an array: $b is an array:
'profile' => profile (array) record for the person from the database 'profile' => profile (array) record for the person from the database
'entry' => the (string) HTML of the generated entry 'entry' => the (string) HTML of the generated entry
### 'contact_block_end' ### 'contact_block_end'
is called when formatting the block of contacts/friends on a profile sidebar has completed. is called when formatting the block of contacts/friends on a profile sidebar has completed.
$b is an array: $b is an array:
'contacts' => array of contacts 'contacts' => array of contacts
'output' => the (string) generated HTML of the contact block 'output' => the (string) generated HTML of the contact block
### 'bbcode' ### 'bbcode'
* called during conversion of bbcode to html * called during conversion of bbcode to html
@ -216,8 +216,8 @@ $b is an array:
'personal_xrd' is called prior to output of personal XRD file. 'personal_xrd' is called prior to output of personal XRD file.
$b is an array: $b is an array:
'user' => the user record for the person 'user' => the user record for the person
'xml' => the complete XML to be output 'xml' => the complete XML to be output
### 'home_content' ### 'home_content'
* called prior to output home page content, shown to unlogged users * called prior to output home page content, shown to unlogged users
@ -227,8 +227,8 @@ $b is an array:
is called when editing contact details on an individual from the Contacts page. is called when editing contact details on an individual from the Contacts page.
$b is an array: $b is an array:
'contact' => contact record (array) of target contact 'contact' => contact record (array) of target contact
'output' => the (string) generated HTML of the contact edit page 'output' => the (string) generated HTML of the contact edit page
### 'contact_edit_post' ### 'contact_edit_post'
* called when posting the contact edit page. * called when posting the contact edit page.
@ -246,9 +246,9 @@ $b is an array:
'avatar_lookup' is called when looking up the avatar. 'avatar_lookup' is called when looking up the avatar.
$b is an array: $b is an array:
'size' => the size of the avatar that will be looked up 'size' => the size of the avatar that will be looked up
'email' => email to look up the avatar for 'email' => email to look up the avatar for
'url' => the (string) generated URL of the avatar 'url' => the (string) generated URL of the avatar
### 'emailer_send_prepare' ### 'emailer_send_prepare'
'emailer_send_prepare' called from Emailer::send() before building the mime message. 'emailer_send_prepare' called from Emailer::send() before building the mime message.
@ -306,199 +306,315 @@ Hook data:
Called after the HTML conversion in prepare_body. Called after the HTML conversion in prepare_body.
Hook data: Hook data:
'item' => item array (input) 'item' => item array (input)
'html' => converted item body (input/output) 'html' => converted item body (input/output)
'is_preview' => post preview flag (input) 'is_preview' => post preview flag (input)
'filter_reasons' => reasons array (input) 'filter_reasons' => reasons array (input)
### 'prepare_body_final' ### 'prepare_body_final'
Called at the end of prepare_body. Called at the end of prepare_body.
Hook data: Hook data:
'item' => item array (input) 'item' => item array (input)
'html' => converted item body (input/output) 'html' => converted item body (input/output)
Complete list of hook callbacks Complete list of hook callbacks
--- ---
Here is a complete list of all hook callbacks with file locations (as of 01-Apr-2018). Please see the source for details of any hooks not documented above. Here is a complete list of all hook callbacks with file locations (as of 01-Apr-2018). Please see the source for details of any hooks not documented above.
index.php: Addon::callHooks('init_1'); ### index.php
index.php: Addon::callHooks('app_menu', $arr);
index.php: Addon::callHooks('page_content_top', $a->page['content']);
index.php: Addon::callHooks($a->module.'_mod_init', $placeholder);
index.php: Addon::callHooks($a->module.'_mod_init', $placeholder);
index.php: Addon::callHooks($a->module.'_mod_post', $_POST);
index.php: Addon::callHooks($a->module.'_mod_afterpost', $placeholder);
index.php: Addon::callHooks($a->module.'_mod_content', $arr);
index.php: Addon::callHooks($a->module.'_mod_aftercontent', $arr);
index.php: Addon::callHooks('page_end', $a->page['content']);
include/api.php: Addon::callHooks('logged_in', $a->user); Addon::callHooks('init_1');
include/api.php: Addon::callHooks('authenticate', $addon_auth); Addon::callHooks('app_menu', $arr);
include/api.php: Addon::callHooks('logged_in', $a->user); Addon::callHooks('page_content_top', $a->page['content']);
Addon::callHooks($a->module.'_mod_init', $placeholder);
Addon::callHooks($a->module.'_mod_init', $placeholder);
Addon::callHooks($a->module.'_mod_post', $_POST);
Addon::callHooks($a->module.'_mod_afterpost', $placeholder);
Addon::callHooks($a->module.'_mod_content', $arr);
Addon::callHooks($a->module.'_mod_aftercontent', $arr);
Addon::callHooks('page_end', $a->page['content']);
### include/api.php
include/enotify.php: Addon::callHooks('enotify', $h); Addon::callHooks('logged_in', $a->user);
include/enotify.php: Addon::callHooks('enotify_store', $datarray); Addon::callHooks('authenticate', $addon_auth);
include/enotify.php: Addon::callHooks('enotify_mail', $datarray); Addon::callHooks('logged_in', $a->user);
include/enotify.php: Addon::callHooks('check_item_notification', $notification_data);
include/conversation.php: Addon::callHooks('conversation_start', $cb); ### include/enotify.php
include/conversation.php: Addon::callHooks('render_location', $locate);
include/conversation.php: Addon::callHooks('display_item', $arr); Addon::callHooks('enotify', $h);
include/conversation.php: Addon::callHooks('display_item', $arr); Addon::callHooks('enotify_store', $datarray);
include/conversation.php: Addon::callHooks('item_photo_menu', $args); Addon::callHooks('enotify_mail', $datarray);
include/conversation.php: Addon::callHooks('jot_tool', $jotplugins); Addon::callHooks('check_item_notification', $notification_data);
### include/conversation.php
include/security.php: Addon::callHooks('logged_in', $a->user); Addon::callHooks('conversation_start', $cb);
Addon::callHooks('render_location', $locate);
Addon::callHooks('display_item', $arr);
Addon::callHooks('display_item', $arr);
Addon::callHooks('item_photo_menu', $args);
Addon::callHooks('jot_tool', $jotplugins);
include/text.php: Addon::callHooks('contact_block_end', $arr); ### include/security.php
include/text.php: Addon::callHooks('poke_verbs', $arr);
include/text.php: Addon::callHooks('prepare_body_init', $item);
include/text.php: Addon::callHooks('prepare_body_content_filter', $hook_data);
include/text.php: Addon::callHooks('prepare_body', $hook_data);
include/text.php: Addon::callHooks('prepare_body_final', $hook_data);
include/items.php: Addon::callHooks('page_info_data', $data); Addon::callHooks('logged_in', $a->user);
mod/directory.php: Addon::callHooks('directory_item', $arr); ### include/text.php
mod/xrd.php: Addon::callHooks('personal_xrd', $arr); Addon::callHooks('contact_block_end', $arr);
Addon::callHooks('poke_verbs', $arr);
Addon::callHooks('prepare_body_init', $item);
Addon::callHooks('prepare_body_content_filter', $hook_data);
Addon::callHooks('prepare_body', $hook_data);
Addon::callHooks('prepare_body_final', $hook_data);
mod/ping.php: Addon::callHooks('network_ping', $arr); ### include/items.php
mod/parse_url.php: Addon::callHooks("parse_link", $arr); Addon::callHooks('page_info_data', $data);
mod/manage.php: Addon::callHooks('home_init', $ret); ### mod/directory.php
mod/acl.php: Addon::callHooks('acl_lookup_end', $results); Addon::callHooks('directory_item', $arr);
mod/network.php: Addon::callHooks('network_content_init', $arr); ### mod/xrd.php
mod/network.php: Addon::callHooks('network_tabs', $arr);
mod/friendica.php: Addon::callHooks('about_hook', $o); Addon::callHooks('personal_xrd', $arr);
mod/subthread.php: Addon::callHooks('post_local_end', $arr);
mod/profiles.php: Addon::callHooks('profile_post', $_POST); ### mod/ping.php
mod/profiles.php: Addon::callHooks('profile_edit', $arr);
mod/settings.php: Addon::callHooks('addon_settings_post', $_POST); Addon::callHooks('network_ping', $arr);
mod/settings.php: Addon::callHooks('connector_settings_post', $_POST);
mod/settings.php: Addon::callHooks('display_settings_post', $_POST);
mod/settings.php: Addon::callHooks('settings_post', $_POST);
mod/settings.php: Addon::callHooks('addon_settings', $settings_addons);
mod/settings.php: Addon::callHooks('connector_settings', $settings_connectors);
mod/settings.php: Addon::callHooks('display_settings', $o);
mod/settings.php: Addon::callHooks('settings_form', $o);
mod/photos.php: Addon::callHooks('photo_post_init', $_POST); ### mod/parse_url.php
mod/photos.php: Addon::callHooks('photo_post_file', $ret);
mod/photos.php: Addon::callHooks('photo_post_end', $foo);
mod/photos.php: Addon::callHooks('photo_post_end', $foo);
mod/photos.php: Addon::callHooks('photo_post_end', $foo);
mod/photos.php: Addon::callHooks('photo_post_end', $foo);
mod/photos.php: Addon::callHooks('photo_post_end', intval($item_id));
mod/photos.php: Addon::callHooks('photo_upload_form', $ret);
mod/profile.php: Addon::callHooks('profile_advanced', $o); Addon::callHooks("parse_link", $arr);
mod/home.php: Addon::callHooks('home_init', $ret); ### mod/manage.php
mod/home.php: Addon::callHooks("home_content", $content);
mod/poke.php: Addon::callHooks('post_local_end', $arr); Addon::callHooks('home_init', $ret);
mod/contacts.php: Addon::callHooks('contact_edit_post', $_POST); ### mod/acl.php
mod/contacts.php: Addon::callHooks('contact_edit', $arr);
mod/tagger.php: Addon::callHooks('post_local_end', $arr); Addon::callHooks('acl_lookup_end', $results);
mod/lockview.php: Addon::callHooks('lockview_content', $item); ### mod/network.php
mod/uexport.php: Addon::callHooks('uexport_options', $options); Addon::callHooks('network_content_init', $arr);
Addon::callHooks('network_tabs', $arr);
mod/register.php: Addon::callHooks('register_post', $arr); ### mod/friendica.php
mod/register.php: Addon::callHooks('register_form', $arr);
mod/item.php: Addon::callHooks('post_local_start', $_REQUEST); Addon::callHooks('about_hook', $o);
mod/item.php: Addon::callHooks('post_local', $datarray);
mod/item.php: Addon::callHooks('post_local_end', $datarray); ### mod/subthread.php
mod/editpost.php: Addon::callHooks('jot_tool', $jotplugins); Addon::callHooks('post_local_end', $arr);
src/Network/FKOAuth1.php: Addon::callHooks('logged_in', $a->user); ### mod/profiles.php
src/Render/FriendicaSmartyEngine.php: Addon::callHooks("template_vars", $arr); Addon::callHooks('profile_post', $_POST);
Addon::callHooks('profile_edit', $arr);
src/Model/Item.php: Addon::callHooks('post_local', $item); ### mod/settings.php
src/Model/Item.php: Addon::callHooks('post_remote', $item);
src/Model/Item.php: Addon::callHooks('post_local_end', $posted_item);
src/Model/Item.php: Addon::callHooks('post_remote_end', $posted_item);
src/Model/Item.php: Addon::callHooks('tagged', $arr);
src/Model/Item.php: Addon::callHooks('post_local_end', $new_item);
src/Model/Contact.php: Addon::callHooks('contact_photo_menu', $args); Addon::callHooks('addon_settings_post', $_POST);
src/Model/Contact.php: Addon::callHooks('follow', $arr); Addon::callHooks('connector_settings_post', $_POST);
Addon::callHooks('display_settings_post', $_POST);
Addon::callHooks('settings_post', $_POST);
Addon::callHooks('addon_settings', $settings_addons);
Addon::callHooks('connector_settings', $settings_connectors);
Addon::callHooks('display_settings', $o);
Addon::callHooks('settings_form', $o);
src/Model/Profile.php: Addon::callHooks('profile_sidebar_enter', $profile); ### mod/photos.php
src/Model/Profile.php: Addon::callHooks('profile_sidebar', $arr);
src/Model/Profile.php: Addon::callHooks('profile_tabs', $arr);
src/Model/Profile.php: Addon::callHooks('zrl_init', $arr);
src/Model/Event.php: Addon::callHooks('event_updated', $event['id']); Addon::callHooks('photo_post_init', $_POST);
src/Model/Event.php: Addon::callHooks("event_created", $event['id']); Addon::callHooks('photo_post_file', $ret);
Addon::callHooks('photo_post_end', $foo);
Addon::callHooks('photo_post_end', $foo);
Addon::callHooks('photo_post_end', $foo);
Addon::callHooks('photo_post_end', $foo);
Addon::callHooks('photo_post_end', intval($item_id));
Addon::callHooks('photo_upload_form', $ret);
src/Model/User.php: Addon::callHooks('register_account', $uid); ### mod/profile.php
src/Model/User.php: Addon::callHooks('remove_user', $user);
src/Content/Text/BBCode.php: Addon::callHooks('bbcode', $text); Addon::callHooks('profile_advanced', $o);
src/Content/Text/BBCode.php: Addon::callHooks('bb2diaspora', $text);
src/Content/Text/HTML.php: Addon::callHooks('html2bbcode', $message); ### mod/home.php
src/Content/Smilies.php: Addon::callHooks('smilie', $params); Addon::callHooks('home_init', $ret);
Addon::callHooks("home_content", $content);
src/Content/Feature.php: Addon::callHooks('isEnabled', $arr); ### mod/poke.php
src/Content/Feature.php: Addon::callHooks('get', $arr);
src/Content/ContactSelector.php: Addon::callHooks('network_to_name', $nets); Addon::callHooks('post_local_end', $arr);
src/Content/ContactSelector.php: Addon::callHooks('gender_selector', $select);
src/Content/ContactSelector.php: Addon::callHooks('sexpref_selector', $select);
src/Content/ContactSelector.php: Addon::callHooks('marital_selector', $select);
src/Content/OEmbed.php: Addon::callHooks('oembed_fetch_url', $embedurl, $j); ### mod/contacts.php
src/Content/Nav.php: Addon::callHooks('page_header', $a->page['nav']); Addon::callHooks('contact_edit_post', $_POST);
src/Content/Nav.php: Addon::callHooks('nav_info', $nav); Addon::callHooks('contact_edit', $arr);
src/Worker/Directory.php: Addon::callHooks('globaldir_update', $arr); ### mod/tagger.php
src/Worker/Notifier.php: Addon::callHooks('notifier_end', $target_item);
src/Worker/Queue.php: Addon::callHooks('queue_predeliver', $r);
src/Worker/Queue.php: Addon::callHooks('queue_deliver', $params);
src/Module/Login.php: Addon::callHooks('authenticate', $addon_auth); Addon::callHooks('post_local_end', $arr);
src/Module/Login.php: Addon::callHooks('login_hook', $o);
src/Module/Logout.php: Addon::callHooks("logging_out");
src/Object/Post.php: Addon::callHooks('render_location', $locate); ### mod/lockview.php
src/Object/Post.php: Addon::callHooks('display_item', $arr);
src/Core/ACL.php: Addon::callHooks('contact_select_options', $x); Addon::callHooks('lockview_content', $item);
src/Core/ACL.php: Addon::callHooks($a->module.'_pre_'.$selname, $arr);
src/Core/ACL.php: Addon::callHooks($a->module.'_post_'.$selname, $o);
src/Core/ACL.php: Addon::callHooks($a->module.'_pre_'.$selname, $arr);
src/Core/ACL.php: Addon::callHooks($a->module.'_post_'.$selname, $o);
src/Core/ACL.php: Addon::callHooks('jot_networks', $jotnets);
src/Core/Worker.php: Addon::callHooks("proc_run", $arr); ### mod/uexport.php
src/Util/Emailer.php: Addon::callHooks('emailer_send_prepare', $params); Addon::callHooks('uexport_options', $options);
src/Util/Emailer.php: Addon::callHooks("emailer_send", $hookdata);
src/Util/Map.php: Addon::callHooks('generate_map', $arr); ### mod/register.php
src/Util/Map.php: Addon::callHooks('generate_named_map', $arr);
src/Util/Map.php: Addon::callHooks('Map::getCoordinates', $arr);
src/Util/Network.php: Addon::callHooks('avatar_lookup', $avatar); Addon::callHooks('register_post', $arr);
Addon::callHooks('register_form', $arr);
src/Util/ParseUrl.php: Addon::callHooks("getsiteinfo", $siteinfo); ### mod/item.php
src/Protocol/DFRN.php: Addon::callHooks('atom_feed_end', $atom); Addon::callHooks('post_local_start', $_REQUEST);
src/Protocol/DFRN.php: Addon::callHooks('atom_feed_end', $atom); Addon::callHooks('post_local', $datarray);
Addon::callHooks('post_local_end', $datarray);
### mod/editpost.php
Addon::callHooks('jot_tool', $jotplugins);
### src/Network/FKOAuth1.php
Addon::callHooks('logged_in', $a->user);
### src/Render/FriendicaSmartyEngine.php
Addon::callHooks("template_vars", $arr);
### src/Model/Item.php
Addon::callHooks('post_local', $item);
Addon::callHooks('post_remote', $item);
Addon::callHooks('post_local_end', $posted_item);
Addon::callHooks('post_remote_end', $posted_item);
Addon::callHooks('tagged', $arr);
Addon::callHooks('post_local_end', $new_item);
### src/Model/Contact.php
Addon::callHooks('contact_photo_menu', $args);
Addon::callHooks('follow', $arr);
### src/Model/Profile.php
Addon::callHooks('profile_sidebar_enter', $profile);
Addon::callHooks('profile_sidebar', $arr);
Addon::callHooks('profile_tabs', $arr);
Addon::callHooks('zrl_init', $arr);
### src/Model/Event.php
Addon::callHooks('event_updated', $event['id']);
Addon::callHooks("event_created", $event['id']);
### src/Model/User.php
Addon::callHooks('register_account', $uid);
Addon::callHooks('remove_user', $user);
### src/Content/Text/BBCode.php
Addon::callHooks('bbcode', $text);
Addon::callHooks('bb2diaspora', $text);
### src/Content/Text/HTML.php
Addon::callHooks('html2bbcode', $message);
### src/Content/Smilies.php
Addon::callHooks('smilie', $params);
### src/Content/Feature.php
Addon::callHooks('isEnabled', $arr);
Addon::callHooks('get', $arr);
### src/Content/ContactSelector.php
Addon::callHooks('network_to_name', $nets);
Addon::callHooks('gender_selector', $select);
Addon::callHooks('sexpref_selector', $select);
Addon::callHooks('marital_selector', $select);
### src/Content/OEmbed.php
Addon::callHooks('oembed_fetch_url', $embedurl, $j);
### src/Content/Nav.php
Addon::callHooks('page_header', $a->page['nav']);
Addon::callHooks('nav_info', $nav);
### src/Worker/Directory.php
Addon::callHooks('globaldir_update', $arr);
### src/Worker/Notifier.php
Addon::callHooks('notifier_end', $target_item);
### src/Worker/Queue.php
Addon::callHooks('queue_predeliver', $r);
Addon::callHooks('queue_deliver', $params);
### src/Module/Login.php
Addon::callHooks('authenticate', $addon_auth);
Addon::callHooks('login_hook', $o);
### src/Module/Logout.php
Addon::callHooks("logging_out");
### src/Object/Post.php
Addon::callHooks('render_location', $locate);
Addon::callHooks('display_item', $arr);
### src/Core/ACL.php
Addon::callHooks('contact_select_options', $x);
Addon::callHooks($a->module.'_pre_'.$selname, $arr);
Addon::callHooks($a->module.'_post_'.$selname, $o);
Addon::callHooks($a->module.'_pre_'.$selname, $arr);
Addon::callHooks($a->module.'_post_'.$selname, $o);
Addon::callHooks('jot_networks', $jotnets);
### src/Core/Worker.php
Addon::callHooks("proc_run", $arr);
### src/Util/Emailer.php
Addon::callHooks('emailer_send_prepare', $params);
Addon::callHooks("emailer_send", $hookdata);
### src/Util/Map.php
Addon::callHooks('generate_map', $arr);
Addon::callHooks('generate_named_map', $arr);
Addon::callHooks('Map::getCoordinates', $arr);
### src/Util/Network.php
Addon::callHooks('avatar_lookup', $avatar);
### src/Util/ParseUrl.php
Addon::callHooks("getsiteinfo", $siteinfo);
### src/Protocol/DFRN.php
Addon::callHooks('atom_feed_end', $atom);
Addon::callHooks('atom_feed_end', $atom);

View file

@ -37,7 +37,7 @@ You can use several servers to create an account:
* [https://jappix.com](https://jappix.com) * [https://jappix.com](https://jappix.com)
* [http://xmpp.net](http://xmpp.net) * [http://xmpp.net](http://xmpp.net)
###1. Basics ### 1. Basics
At first you have to get the current version. You can either pull it from [Github](https://github.com) like so: At first you have to get the current version. You can either pull it from [Github](https://github.com) like so:
@ -54,7 +54,7 @@ The following page shows the settings of this addon.
Activate the BOSH proxy. Activate the BOSH proxy.
###2. Settings ### 2. Settings
Go to your user account settings next and choose the addon page. Go to your user account settings next and choose the addon page.
Scroll down until you find the Jappix Mini addon settings. Scroll down until you find the Jappix Mini addon settings.

View file

@ -29,7 +29,7 @@ Active the following addons:
rendertime rendertime
###rendertime ### rendertime
This addon doesn't speed up your system. This addon doesn't speed up your system.
It helps to analyze your bottlenecks. It helps to analyze your bottlenecks.
@ -52,7 +52,7 @@ Apache Webserver
The following Apache modules are recommended: The following Apache modules are recommended:
###Cache-Control ### Cache-Control
This module tells the client to cache the content of static files so that they aren't fetched with every request. This module tells the client to cache the content of static files so that they aren't fetched with every request.
Enable the module "mod_expires" by typing in "a2enmod expires" as root. Enable the module "mod_expires" by typing in "a2enmod expires" as root.
@ -62,7 +62,7 @@ Please add the following lines to your site configuration in the "directory" con
Also see the Apache [2.2](http://httpd.apache.org/docs/2.2/mod/mod_expires.html) / [2.4](https://httpd.apache.org/docs/2.4/mod/mod_expires.html) documentation. Also see the Apache [2.2](http://httpd.apache.org/docs/2.2/mod/mod_expires.html) / [2.4](https://httpd.apache.org/docs/2.4/mod/mod_expires.html) documentation.
###Compress content ### Compress content
This module compresses the traffic between the web server and the client. This module compresses the traffic between the web server and the client.
Enable the module "mod_deflate" by typing in "a2enmod deflate" as root. Enable the module "mod_deflate" by typing in "a2enmod deflate" as root.
@ -72,14 +72,14 @@ Also see the Apache [2.2](http://httpd.apache.org/docs/2.2/mod/mod_deflate.html)
PHP PHP
-------- --------
###FCGI ### FCGI
When using Apache think about using FCGI. When using Apache think about using FCGI.
In a Debian-based distribution you will need to install the packages named "php5-cgi" and "libapache2-mod-fcgid". In a Debian-based distribution you will need to install the packages named "php5-cgi" and "libapache2-mod-fcgid".
Please refer to external documentation for a more detailed explanation how to set up a system based upon FCGI. Please refer to external documentation for a more detailed explanation how to set up a system based upon FCGI.
###Database ### Database
There are scripts like [tuning-primer.sh](http://www.day32.com/MySQL/) and [mysqltuner.pl](http://mysqltuner.pl) that analyze your database server and give hints on values that could be changed. There are scripts like [tuning-primer.sh](http://www.day32.com/MySQL/) and [mysqltuner.pl](http://mysqltuner.pl) that analyze your database server and give hints on values that could be changed.

View file

@ -2,6 +2,7 @@ Friendica Installation
=============== ===============
We've tried very hard to ensure that Friendica will run on commodity hosting platforms - such as those used to host Wordpress blogs and Drupal websites. We've tried very hard to ensure that Friendica will run on commodity hosting platforms - such as those used to host Wordpress blogs and Drupal websites.
We offer a manual and an automatic installation.
But be aware that Friendica is more than a simple web application. But be aware that Friendica is more than a simple web application.
It is a complex communications system which more closely resembles an email server than a web server. It is a complex communications system which more closely resembles an email server than a web server.
For reliability and performance, messages are delivered in the background and are queued for later delivery when sites are down. For reliability and performance, messages are delivered in the background and are queued for later delivery when sites are down.
@ -27,10 +28,10 @@ Requirements
* Apache with mod-rewrite enabled and "Options All" so you can use a local .htaccess file * Apache with mod-rewrite enabled and "Options All" so you can use a local .htaccess file
* PHP 5.6+ (PHP 7 is recommended for performance) * PHP 5.6+ (PHP 7 is recommended for performance)
* PHP *command line* access with register_argc_argv set to true in the php.ini file * PHP *command line* access with register_argc_argv set to true in the php.ini file
* Curl, GD, PDO, MySQLi, hash, xml, zip and OpenSSL extensions * Curl, GD, PDO, MySQLi, hash, xml, zip and OpenSSL extensions
* The POSIX module of PHP needs to be activated (e.g. [RHEL, CentOS](http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7) have disabled it) * The POSIX module of PHP needs to be activated (e.g. [RHEL, CentOS](http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7) have disabled it)
* some form of email server or email gateway such that PHP mail() works * some form of email server or email gateway such that PHP mail() works
* Mysql 5.5.3+ or an equivalant alternative for MySQL (MariaDB, Percona Server etc.) * Mysql 5.5.3+ or an equivalant alternative for MySQL (MariaDB, Percona Server etc.)
* the ability to schedule jobs with cron (Linux/Mac) or Scheduled Tasks (Windows) (Note: other options are presented in Section 7 of this document.) * the ability to schedule jobs with cron (Linux/Mac) or Scheduled Tasks (Windows) (Note: other options are presented in Section 7 of this document.)
* Installation into a top-level domain or sub-domain (without a directory/path component in the URL) is preferred. Directory paths will not be as convenient to use and have not been thoroughly tested. * Installation into a top-level domain or sub-domain (without a directory/path component in the URL) is preferred. Directory paths will not be as convenient to use and have not been thoroughly tested.
@ -79,24 +80,49 @@ In this case find the [mysqld] section in your my.cnf file and add the line :
Restart mysql and you should be fine. Restart mysql and you should be fine.
### Option A: Run the manual installer
### Run the installer
Point your web browser to the new site and follow the instructions. Point your web browser to the new site and follow the instructions.
Please note any error messages and correct these before continuing. Please note any error messages and correct these before continuing.
If you need to specify a port for the connection to the database, you can do so in the host name setting for the database. If you need to specify a port for the connection to the database, you can do so in the host name setting for the database.
*If* the automated installation fails for any reason, check the following: *If* the manual installation fails for any reason, check the following:
* Does ".htconfig.php" exist? If not, edit htconfig.php and change the system settings. Rename to .htconfig.php * Does ".htconfig.php" exist? If not, edit htconfig.php and change the system settings. Rename to .htconfig.php
* Is the database is populated? If not, import the contents of "database.sql" with phpmyadmin or mysql command line. * Is the database is populated? If not, import the contents of "database.sql" with phpmyadmin or the mysql command line.
At this point visit your website again, and register your personal account. At this point visit your website again, and register your personal account.
Registration errors should all be recoverable automatically. Registration errors should all be recoverable automatically.
If you get any *critical* failure at this point, it generally indicates the database was not installed correctly. If you get any *critical* failure at this point, it generally indicates the database was not installed correctly.
You might wish to move/rename .htconfig.php to another name and empty (called 'dropping') the database tables, so that you can start fresh. You might wish to move/rename .htconfig.php to another name and empty (called 'dropping') the database tables, so that you can start fresh.
### Option B: Run the automatic install script
Open the file htconfig.php in the main Friendica directory with a text editor.
Remove the `die('...');` line and edit the lines to suit your installation (MySQL, language, theme etc.).
Then save the file (do not rename it).
Navigate to the main Friendica directory and execute the following command:
bin/console autoinstall
Or if you wish to include all optional checks, execute this statement instead:
bin/console autoinstall -a
At this point visit your website again, and register your personal account.
*If* the automatic installation fails for any reason, check the following:
* Does ".htconfig.php" already exist? If yes, the automatic installation won't start
* Are the settings inside "htconfig.php" correct? If not, edit the file again.
* Is the empty MySQL-database created? If not, create it.
For more information during the installation, you can use this command line option
bin/console autoinstall -v
### Set up the worker ### Set up the worker
Set up a cron job or scheduled task to run the worker once every 5-10 minutes in order to perform background processing. Set up a cron job or scheduled task to run the worker once every 5-10 minutes in order to perform background processing.

View file

@ -32,7 +32,7 @@ Twitter Addon for Friendica
* tobias.diekershoff@gmx.net * tobias.diekershoff@gmx.net
* License: 3-clause BSD license * License: 3-clause BSD license
###Configuration ### Configuration
To use this addon you need a OAuth Consumer key pair (key & secret). To use this addon you need a OAuth Consumer key pair (key & secret).
You can get it from [Twitter](https://twitter.com/apps). You can get it from [Twitter](https://twitter.com/apps).
@ -46,7 +46,7 @@ Add this key pair to your global .htconfig.php:
After this, your users can configure their Twitter account settings from "Settings -> Connector Settings". After this, your users can configure their Twitter account settings from "Settings -> Connector Settings".
###More documentation ### More documentation
Find the author's documentation here: [http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/Twitter_Plugin](http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/Twitter_Plugin) Find the author's documentation here: [http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/Twitter_Plugin](http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/Twitter_Plugin)
@ -58,7 +58,7 @@ GNU Social Addon for Friendica
* tobias.diekershoff@gmx.net * tobias.diekershoff@gmx.net
* License: 3-clause BSD license * License: 3-clause BSD license
###Configuration ### Configuration
When the addon is activated the user has to acquire the following in order to connect to the GNU Social account of choice. When the addon is activated the user has to acquire the following in order to connect to the GNU Social account of choice.

View file

@ -50,7 +50,7 @@ This will take you through a similar process.
Connect to users of alternate networks Connect to users of alternate networks
--- ---
###Across the Federation and Fedivese ### Across the Federation and Fedivese
You can also use your Identity Address or other people's Identity Addresses to become friends across the so-called Federation/Fedivese of open source social media. You can also use your Identity Address or other people's Identity Addresses to become friends across the so-called Federation/Fedivese of open source social media.
Currently, Friendica supports connections with people on diaspora*, Red, Hubzilla, GNU Social, StatusNet, Mastodon, Pleroma, socialhome, and ganggo platforms. Currently, Friendica supports connections with people on diaspora*, Red, Hubzilla, GNU Social, StatusNet, Mastodon, Pleroma, socialhome, and ganggo platforms.
@ -60,13 +60,13 @@ Note: Some versions of GNU Social software may require the full URL to your prof
People on these networks can also initiate contact with you, if they know your contact details. People on these networks can also initiate contact with you, if they know your contact details.
###Other social media ### Other social media
If you server provides this functionality, you can also connect with people one If you server provides this functionality, you can also connect with people one
Twitter or important feeds from Tumblr, Wordpress, and many more. Twitter or important feeds from Tumblr, Wordpress, and many more.
To connect, enter their contact details in the "connect" box on your "Contacts" page. To connect, enter their contact details in the "connect" box on your "Contacts" page.
###Email ### Email
If you have supplied your mailbox connection information on your Settings page, you can enter the email address of anybody that has sent you a message recently and have their email messages show up in your social stream. If you have supplied your mailbox connection information on your Settings page, you can enter the email address of anybody that has sent you a message recently and have their email messages show up in your social stream.
You can also reply to them from within Friendica. You can also reply to them from within Friendica.
@ -76,7 +76,7 @@ In order to avoid abuse or spam, you must have an email from Alice with the corr
Subscribing to mailing lists is done in the same way, but without the use of the "mailto:" prefix. Subscribing to mailing lists is done in the same way, but without the use of the "mailto:" prefix.
To subscribe to a mailing list, enter the email in following example format "mailling-list@list-server.net". To subscribe to a mailing list, enter the email in following example format "mailling-list@list-server.net".
###Syndication feeds ### Syndication feeds
You can "follow" almost anybody or any website that produces a syndication feed (RSS/Atom,etc.). You can "follow" almost anybody or any website that produces a syndication feed (RSS/Atom,etc.).
If we can find an information stream and a name to attach to the contact, we'll try to connect with them. If we can find an information stream and a name to attach to the contact, we'll try to connect with them.

View file

@ -4,35 +4,32 @@ Profiles
* [Home](help) * [Home](help)
Friendica has unlimited profiles. Friendica has unlimited profiles.
You may use different profiles to show different "sides of yourself" to different audiences. You may use different profiles to present different aspects of yourself to different audiences.
Default / public profile Default / public profile
--- ---
You always have a profile known as your "default" or "public" profile. You always have a profile known as your "default" or "public" profile.
This profile is always available to the general public and cannot be hidden (there may be rare exceptions on privately run or disconnected sites). This profile is always available to the general public and usually cannot be hidden.
You may, and probably should restrict the information you make available on your public profile. You may, and probably should restrict the personal information you make available on your public profile.
That said, if you want other friends to be able to find you, it helps to have the following information in your public profile: That said, if you want other friends to be able to find you, it helps to have the following information in your public profile:
* Your real name * Your real name
* A photo of **you** * A photo of **you**
* Your location on the planet, at least to a country level. * Your location, preferably at least the country.
Without this basic information, you could get very lonely here. In addition, if you'd like to meet people that share some general interests with you, add some "Public Keywords" to your profile.
Most people (even your best friends) will not try and connect with somebody that has a fake name or doesn't contain a real photo.
In addition, if you'd like to meet people that share some general interests with you, please take a moment and add some "Public Keywords" to your profile.
Such as "music, linux, photography" or whatever. Such as "music, linux, photography" or whatever.
You can add as many keywords as you like. You can add as many keywords as you like.
Your default or public profile is also shown to contacts on other networks, since they do not have the ability to view your private profiles. Your default or public profile is also shown to contacts on other networks, since they do not have the ability to view your private profiles.
Only members of the Friendica network can see alternate/private profiles. Only members of the Friendica network can see alternate/ private profiles.
Alternate profiles Alternate/ private profiles
--- ---
To create an alternate profile, select "Profiles" from the menu of your Friendica site. To create an alternate profile, select "Profiles" from the menu of your Friendica site.
You may edit an existing profile, change the profile photo, or create a new profile. You may edit an existing profile, change the profile photo, or create a new profile.
You may also create a "clone" of an existing profile if you only wish to change a few items but don't wish to enter all the information again. You may also "clone" your existing profile if you only wish to change a few items but don't wish to enter all the information again.
To assign a profile to specific persons, select the person from your "Contacts" page and click the pencil "Edit" icon. To assign a profile to specific persons, select the person from your "Contacts" page and click the pencil "Edit" icon.
You will find a dropdown box listing the various profiles available. You will find a dropdown box listing the various profiles available.
@ -51,17 +48,13 @@ You may also be able to comment directly on posts from while visiting the other
There are two settings which allow you to publish your profile to a directory and ensure that it can be found by others. There are two settings which allow you to publish your profile to a directory and ensure that it can be found by others.
You can change these through settings on the "Settings" page. You can change these through settings on the "Settings" page.
One setting allows you to publish your profile in the site directory of this Friendica server. One setting allows you to publish your profile in the site directory of this Friendica server.
Another option (this may have been disabled by the site creator) allows you to publish your profile in the "Global Directory". Another option (this may have been disabled by the site admin) allows you to publish your profile in a [Global Directory](Making-Friends.md#the-directories).
This is a mega directory which contains people from many other Friendica installations world-wide.
If you do not wish to be visible to any of these sites, you may leave your profile unpublished. If you do not wish to be visible to any of these directories, do not published your profile.
Although you may have multiple profiles, you only have one profile photo. Although you may have multiple profiles, you only have one profile photo.
This is intentional. This is intentional; it avoids confusion by potentially seeing different profile pictures of a contact depending on what website you visit or conversation you participate in.
In early tests we experimented with different photos for each profile and found it was very confusing for people. You can always can use the free text information boxes within a profile such as "Tell us about yourself" and link other photos for yourself.
They might see a different picture depending on what website they visited or what conversation they were in, and often alerted them to the fact that other people might be able to see different profiles of you than they could see.
(But you can use the rich-text information boxes within a profile such as "Tell us about yourself" and link other photos onto the page.)
Keywords and Directory Search Keywords and Directory Search
--- ---
@ -70,8 +63,7 @@ The search is typically for your nickname or part of your full name.
However this search will also match against other profile fields - such as gender, location, "about", work, and education. However this search will also match against other profile fields - such as gender, location, "about", work, and education.
You may also include "Keywords" in your default profile - which may be used to search for common interests with other members. You may also include "Keywords" in your default profile - which may be used to search for common interests with other members.
You have two sets of keywords available - public and private. You have two sets of keywords available - public and private.
Private keywords are *not* visible to anybody. Private keywords are *not* visible on your profile, but will bring up your profile when matched in a search of the site directory.
You could use these keywords to locate people who share membership in secret societies, or that share a love of fishing (for example) - without making this information visible on your public profile.
Public keywords are used in the friend suggestion tool and although they aren't readily visible, they may be seen by viewing the HTML of your profile page. Public keywords are used in the friend suggestion tool and although they aren't readily visible, they may be seen by viewing the HTML of your profile page.
Directory searches are also able to use "boolean" logic so that you can search for "+lesbian +Florida" and find those who's sexual preference (or keywords) contain the world "lesbian" and that live in Florida. Directory searches are also able to use "boolean" logic so that you can search for "+lesbian +Florida" and find those who's sexual preference (or keywords) contain the world "lesbian" and that live in Florida.
@ -79,7 +71,7 @@ See the section on "Topical Tags" on the [Tags-and-Mentions](help/Tags-and-Menti
On your Contacts page is a link to "Find People with Shared Interests" (unless your site administrator has disabled the global directory). On your Contacts page is a link to "Find People with Shared Interests" (unless your site administrator has disabled the global directory).
This will combine both your public and private keywords, and find people in the global directory who have matching and/or similar keywords. This will combine both your public and private keywords, and find people in the global directory who have matching and/or similar keywords.
(Your private keywords are not identified or stored on the global directory). Private keywords are not identified or stored on the global directory.
The more keywords you provide, the more relevant the search results that are returned. The more keywords you provide, the more relevant the search results that are returned.
These are sorted by relevance. These are sorted by relevance.
You may discover that you are the first person on the list - because you are very likely the most relevant match for your keywords in the directory. You may discover that you are the first person on the list - because you are very likely the most relevant match for your keywords in the directory.

View file

@ -101,7 +101,7 @@ Derzeitige Hooks
**'post_remote'** - wird aufgerufen, wenn ein Beitrag aus einer anderen Quelle empfangen wird. Dies kann auch genutzt werden, um lokale Aktivitäten oder systemgenerierte Nachrichten zu veröffentlichen/posten. **'post_remote'** - wird aufgerufen, wenn ein Beitrag aus einer anderen Quelle empfangen wird. Dies kann auch genutzt werden, um lokale Aktivitäten oder systemgenerierte Nachrichten zu veröffentlichen/posten.
$b ist das Item-Array einer Information, die in der Datenbank und im Item gespeichert ist. $b ist das Item-Array einer Information, die in der Datenbank und im Item gespeichert ist.
{Bitte beachte: der Seiteninhalt ist bbcode - nicht HTML) {Bitte beachte: der Seiteninhalt ist bbcode - nicht HTML)
**'settings_form'** - wird aufgerufen, wenn die HTML-Ausgabe für die Einstellungsseite generiert wird. **'settings_form'** - wird aufgerufen, wenn die HTML-Ausgabe für die Einstellungsseite generiert wird.
$b ist die HTML-Ausgabe (String) der Einstellungsseite vor dem finalen "</form>"-Tag. $b ist die HTML-Ausgabe (String) der Einstellungsseite vor dem finalen "</form>"-Tag.
@ -191,184 +191,300 @@ Komplette Liste der Hook-Callbacks
Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Apr-2018 generiert): Bitte schau in die Quellcodes für Details zu Hooks, die oben nicht dokumentiert sind. Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Apr-2018 generiert): Bitte schau in die Quellcodes für Details zu Hooks, die oben nicht dokumentiert sind.
index.php: Addon::callHooks('init_1'); ### index.php
index.php: Addon::callHooks('app_menu', $arr);
index.php: Addon::callHooks('page_content_top', $a->page['content']);
index.php: Addon::callHooks($a->module.'_mod_init', $placeholder);
index.php: Addon::callHooks($a->module.'_mod_init', $placeholder);
index.php: Addon::callHooks($a->module.'_mod_post', $_POST);
index.php: Addon::callHooks($a->module.'_mod_afterpost', $placeholder);
index.php: Addon::callHooks($a->module.'_mod_content', $arr);
index.php: Addon::callHooks($a->module.'_mod_aftercontent', $arr);
index.php: Addon::callHooks('page_end', $a->page['content']);
include/api.php: Addon::callHooks('logged_in', $a->user); Addon::callHooks('init_1');
include/api.php: Addon::callHooks('authenticate', $addon_auth); Addon::callHooks('app_menu', $arr);
include/api.php: Addon::callHooks('logged_in', $a->user); Addon::callHooks('page_content_top', $a->page['content']);
Addon::callHooks($a->module.'_mod_init', $placeholder);
Addon::callHooks($a->module.'_mod_init', $placeholder);
Addon::callHooks($a->module.'_mod_post', $_POST);
Addon::callHooks($a->module.'_mod_afterpost', $placeholder);
Addon::callHooks($a->module.'_mod_content', $arr);
Addon::callHooks($a->module.'_mod_aftercontent', $arr);
Addon::callHooks('page_end', $a->page['content']);
### include/api.php
include/enotify.php: Addon::callHooks('enotify', $h); Addon::callHooks('logged_in', $a->user);
include/enotify.php: Addon::callHooks('enotify_store', $datarray); Addon::callHooks('authenticate', $addon_auth);
include/enotify.php: Addon::callHooks('enotify_mail', $datarray); Addon::callHooks('logged_in', $a->user);
include/enotify.php: Addon::callHooks('check_item_notification', $notification_data);
include/conversation.php: Addon::callHooks('conversation_start', $cb); ### include/enotify.php
include/conversation.php: Addon::callHooks('render_location', $locate);
include/conversation.php: Addon::callHooks('display_item', $arr);
include/conversation.php: Addon::callHooks('display_item', $arr);
include/conversation.php: Addon::callHooks('item_photo_menu', $args);
include/conversation.php: Addon::callHooks('jot_tool', $jotplugins);
include/security.php: Addon::callHooks('logged_in', $a->user); Addon::callHooks('enotify', $h);
Addon::callHooks('enotify_store', $datarray);
Addon::callHooks('enotify_mail', $datarray);
Addon::callHooks('check_item_notification', $notification_data);
### include/conversation.php
include/text.php: Addon::callHooks('contact_block_end', $arr); Addon::callHooks('conversation_start', $cb);
include/text.php: Addon::callHooks('poke_verbs', $arr); Addon::callHooks('render_location', $locate);
include/text.php: Addon::callHooks('prepare_body_init', $item); Addon::callHooks('display_item', $arr);
include/text.php: Addon::callHooks('prepare_body_content_filter', $hook_data); Addon::callHooks('display_item', $arr);
include/text.php: Addon::callHooks('prepare_body', $hook_data); Addon::callHooks('item_photo_menu', $args);
include/text.php: Addon::callHooks('prepare_body_final', $hook_data); Addon::callHooks('jot_tool', $jotplugins);
include/items.php: Addon::callHooks('page_info_data', $data); ### include/security.php
mod/directory.php: Addon::callHooks('directory_item', $arr); Addon::callHooks('logged_in', $a->user);
mod/xrd.php: Addon::callHooks('personal_xrd', $arr); ### include/text.php
mod/ping.php: Addon::callHooks('network_ping', $arr); Addon::callHooks('contact_block_end', $arr);
Addon::callHooks('poke_verbs', $arr);
Addon::callHooks('prepare_body_init', $item);
Addon::callHooks('prepare_body_content_filter', $hook_data);
Addon::callHooks('prepare_body', $hook_data);
Addon::callHooks('prepare_body_final', $hook_data);
mod/parse_url.php: Addon::callHooks("parse_link", $arr); ### include/items.php
mod/manage.php: Addon::callHooks('home_init', $ret); Addon::callHooks('page_info_data', $data);
mod/acl.php: Addon::callHooks('acl_lookup_end', $results); ### mod/directory.php
mod/network.php: Addon::callHooks('network_content_init', $arr); Addon::callHooks('directory_item', $arr);
mod/network.php: Addon::callHooks('network_tabs', $arr);
mod/friendica.php: Addon::callHooks('about_hook', $o); ### mod/xrd.php
mod/subthread.php: Addon::callHooks('post_local_end', $arr);
mod/profiles.php: Addon::callHooks('profile_post', $_POST); Addon::callHooks('personal_xrd', $arr);
mod/profiles.php: Addon::callHooks('profile_edit', $arr);
mod/settings.php: Addon::callHooks('addon_settings_post', $_POST); ### mod/ping.php
mod/settings.php: Addon::callHooks('connector_settings_post', $_POST);
mod/settings.php: Addon::callHooks('display_settings_post', $_POST);
mod/settings.php: Addon::callHooks('settings_post', $_POST);
mod/settings.php: Addon::callHooks('addon_settings', $settings_addons);
mod/settings.php: Addon::callHooks('connector_settings', $settings_connectors);
mod/settings.php: Addon::callHooks('display_settings', $o);
mod/settings.php: Addon::callHooks('settings_form', $o);
mod/photos.php: Addon::callHooks('photo_post_init', $_POST); Addon::callHooks('network_ping', $arr);
mod/photos.php: Addon::callHooks('photo_post_file', $ret);
mod/photos.php: Addon::callHooks('photo_post_end', $foo);
mod/photos.php: Addon::callHooks('photo_post_end', $foo);
mod/photos.php: Addon::callHooks('photo_post_end', $foo);
mod/photos.php: Addon::callHooks('photo_post_end', $foo);
mod/photos.php: Addon::callHooks('photo_post_end', intval($item_id));
mod/photos.php: Addon::callHooks('photo_upload_form', $ret);
mod/profile.php: Addon::callHooks('profile_advanced', $o); ### mod/parse_url.php
mod/home.php: Addon::callHooks('home_init', $ret); Addon::callHooks("parse_link", $arr);
mod/home.php: Addon::callHooks("home_content", $content);
mod/poke.php: Addon::callHooks('post_local_end', $arr); ### mod/manage.php
mod/contacts.php: Addon::callHooks('contact_edit_post', $_POST); Addon::callHooks('home_init', $ret);
mod/contacts.php: Addon::callHooks('contact_edit', $arr);
mod/tagger.php: Addon::callHooks('post_local_end', $arr); ### mod/acl.php
mod/lockview.php: Addon::callHooks('lockview_content', $item); Addon::callHooks('acl_lookup_end', $results);
mod/uexport.php: Addon::callHooks('uexport_options', $options); ### mod/network.php
mod/register.php: Addon::callHooks('register_post', $arr); Addon::callHooks('network_content_init', $arr);
mod/register.php: Addon::callHooks('register_form', $arr); Addon::callHooks('network_tabs', $arr);
mod/item.php: Addon::callHooks('post_local_start', $_REQUEST); ### mod/friendica.php
mod/item.php: Addon::callHooks('post_local', $datarray);
mod/item.php: Addon::callHooks('post_local_end', $datarray);
mod/editpost.php: Addon::callHooks('jot_tool', $jotplugins); Addon::callHooks('about_hook', $o);
### mod/subthread.php
src/Network/FKOAuth1.php: Addon::callHooks('logged_in', $a->user); Addon::callHooks('post_local_end', $arr);
src/Render/FriendicaSmartyEngine.php: Addon::callHooks("template_vars", $arr); ### mod/profiles.php
src/Model/Item.php: Addon::callHooks('post_local', $item); Addon::callHooks('profile_post', $_POST);
src/Model/Item.php: Addon::callHooks('post_remote', $item); Addon::callHooks('profile_edit', $arr);
src/Model/Item.php: Addon::callHooks('post_local_end', $posted_item);
src/Model/Item.php: Addon::callHooks('post_remote_end', $posted_item);
src/Model/Item.php: Addon::callHooks('tagged', $arr);
src/Model/Item.php: Addon::callHooks('post_local_end', $new_item);
src/Model/Contact.php: Addon::callHooks('contact_photo_menu', $args); ### mod/settings.php
src/Model/Contact.php: Addon::callHooks('follow', $arr);
src/Model/Profile.php: Addon::callHooks('profile_sidebar_enter', $profile); Addon::callHooks('addon_settings_post', $_POST);
src/Model/Profile.php: Addon::callHooks('profile_sidebar', $arr); Addon::callHooks('connector_settings_post', $_POST);
src/Model/Profile.php: Addon::callHooks('profile_tabs', $arr); Addon::callHooks('display_settings_post', $_POST);
src/Model/Profile.php: Addon::callHooks('zrl_init', $arr); Addon::callHooks('settings_post', $_POST);
Addon::callHooks('addon_settings', $settings_addons);
Addon::callHooks('connector_settings', $settings_connectors);
Addon::callHooks('display_settings', $o);
Addon::callHooks('settings_form', $o);
src/Model/Event.php: Addon::callHooks('event_updated', $event['id']); ### mod/photos.php
src/Model/Event.php: Addon::callHooks("event_created", $event['id']);
src/Model/User.php: Addon::callHooks('register_account', $uid); Addon::callHooks('photo_post_init', $_POST);
src/Model/User.php: Addon::callHooks('remove_user', $user); Addon::callHooks('photo_post_file', $ret);
Addon::callHooks('photo_post_end', $foo);
Addon::callHooks('photo_post_end', $foo);
Addon::callHooks('photo_post_end', $foo);
Addon::callHooks('photo_post_end', $foo);
Addon::callHooks('photo_post_end', intval($item_id));
Addon::callHooks('photo_upload_form', $ret);
src/Content/Text/BBCode.php: Addon::callHooks('bbcode', $text); ### mod/profile.php
src/Content/Text/BBCode.php: Addon::callHooks('bb2diaspora', $text);
src/Content/Text/HTML.php: Addon::callHooks('html2bbcode', $message); Addon::callHooks('profile_advanced', $o);
src/Content/Smilies.php: Addon::callHooks('smilie', $params); ### mod/home.php
src/Content/Feature.php: Addon::callHooks('isEnabled', $arr); Addon::callHooks('home_init', $ret);
src/Content/Feature.php: Addon::callHooks('get', $arr); Addon::callHooks("home_content", $content);
src/Content/ContactSelector.php: Addon::callHooks('network_to_name', $nets); ### mod/poke.php
src/Content/ContactSelector.php: Addon::callHooks('gender_selector', $select);
src/Content/ContactSelector.php: Addon::callHooks('sexpref_selector', $select);
src/Content/ContactSelector.php: Addon::callHooks('marital_selector', $select);
src/Content/OEmbed.php: Addon::callHooks('oembed_fetch_url', $embedurl, $j); Addon::callHooks('post_local_end', $arr);
src/Content/Nav.php: Addon::callHooks('page_header', $a->page['nav']); ### mod/contacts.php
src/Content/Nav.php: Addon::callHooks('nav_info', $nav);
src/Worker/Directory.php: Addon::callHooks('globaldir_update', $arr); Addon::callHooks('contact_edit_post', $_POST);
src/Worker/Notifier.php: Addon::callHooks('notifier_end', $target_item); Addon::callHooks('contact_edit', $arr);
src/Worker/Queue.php: Addon::callHooks('queue_predeliver', $r);
src/Worker/Queue.php: Addon::callHooks('queue_deliver', $params);
src/Module/Login.php: Addon::callHooks('authenticate', $addon_auth); ### mod/tagger.php
src/Module/Login.php: Addon::callHooks('login_hook', $o);
src/Module/Logout.php: Addon::callHooks("logging_out");
src/Object/Post.php: Addon::callHooks('render_location', $locate); Addon::callHooks('post_local_end', $arr);
src/Object/Post.php: Addon::callHooks('display_item', $arr);
src/Core/ACL.php: Addon::callHooks('contact_select_options', $x); ### mod/lockview.php
src/Core/ACL.php: Addon::callHooks($a->module.'_pre_'.$selname, $arr);
src/Core/ACL.php: Addon::callHooks($a->module.'_post_'.$selname, $o);
src/Core/ACL.php: Addon::callHooks($a->module.'_pre_'.$selname, $arr);
src/Core/ACL.php: Addon::callHooks($a->module.'_post_'.$selname, $o);
src/Core/ACL.php: Addon::callHooks('jot_networks', $jotnets);
src/Core/Worker.php: Addon::callHooks("proc_run", $arr); Addon::callHooks('lockview_content', $item);
src/Util/Emailer.php: Addon::callHooks('emailer_send_prepare', $params); ### mod/uexport.php
src/Util/Emailer.php: Addon::callHooks("emailer_send", $hookdata);
src/Util/Map.php: Addon::callHooks('generate_map', $arr); Addon::callHooks('uexport_options', $options);
src/Util/Map.php: Addon::callHooks('generate_named_map', $arr);
src/Util/Map.php: Addon::callHooks('Map::getCoordinates', $arr);
src/Util/Network.php: Addon::callHooks('avatar_lookup', $avatar); ### mod/register.php
src/Util/ParseUrl.php: Addon::callHooks("getsiteinfo", $siteinfo); Addon::callHooks('register_post', $arr);
Addon::callHooks('register_form', $arr);
src/Protocol/DFRN.php: Addon::callHooks('atom_feed_end', $atom); ### mod/item.php
src/Protocol/DFRN.php: Addon::callHooks('atom_feed_end', $atom);
Addon::callHooks('post_local_start', $_REQUEST);
Addon::callHooks('post_local', $datarray);
Addon::callHooks('post_local_end', $datarray);
### mod/editpost.php
Addon::callHooks('jot_tool', $jotplugins);
### src/Network/FKOAuth1.php
Addon::callHooks('logged_in', $a->user);
### src/Render/FriendicaSmartyEngine.php
Addon::callHooks("template_vars", $arr);
### src/Model/Item.php
Addon::callHooks('post_local', $item);
Addon::callHooks('post_remote', $item);
Addon::callHooks('post_local_end', $posted_item);
Addon::callHooks('post_remote_end', $posted_item);
Addon::callHooks('tagged', $arr);
Addon::callHooks('post_local_end', $new_item);
### src/Model/Contact.php
Addon::callHooks('contact_photo_menu', $args);
Addon::callHooks('follow', $arr);
### src/Model/Profile.php
Addon::callHooks('profile_sidebar_enter', $profile);
Addon::callHooks('profile_sidebar', $arr);
Addon::callHooks('profile_tabs', $arr);
Addon::callHooks('zrl_init', $arr);
### src/Model/Event.php
Addon::callHooks('event_updated', $event['id']);
Addon::callHooks("event_created", $event['id']);
### src/Model/User.php
Addon::callHooks('register_account', $uid);
Addon::callHooks('remove_user', $user);
### src/Content/Text/BBCode.php
Addon::callHooks('bbcode', $text);
Addon::callHooks('bb2diaspora', $text);
### src/Content/Text/HTML.php
Addon::callHooks('html2bbcode', $message);
### src/Content/Smilies.php
Addon::callHooks('smilie', $params);
### src/Content/Feature.php
Addon::callHooks('isEnabled', $arr);
Addon::callHooks('get', $arr);
### src/Content/ContactSelector.php
Addon::callHooks('network_to_name', $nets);
Addon::callHooks('gender_selector', $select);
Addon::callHooks('sexpref_selector', $select);
Addon::callHooks('marital_selector', $select);
### src/Content/OEmbed.php
Addon::callHooks('oembed_fetch_url', $embedurl, $j);
### src/Content/Nav.php
Addon::callHooks('page_header', $a->page['nav']);
Addon::callHooks('nav_info', $nav);
### src/Worker/Directory.php
Addon::callHooks('globaldir_update', $arr);
### src/Worker/Notifier.php
Addon::callHooks('notifier_end', $target_item);
### src/Worker/Queue.php
Addon::callHooks('queue_predeliver', $r);
Addon::callHooks('queue_deliver', $params);
### src/Module/Login.php
Addon::callHooks('authenticate', $addon_auth);
Addon::callHooks('login_hook', $o);
### src/Module/Logout.php
Addon::callHooks("logging_out");
### src/Object/Post.php
Addon::callHooks('render_location', $locate);
Addon::callHooks('display_item', $arr);
### src/Core/ACL.php
Addon::callHooks('contact_select_options', $x);
Addon::callHooks($a->module.'_pre_'.$selname, $arr);
Addon::callHooks($a->module.'_post_'.$selname, $o);
Addon::callHooks($a->module.'_pre_'.$selname, $arr);
Addon::callHooks($a->module.'_post_'.$selname, $o);
Addon::callHooks('jot_networks', $jotnets);
### src/Core/Worker.php
Addon::callHooks("proc_run", $arr);
### src/Util/Emailer.php
Addon::callHooks('emailer_send_prepare', $params);
Addon::callHooks("emailer_send", $hookdata);
### src/Util/Map.php
Addon::callHooks('generate_map', $arr);
Addon::callHooks('generate_named_map', $arr);
Addon::callHooks('Map::getCoordinates', $arr);
### src/Util/Network.php
Addon::callHooks('avatar_lookup', $avatar);
### src/Util/ParseUrl.php
Addon::callHooks("getsiteinfo", $siteinfo);
### src/Protocol/DFRN.php
Addon::callHooks('atom_feed_end', $atom);
Addon::callHooks('atom_feed_end', $atom);

View file

@ -8,7 +8,7 @@ Du hast derzeit zwei Möglichkeiten, einen Chat auf Deiner Friendica-Seite zu be
* IRC - Internet Relay Chat * IRC - Internet Relay Chat
* Jappix * Jappix
##IRC Addon ## IRC Addon
Sobald das Addon aktiviert ist, kannst Du den Chat unter [deineSeite.de/irc](../irc) finden. Sobald das Addon aktiviert ist, kannst Du den Chat unter [deineSeite.de/irc](../irc) finden.
Beachte aber, dass dieser Chat auch ohne Anmeldung auf Deiner Seite zugänglich ist und somit auch Fremde diesen Chat mitnutzen können. Beachte aber, dass dieser Chat auch ohne Anmeldung auf Deiner Seite zugänglich ist und somit auch Fremde diesen Chat mitnutzen können.
@ -27,7 +27,7 @@ Unten hast Du ein Eingabefeld, um Beiträge zu schreiben.
Weiter Informationen zu IRC findest Du zum Beispiel auf <a href="http://wiki.ubuntuusers.de/IRC" target="_blank">ubuntuusers.de</a>, in <a href="https://de.wikipedia.org/wiki/Internet_Relay_Chat" target="_blank">Wikipedia</a> oder bei <a href="http://www.irchelp.org/" target="_blank">icrhelp.org</a> (in Englisch). Weiter Informationen zu IRC findest Du zum Beispiel auf <a href="http://wiki.ubuntuusers.de/IRC" target="_blank">ubuntuusers.de</a>, in <a href="https://de.wikipedia.org/wiki/Internet_Relay_Chat" target="_blank">Wikipedia</a> oder bei <a href="http://www.irchelp.org/" target="_blank">icrhelp.org</a> (in Englisch).
##Jappix Mini ## Jappix Mini
Das Jappix Mini Addon erlaubt das Erstellen einer Chatbox für Jabber/XMPP-Kontakte. Das Jappix Mini Addon erlaubt das Erstellen einer Chatbox für Jabber/XMPP-Kontakte.
Ein Jabber/XMPP Account sollte vor der Installation bereits vorhanden sein. Ein Jabber/XMPP Account sollte vor der Installation bereits vorhanden sein.

View file

@ -35,7 +35,7 @@ Aktiviere die folgenden Addons:
rendertime rendertime
###rendertime ### rendertime
**Beschreibung** **Beschreibung**
@ -60,7 +60,7 @@ Webserver
Wenn du einen Apache-Webserver nutzt, aktiviere bitte die folgenden Module: Wenn du einen Apache-Webserver nutzt, aktiviere bitte die folgenden Module:
###Cache-Control ### Cache-Control
**Beschreibung** **Beschreibung**
@ -74,7 +74,7 @@ ExpiresActive on ExpiresDefault "access plus 1 week"
Weitere Informationen findest du hier: http://httpd.apache.org/docs/2.2/mod/mod_expires.html. Weitere Informationen findest du hier: http://httpd.apache.org/docs/2.2/mod/mod_expires.html.
###Compress content ### Compress content
**Beschreibung** **Beschreibung**
@ -85,7 +85,7 @@ Aktiviere das Modul "mod_deflate" durch die Eingabe "a2enmod deflate" als root.
Weitere Informationen findest du hier: http://httpd.apache.org/docs/2.2/mod/mod_deflate.html Weitere Informationen findest du hier: http://httpd.apache.org/docs/2.2/mod/mod_deflate.html
###PHP ### PHP
**FCGI** **FCGI**
@ -93,7 +93,7 @@ Wenn du Apache nutzt, dann denk darüber nach, FCGI zu nutzen.
Wenn du eine Debian-basierte Distribution nutzt, dann wirst du die Pakete "php5-cgi" und "libapache2-mod-fcgid" benötigen. Wenn du eine Debian-basierte Distribution nutzt, dann wirst du die Pakete "php5-cgi" und "libapache2-mod-fcgid" benötigen.
Nutze externe Dokumente, um eine detailiertere Erklärung für die Einrichtung eines Systems auf FCGI-Basis zu erhalten. Nutze externe Dokumente, um eine detailiertere Erklärung für die Einrichtung eines Systems auf FCGI-Basis zu erhalten.
###Database ### Database
Es gibt Skripte wie [tuning-primer.sh](http://www.day32.com/MySQL/) und [mysqltuner.pl](http://mysqltuner.pl), die den Datenbankserver analysieren und Hinweise darauf geben, welche Werte verändert werden könnten. Es gibt Skripte wie [tuning-primer.sh](http://www.day32.com/MySQL/) und [mysqltuner.pl](http://mysqltuner.pl), die den Datenbankserver analysieren und Hinweise darauf geben, welche Werte verändert werden könnten.

View file

@ -4,6 +4,7 @@ Friendica Installation
* [Zur Startseite der Hilfe](help) * [Zur Startseite der Hilfe](help)
Wir haben hart daran gearbeitet, um Friendica auf vorgefertigten Hosting-Plattformen zum Laufen zu bringen - solche, auf denen auch Wordpress Blogs und Drupal-Installationen laufen. Wir haben hart daran gearbeitet, um Friendica auf vorgefertigten Hosting-Plattformen zum Laufen zu bringen - solche, auf denen auch Wordpress Blogs und Drupal-Installationen laufen.
Wir bieten eine manuelle und eine automatische Installation an.
Aber bedenke, dass Friendica mehr als eine einfache Webanwendung ist. Aber bedenke, dass Friendica mehr als eine einfache Webanwendung ist.
Es handelt sich um ein komplexes Kommunikationssystem, das eher an einen Email-Server erinnert als an einen Webserver. Es handelt sich um ein komplexes Kommunikationssystem, das eher an einen Email-Server erinnert als an einen Webserver.
Um die Verfügbarkeit und Performance zu gewährleisten, werden Nachrichten im Hintergrund verschickt und gespeichert, um sie später zu verschicken, wenn eine Webseite gerade nicht erreichbar ist. Um die Verfügbarkeit und Performance zu gewährleisten, werden Nachrichten im Hintergrund verschickt und gespeichert, um sie später zu verschicken, wenn eine Webseite gerade nicht erreichbar ist.
@ -11,83 +12,124 @@ Diese Funktionalität benötigt ein wenig mehr als die normalen Blogs.
Nicht jeder PHP/MySQL-Hosting-Anbieter kann Friendica unterstützen. Nicht jeder PHP/MySQL-Hosting-Anbieter kann Friendica unterstützen.
Viele hingegen können es. Aber **bitte** prüfe die Voraussetzungen deines Servers vor der Installation. Viele hingegen können es. Aber **bitte** prüfe die Voraussetzungen deines Servers vor der Installation.
Wenn dir Fehler während der Installation auffallen, sag uns bitte über [github](https://github.com/friendica/issues) Bescheid. Wenn dir Fehler während der Installation auffallen, sag uns bitte über [Helper](http://forum.friendi.ca/profile/helpers) oder das [Entwickler Forum](https://forum.friendi.ca/profile/developers) Bescheid oder [erstelle ein Issue](https://github.com/friendica/friendica/issues).
Gib uns bitte so viele Infos zu deinem System, wie du kannst, und beschreibe den Fehler mit allen Details und Fehlermeldungen, so dass wir den Fehler zukünftig verhindern können. Gib uns bitte so viele Infos zu deinem System, wie du kannst, und beschreibe den Fehler mit allen Details und Fehlermeldungen, so dass wir den Fehler zukünftig verhindern können.
Aufgrund der großen Anzahl an verschiedenen Betriebssystemen und PHP-Plattformen haben wir nur geringe Kapazitäten, um deine PHP-Installation zu debuggen oder fehlende Module zu ersetzen, aber wir tun unser Bestes, um allgemeine Code-Fehler zu beheben. Aufgrund der großen Anzahl an verschiedenen Betriebssystemen und PHP-Plattformen haben wir nur geringe Kapazitäten, um deine PHP-Installation zu debuggen oder fehlende Module zu ersetzen, aber wir tun unser Bestes, um allgemeine Code-Fehler zu beheben.
Falls du noch keinen Friendica-Account hast, kannst du dir einen temporären Account hier erstellen: [tryfriendica.de](https://tryfriendica.de).
Darüber kannst du den genannten Forum beitreten.
Der Account wird nach 7 Tagen ablaufen, aber du kannst einen Server-Admin fragen, diesen Account länger zu erhalten, sollte das Problem nicht innerhalb dieser Zeit gelöst sein.
Bevor du anfängst: suche dir einen Domain- oder Subdomainnamen für deinen Server. Bevor du anfängst: suche dir einen Domain- oder Subdomainnamen für deinen Server.
Dinge verändern sich und einige deiner Freunde haben möglicherweise Probleme, mit dir zu kommunizieren. Dinge verändern sich und einige deiner Freunde haben möglicherweise Probleme, mit dir zu kommunizieren.
Wir planen, diese Einschränkung in einer zukünftigen Version zu beheben. Wir planen, diese Einschränkung in einer zukünftigen Version zu beheben.
1. Voraussetzungen Requirements
- Apache mit einer aktiverten mod-rewrite-Funktion und dem Eintrag "Options All", so dass du die lokale .htaccess-Datei nutzen kannst ---
- PHP 5.6+. Je neuer, desto besser.
- PHP *Kommandozeilen*-Zugang mit register_argc_argv auf "true" gesetzt in der php.ini-Datei
- Curl, GD, PDO, MySQLi, xml, zip und OpenSSL-Erweiterung
- etwas in der Art eines Email-Servers oder eines Gateways wie PHP mail()
- Das POSIX Modul muss aktiviert sein ([CentOS, RHEL](http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7) haben dies z.B. deaktiviert)
- Mysql 5.5.3+
- die Möglichkeit, wiederkehrende Aufgaben mit cron (Linux/Mac) oder "Scheduled Tasks" einzustellen (Windows) [Beachte: andere Optionen sind in Abschnitt 7 dieser Dokumentation zu finden]
- Installation in einer Top-Level-Domain oder Subdomain (ohne eine Verzeichnis/Pfad-Komponente in der URL) wird bevorzugt. Verzeichnispfade sind für diesen Zweck nicht so günstig und wurden auch nicht ausführlich getestet.
* Apache mit einer aktiverten mod-rewrite-Funktion und dem Eintrag "Options All", so dass du die lokale .htaccess-Datei nutzen kannst
* PHP 5.6+ (PHP 7 ist aufgrund der Performance empfohlen)
* PHP *Kommandozeilen*-Zugang mit register_argc_argv auf "true" gesetzt in der php.ini-Datei
* Curl, GD, PDO, MySQLi, xml, zip und OpenSSL-Erweiterung
* Das POSIX Modul muss aktiviert sein ([CentOS, RHEL](http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7) haben dies z.B. deaktiviert)
* etwas in der Art eines Email-Servers oder eines Gateways wie PHP mail()
* Mysql 5.5.3+ (oder eine äquivalente Alternative: MariaDB, Percona Server etc.)
* die Möglichkeit, wiederkehrende Aufgaben mit cron (Linux/Mac) oder "Scheduled Tasks" einzustellen (Windows) [Beachte: andere Optionen sind in Abschnitt 7 dieser Dokumentation zu finden]
* Installation in einer Top-Level-Domain oder Subdomain (ohne eine Verzeichnis/Pfad-Komponente in der URL) wird bevorzugt. Verzeichnispfade sind für diesen Zweck nicht so günstig und wurden auch nicht ausführlich getestet.
[Dreamhost.com bietet ein ausreichendes Hosting-Paket mit den nötigen Features zu einem annehmbaren Preis. Wenn dein Hosting-Anbieter keinen Unix-Zugriff erlaubt, kannst du Schwierigkeiten mit der Einrichtung der Webseite haben. Installation
---
1.1. APT-Pakete ### Friendica
- Apache: sudo apt-get install apache2
- PHP5: sudo apt-get install php5
- PHP5-Zusätzliche Pakete: sudo apt-get install php5-curl php5-gd php5-mysql
- MySQL: sudo apt-get install mysql-server
2. Entpacke die Friendica-Daten in das Quellverzeichnis (root) des Dokumentenbereichs deines Webservers. Entpacke die Friendica-Daten in das Quellverzeichnis (root) des Dokumentenbereichs deines Webservers.
Wenn du die Möglichkeit hierzu hast, empfehlen wir dir "git" zu nutzen, um die Daten direkt von der Quelle zu klonen, statt die gepackte .tar- oder .zip-Datei zu nutzen.
Das macht die Aktualisierung wesentlich einfacher.
Der Linux-Code, mit dem man die Dateien direkt in ein Verzeichnis wie "meinewebseite" kopiert, ist
- Wenn du die Möglichkeit hierzu hast, empfehlen wir dir "git" zu nutzen, um die Daten direkt von der Quelle zu klonen, statt die gepackte .tar- oder .zip-Datei zu nutzen. Das macht die Aktualisierung wesentlich einfacher. Der Linux-Code, mit dem man die Dateien direkt in ein Verzeichnis wie "meinewebseite" kopiert, ist git clone https://github.com/friendica/friendica.git mywebsite
cd mywebsite
bin/composer.phar install
`git clone https://github.com/friendica/friendica.git meinewebseite` Stelle sicher, dass der Ordner *view/smarty3* existiert and von dem Webserver-Benutzer beschreibbar ist
- und dann kannst du die letzten Änderungen immer mit dem folgenden Code holen mkdir view/smarty3
chmod 777 view/smarty3
`cd meinewebseite` Falls Addons installiert werden sollen: Gehe in den Friendica-Ordner
`git pull`
`bin/composer.phar install`
- Addons installieren cd mywebsite
- zunächst solltest du **in** deinem Webseitenordner sein
`cd meinewebseite` Und die Addon Repository klonst:
- dann kannst du das Addon-Verzeichnis seperat kopieren git clone https://github.com/friendica/friendica-addons.git addon
`git clone https://github.com/friendica/friendica-addons.git addon` Um das Addon-Verzeichnis aktuell zu halten, solltest du in diesem Pfad ein "git pull"-Befehl eintragen
- Um das Addon-Verzeichnis aktuell zu halten, solltest du in diesem Pfad ein "git pull"-Befehl eintragen cd meinewebseite/addon
git pull
`cd meinewebseite/addon` Wenn du den Verzeichnispfad auf deinen Webserver kopierst, dann stelle sicher, dass du auch die .htaccess kopierst, da "Punkt"-Dateien oft versteckt sind und normalerweise nicht direkt kopiert werden.
`git pull` ### Erselle eine Datenbank
- Wenn du den Verzeichnispfad auf deinen Webserver kopierst, dann stelle sicher, dass du auch die .htaccess kopierst, da "Punkt"-Dateien oft versteckt sind und normalerweise nicht direkt kopiert werden. Erstelle eine leere Datenbank und notiere alle Zugangsdaten (Adresse der Datenbank, Nutzername, Passwort, Datenbankname).
3. Erstelle eine leere Datenbank und notiere alle Zugangsdaten (Adresse der Datenbank, Nutzername, Passwort, Datenbankname).
Friendica benötigt die Berechtigungen um neue Felder in dieser Datenbank zu ertellen (create) und zu löschen (delete). Friendica benötigt die Berechtigungen um neue Felder in dieser Datenbank zu ertellen (create) und zu löschen (delete).
4. Besuche deine Webseite mit deinem Browser und befolge die Anleitung. Bitte beachte jeden Fehler und korrigiere diese, bevor du fortfährst. Mit neueren Versionen von MySQL (5.7.17+) musst du den `sql_mode` zu `''` (blank) setzen.
Benutze diese Einstellung, wenn der Installer nicht in der Lage ist, die Tabellen aufgrund eines Timestamp-Format Problems zu erstellen.
Falls dem so ist, finde den `[mysqld]` Bereich in deiner `my.conf` Datei und füge diese Zeile hinzu:
5. *Wenn* die automatisierte Installation aus irgendeinem Grund fehlschlägt, dann prüfe das Folgende: sql_mode = ''
- ".htconfig.php" existiert ... wenn nicht, bearbeite die „htconfig.php“ und ändere die Systemeinstellungen. Benenne sie um in „.htconfig.php" Starte MySQL dann neu und es sollte klappen.
- die Datenbank beinhaltet Daten. ... wenn nicht, importiere den Inhalt der Datei "database.sql" mit phpmyadmin oder per mysql-Kommandozeile.
6. Besuche deine Seite an diesem Punkt wieder und registriere deinen persönlichen Account. Alle Registrierungsprobleme sollten automatisch behebbar sein. ### Option A: Der manuelle Installer
Wenn du irgendwelche **kritischen** Fehler zu diesen Zeitpunkt erhalten solltest, deutet das darauf hin, dass die Datenbank nicht korrekt installiert wurde. Du kannst bei Bedarf die Datei .htconfig.php verschieben/umbenennen und die Datenbank leeren (als „Dropping“ bezeichnet), so dass du mit einem sauberen System neu starten kannst.
7. Erstelle einen Cron job oder einen regelmäßigen Task, um den Poller alle 5-10 Minuten im Hintergrund ablaufen zu lassen. Beispiel: Besuche deine Webseite mit deinem Browser und befolge die Anleitung.
Bitte beachte jeden Fehler und korrigiere diese, bevor du fortfährst.
`cd /base/directory; /path/to/php bin/worker.php` Falls du einen Port für die Datenbankverbindung angeben musst, kannst du diesen in der Host-Eingabe Zeile angeben.
*Wenn* die manuelle Installation aus irgendeinem Grund fehlschlägt, dann prüfe das Folgende:
* ".htconfig.php" existiert ... wenn nicht, bearbeite die „htconfig.php“ und ändere die Systemeinstellungen. Benenne sie um in „.htconfig.php".
* die Datenbank beinhaltet Daten. ... wenn nicht, importiere den Inhalt der Datei "database.sql" mit phpmyadmin oder per mysql-Kommandozeile.
Besuche deine Seite an diesem Punkt wieder und registriere deinen persönlichen Account.
Alle Registrierungsprobleme sollten automatisch behebbar sein.
Wenn du irgendwelche **kritischen** Fehler zu diesen Zeitpunkt erhalten solltest, deutet das darauf hin, dass die Datenbank nicht korrekt installiert wurde.
Du kannst bei Bedarf die Datei .htconfig.php verschieben/umbenennen und die Datenbank leeren (als „Dropping“ bezeichnet), so dass du mit einem sauberen System neu starten kannst.
### Option B: Starte das manuelle Installationsscript
Öffne die Datei htconfig.php im Friendica-Hauptordner mit einem Text-Editor.
Entferne die `die('...');` Zeile und bearbeite die Einstellungen so, das sie zu deinem System passen (MySQL, Sprache, Theme etc.).
Dann speichere die Datei (jedoch nicht umbenennen).
Gehe in den Friendica-Hauptordner und führe den Kommandozeilen Befehl aus:
bin/console autoinstall
Oder falls du alle optionalen Checks ausfürehn lassen möchtest, benutze diese Option:
bin/console autoinstall -a
*Wenn* die automatisierte Installation aus irgendeinem Grund fehlschlägt, dann prüfe das Folgende:
* Existiert die `.htconfig.php`? Falls ja, wird die automatisierte Installation nicht gestartet.
* Sind Einstellungen in der `.htconfig.php` korrekt? Falls nicht, bitte bearbeite diese Datei erneut.
* Ist die leere MySQL-Datenbank erstellt? Falls nicht, erstelle diese.
Für mehr Informationen kannst du diese Option verwenden:
bin/console autoinstall -v
### Einen Worker einrichten
Erstelle einen Cron job oder einen regelmäßigen Task, um den Poller alle 5-10 Minuten im Hintergrund ablaufen zu lassen.
Beispiel:
cd /base/directory; /path/to/php bin/worker.php
Ändere "/base/directory" und "/path/to/php" auf deine Systemvorgaben. Ändere "/base/directory" und "/path/to/php" auf deine Systemvorgaben.
@ -101,10 +143,11 @@ Friendica wird nicht korrekt laufen, wenn dieser Schritt nicht erfolgreich abges
Falls das Einrichten des cron nicht möglich ist, kannst Du alternativ den "frontend worker" vom Administrationsinterface aus aktivieren. Falls das Einrichten des cron nicht möglich ist, kannst Du alternativ den "frontend worker" vom Administrationsinterface aus aktivieren.
###Erstelle einen Backup Plan ### Erstelle einen Backup Plan
Es werden schlimme Dinge geschehen. Es werden schlimme Dinge geschehen.
Sei es nun ein Hardwareversage oder eine korrumpierte Datenbank. Sei es nun ein Hardwareversagen oder eine kaputte Datenbank.
Deshalb solltest du dir nachdem die Installation deines Friendica Knotens abgeschlossen ist einen Backup Plan erstellen. Deshalb solltest du dir, nachdem die Installation deines Friendica Knotens abgeschlossen ist, einen Backup Plan erstellen.
Die wichtigste Datei ist die `.htconfig.php` im Stammverzeichnis deiner Friendica Installation. Die wichtigste Datei ist die `.htconfig.php` im Stammverzeichnis deiner Friendica Installation.
Und da alle Daten in der Datenbank gespeichert werden, solltest du einen nicht all zu alten Dump der Friendica Datenbank zur Hand haben, solltest du deinen Knoten wieder herstellen müssen. Und da alle Daten in der Datenbank gespeichert werden, solltest du einen nicht all zu alten Dump der Friendica Datenbank zur Hand haben, solltest du deinen Knoten wieder herstellen müssen.

View file

@ -860,12 +860,15 @@ class dba {
* *
* @param string $table Table name * @param string $table Table name
* @param array $conditions Field condition(s) * @param array $conditions Field condition(s)
* @param array $options
* - cascade: If true we delete records in other tables that depend on the one we're deleting through
* relations (default: true)
* @param boolean $in_process Internal use: Only do a commit after the last delete * @param boolean $in_process Internal use: Only do a commit after the last delete
* @param array $callstack Internal use: prevent endless loops * @param array $callstack Internal use: prevent endless loops
* *
* @return boolean|array was the delete successful? When $in_process is set: deletion data * @return boolean|array was the delete successful? When $in_process is set: deletion data
*/ */
public static function delete($table, array $conditions, $in_process = false, array &$callstack = []) public static function delete($table, array $conditions, array $options = [], $in_process = false, array &$callstack = [])
{ {
if (empty($table) || empty($conditions)) { if (empty($table) || empty($conditions)) {
logger('Table and conditions have to be set'); logger('Table and conditions have to be set');
@ -888,13 +891,15 @@ class dba {
$commands[$key] = ['table' => $table, 'conditions' => $conditions]; $commands[$key] = ['table' => $table, 'conditions' => $conditions];
$cascade = defaults($options, 'cascade', true);
// To speed up the whole process we cache the table relations // To speed up the whole process we cache the table relations
if (count(self::$relation) == 0) { if ($cascade && count(self::$relation) == 0) {
self::buildRelationData(); self::buildRelationData();
} }
// Is there a relation entry for the table? // Is there a relation entry for the table?
if (isset(self::$relation[$table])) { if ($cascade && isset(self::$relation[$table])) {
// We only allow a simple "one field" relation. // We only allow a simple "one field" relation.
$field = array_keys(self::$relation[$table])[0]; $field = array_keys(self::$relation[$table])[0];
$rel_def = array_values(self::$relation[$table])[0]; $rel_def = array_values(self::$relation[$table])[0];
@ -907,7 +912,7 @@ class dba {
if ((count($conditions) == 1) && ($field == array_keys($conditions)[0])) { if ((count($conditions) == 1) && ($field == array_keys($conditions)[0])) {
foreach ($rel_def AS $rel_table => $rel_fields) { foreach ($rel_def AS $rel_table => $rel_fields) {
foreach ($rel_fields AS $rel_field) { foreach ($rel_fields AS $rel_field) {
$retval = self::delete($rel_table, [$rel_field => array_values($conditions)[0]], true, $callstack); $retval = self::delete($rel_table, [$rel_field => array_values($conditions)[0]], $options, true, $callstack);
$commands = array_merge($commands, $retval); $commands = array_merge($commands, $retval);
} }
} }
@ -921,7 +926,7 @@ class dba {
while ($row = self::fetch($data)) { while ($row = self::fetch($data)) {
// Now we accumulate the delete commands // Now we accumulate the delete commands
$retval = self::delete($table, [$field => $row[$field]], true, $callstack); $retval = self::delete($table, [$field => $row[$field]], $options, true, $callstack);
$commands = array_merge($commands, $retval); $commands = array_merge($commands, $retval);
} }
@ -968,7 +973,7 @@ class dba {
// Split the SQL queries in chunks of 100 values // Split the SQL queries in chunks of 100 values
// We do the $i stuff here to make the code better readable // We do the $i stuff here to make the code better readable
$i = $counter[$key_table][$key_condition]; $i = $counter[$key_table][$key_condition];
if (count($compacted[$key_table][$key_condition][$i]) > 100) { if (isset($compacted[$key_table][$key_condition][$i]) && count($compacted[$key_table][$key_condition][$i]) > 100) {
++$i; ++$i;
} }

View file

@ -1411,18 +1411,13 @@ function prepare_body(array &$item, $attach = false, $is_preview = false)
function apply_content_filter($html, array $reasons) function apply_content_filter($html, array $reasons)
{ {
if (count($reasons)) { if (count($reasons)) {
$rnd = random_string(8); $tpl = get_markup_template('wall/content_filter.tpl');
$content_filter_html = '<ul class="content-filter-reasons">'; $html = replace_macros($tpl, [
foreach ($reasons as $reason) { '$reasons' => $reasons,
$content_filter_html .= '<li>' . htmlspecialchars($reason) . '</li>' . PHP_EOL; '$rnd' => random_string(8),
} '$openclose' => L10n::t('Click to open/close'),
$content_filter_html .= '</ul> '$html' => $html
<p><span id="content-filter-wrap-' . $rnd . '" class="fakelink content-filter-button" onclick=openClose(\'content-filter-' . $rnd . '\'); >' . ]);
L10n::t('Click to open/close') .
'</span></p>
<div id="content-filter-' . $rnd . '" class="content-filter-content" style="display: none;">';
$html = $content_filter_html . $html . '</div>';
} }
return $html; return $html;

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');
@ -1262,6 +1263,7 @@ function admin_page_site(App $a)
/* Community page style */ /* Community page style */
$community_page_style_choices = [ $community_page_style_choices = [
CP_NO_INTERNAL_COMMUNITY => L10n::t("No community page for local users"),
CP_NO_COMMUNITY_PAGE => L10n::t("No community page"), CP_NO_COMMUNITY_PAGE => L10n::t("No community page"),
CP_USERS_ON_SERVER => L10n::t("Public postings from users of this site"), CP_USERS_ON_SERVER => L10n::t("Public postings from users of this site"),
CP_GLOBAL_COMMUNITY => L10n::t("Public postings from the federated network"), CP_GLOBAL_COMMUNITY => L10n::t("Public postings from the federated network"),

View file

@ -23,6 +23,12 @@ function babel_content()
'content' => visible_lf($bbcode) 'content' => visible_lf($bbcode)
]; ];
$plain = Text\BBCode::toPlaintext($bbcode, false);
$results[] = [
'title' => L10n::t('BBCode::toPlaintext'),
'content' => visible_lf($plain)
];
$html = Text\BBCode::convert($bbcode); $html = Text\BBCode::convert($bbcode);
$results[] = [ $results[] = [
'title' => L10n::t("BBCode::convert \x28raw HTML\x29"), 'title' => L10n::t("BBCode::convert \x28raw HTML\x29"),

View file

@ -30,6 +30,11 @@ function community_content(App $a, $update = 0)
$page_style = Config::get('system', 'community_page_style'); $page_style = Config::get('system', 'community_page_style');
if ($page_style == CP_NO_INTERNAL_COMMUNITY) {
notice(L10n::t('Access denied.') . EOL);
return;
}
if ($a->argc > 1) { if ($a->argc > 1) {
$content = $a->argv[1]; $content = $a->argv[1];
} else { } else {

View file

@ -25,42 +25,13 @@ function dfrn_notify_post(App $a) {
$data = json_decode($postdata); $data = json_decode($postdata);
if (is_object($data)) { if (is_object($data)) {
$nick = defaults($a->argv, 1, ''); $nick = defaults($a->argv, 1, '');
$user = dba::selectFirst('user', [], ['nickname' => $nick, 'account_expired' => false, 'account_removed' => false]); $user = dba::selectFirst('user', [], ['nickname' => $nick, 'account_expired' => false, 'account_removed' => false]);
if (!DBM::is_result($user)) { if (!DBM::is_result($user)) {
System::httpExit(500); System::httpExit(500);
} }
$msg = Diaspora::decodeRaw($user, $postdata); dfrn_dispatch_private($user, $postdata);
} elseif (!dfrn_dispatch_public($postdata)) {
// Check if the user has got this contact
$cid = Contact::getIdForURL($msg['author'], $user['uid']);
if (!$cid) {
// Otherwise there should be a public contact
$cid = Contact::getIdForURL($msg['author']);
if (!$cid) {
logger('Contact not found for address ' . $msg['author']);
System::xmlExit(3, 'Contact not found');
}
}
// We now have some contact, so we fetch it
$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($importer)) {
logger('Contact not found for address ' . $msg['author']);
System::xmlExit(3, 'Contact not found');
}
// Set the user id. This is important if this is a public contact
$importer['importer_uid'] = $user['uid'];
// Now we should be able to import it
$ret = DFRN::import($msg['message'], $importer);
System::xmlExit($ret, 'Done');
} else {
require_once 'mod/salmon.php'; require_once 'mod/salmon.php';
salmon_post($a, $postdata); salmon_post($a, $postdata);
} }
@ -91,19 +62,12 @@ function dfrn_notify_post(App $a) {
$dfrn_id = substr($dfrn_id, 2); $dfrn_id = substr($dfrn_id, 2);
} }
$r = q("SELECT * FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", if (!dba::exists('challenge', ['dfrn-id' => $dfrn_id, 'challenge' => $challenge])) {
dbesc($dfrn_id), logger('could not match challenge to dfrn_id ' . $dfrn_id . ' challenge=' . $challenge);
dbesc($challenge)
);
if (! DBM::is_result($r)) {
logger('dfrn_notify: could not match challenge to dfrn_id ' . $dfrn_id . ' challenge=' . $challenge);
System::xmlExit(3, 'Could not match challenge'); System::xmlExit(3, 'Could not match challenge');
} }
$r = q("DELETE FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s'", dba::delete('challenge', ['dfrn-id' => $dfrn_id, 'challenge' => $challenge]);
dbesc($dfrn_id),
dbesc($challenge)
);
// find the local user who owns this relationship. // find the local user who owns this relationship.
@ -143,8 +107,8 @@ function dfrn_notify_post(App $a) {
dbesc($a->argv[1]) dbesc($a->argv[1])
); );
if (! DBM::is_result($r)) { if (!DBM::is_result($r)) {
logger('dfrn_notify: contact not found for dfrn_id ' . $dfrn_id); logger('contact not found for dfrn_id ' . $dfrn_id);
System::xmlExit(3, 'Contact not found'); System::xmlExit(3, 'Contact not found');
//NOTREACHED //NOTREACHED
} }
@ -153,15 +117,11 @@ function dfrn_notify_post(App $a) {
$importer = $r[0]; $importer = $r[0];
logger("Remote rino version: ".$rino_remote." for ".$importer["url"], LOGGER_DEBUG);
if ((($writable != (-1)) && ($writable != $importer['writable'])) || ($importer['forum'] != $forum) || ($importer['prv'] != $prv)) { if ((($writable != (-1)) && ($writable != $importer['writable'])) || ($importer['forum'] != $forum) || ($importer['prv'] != $prv)) {
q("UPDATE `contact` SET `writable` = %d, forum = %d, prv = %d WHERE `id` = %d", $fields = ['writable' => ($writable == (-1)) ? $importer['writable'] : $writable,
intval(($writable == (-1)) ? $importer['writable'] : $writable), 'forum' => $forum, 'prv' => $prv];
intval($forum), dba::update('contact', $fields, ['id' => $importer['id']]);
intval($prv),
intval($importer['id'])
);
if ($writable != (-1)) { if ($writable != (-1)) {
$importer['writable'] = $writable; $importer['writable'] = $writable;
} }
@ -173,8 +133,7 @@ function dfrn_notify_post(App $a) {
$importer = Contact::updateSslPolicy($importer, $ssl_policy); $importer = Contact::updateSslPolicy($importer, $ssl_policy);
logger('dfrn_notify: received notify from ' . $importer['name'] . ' for ' . $importer['username']); logger('data: ' . $data, LOGGER_DATA);
logger('dfrn_notify: data: ' . $data, LOGGER_DATA);
if ($dissolve == 1) { if ($dissolve == 1) {
// Relationship is dissolved permanently // Relationship is dissolved permanently
@ -186,8 +145,6 @@ function dfrn_notify_post(App $a) {
$rino = Config::get('system', 'rino_encrypt'); $rino = Config::get('system', 'rino_encrypt');
$rino = intval($rino); $rino = intval($rino);
logger("Local rino version: " . $rino, LOGGER_DEBUG);
if (strlen($key)) { if (strlen($key)) {
// if local rino is lower than remote rino, abort: should not happen! // if local rino is lower than remote rino, abort: should not happen!
@ -198,24 +155,25 @@ function dfrn_notify_post(App $a) {
} }
$rawkey = hex2bin(trim($key)); $rawkey = hex2bin(trim($key));
logger('rino: md5 raw key: ' . md5($rawkey)); logger('rino: md5 raw key: ' . md5($rawkey), LOGGER_DATA);
$final_key = ''; $final_key = '';
if ($dfrn_version >= 2.1) { if ($dfrn_version >= 2.1) {
if ((($importer['duplex']) && strlen($importer['cprvkey'])) || (! strlen($importer['cpubkey']))) { if (($importer['duplex'] && strlen($importer['cprvkey'])) || !strlen($importer['cpubkey'])) {
openssl_private_decrypt($rawkey, $final_key, $importer['cprvkey']); openssl_private_decrypt($rawkey, $final_key, $importer['cprvkey']);
} else { } else {
openssl_public_decrypt($rawkey, $final_key, $importer['cpubkey']); openssl_public_decrypt($rawkey, $final_key, $importer['cpubkey']);
} }
} else { } else {
if ((($importer['duplex']) && strlen($importer['cpubkey'])) || (! strlen($importer['cprvkey']))) { if (($importer['duplex'] && strlen($importer['cpubkey'])) || !strlen($importer['cprvkey'])) {
openssl_public_decrypt($rawkey, $final_key, $importer['cpubkey']); openssl_public_decrypt($rawkey, $final_key, $importer['cpubkey']);
} else { } else {
openssl_private_decrypt($rawkey, $final_key, $importer['cprvkey']); openssl_private_decrypt($rawkey, $final_key, $importer['cprvkey']);
} }
} }
switch($rino_remote) { switch ($rino_remote) {
case 0: case 0:
case 1: case 1:
// we got a key. old code send only the key, without RINO version. // we got a key. old code send only the key, without RINO version.
@ -230,16 +188,93 @@ function dfrn_notify_post(App $a) {
logger('rino: decrypted data: ' . $data, LOGGER_DATA); logger('rino: decrypted data: ' . $data, LOGGER_DATA);
} }
logger('Importing post from ' . $importer['addr'] . ' to ' . $importer['nickname'] . ' with the RINO ' . $rino_remote . ' encryption.', LOGGER_DEBUG);
$ret = DFRN::import($data, $importer); $ret = DFRN::import($data, $importer);
System::xmlExit($ret, 'Processed'); System::xmlExit($ret, 'Processed');
// NOTREACHED // NOTREACHED
} }
function dfrn_dispatch_public($postdata)
{
$msg = Diaspora::decodeRaw([], $postdata);
if (!$msg) {
// We have to fail silently to be able to hand it over to the salmon parser
return false;
}
// Fetch the corresponding public contact
$contact = Contact::getDetailsByAddr($msg['author'], 0);
if (!$contact) {
logger('Contact not found for address ' . $msg['author']);
System::xmlExit(3, 'Contact not found');
}
// We now have some contact, so we fetch it
$importer = dba::fetch_first("SELECT *, `name` as `senderName`
FROM `contact`
WHERE NOT `blocked` AND `id` = ? LIMIT 1",
$contact['id']);
$importer['importer_uid'] = 0;
// This should never fail
if (!DBM::is_result($importer)) {
logger('Contact not found for address ' . $msg['author']);
System::xmlExit(3, 'Contact not found');
}
logger('Importing post from ' . $msg['author'] . ' with the public envelope.', LOGGER_DEBUG);
// Now we should be able to import it
$ret = DFRN::import($msg['message'], $importer);
System::xmlExit($ret, 'Done');
}
function dfrn_dispatch_private($user, $postdata)
{
$msg = Diaspora::decodeRaw($user, $postdata);
if (!$msg) {
System::xmlExit(4, 'Unable to parse message');
}
// Check if the user has got this contact
$cid = Contact::getIdForURL($msg['author'], $user['uid']);
if (!$cid) {
// Otherwise there should be a public contact
$cid = Contact::getIdForURL($msg['author']);
if (!$cid) {
logger('Contact not found for address ' . $msg['author']);
System::xmlExit(3, 'Contact not found');
}
}
// We now have some contact, so we fetch it
$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($importer)) {
logger('Contact not found for address ' . $msg['author']);
System::xmlExit(3, 'Contact not found');
}
// Set the user id. This is important if this is a public contact
$importer['importer_uid'] = $user['uid'];
logger('Importing post from ' . $msg['author'] . ' to ' . $user['nickname'] . ' with the private envelope.', LOGGER_DEBUG);
// Now we should be able to import it
$ret = DFRN::import($msg['message'], $importer);
System::xmlExit($ret, 'Done');
}
function dfrn_notify_content(App $a) { function dfrn_notify_content(App $a) {
if(x($_GET,'dfrn_id')) { if (x($_GET,'dfrn_id')) {
/* /*
* initial communication from external contact, $direction is their direction. * initial communication from external contact, $direction is their direction.
@ -252,10 +287,10 @@ function dfrn_notify_content(App $a) {
$type = ""; $type = "";
$last_update = ""; $last_update = "";
logger('dfrn_notify: new notification dfrn_id=' . $dfrn_id); logger('new notification dfrn_id=' . $dfrn_id);
$direction = (-1); $direction = (-1);
if(strpos($dfrn_id,':') == 1) { if (strpos($dfrn_id,':') == 1) {
$direction = intval(substr($dfrn_id,0,1)); $direction = intval(substr($dfrn_id,0,1));
$dfrn_id = substr($dfrn_id,2); $dfrn_id = substr($dfrn_id,2);
} }
@ -264,23 +299,18 @@ function dfrn_notify_content(App $a) {
$status = 0; $status = 0;
$r = q("DELETE FROM `challenge` WHERE `expire` < " . intval(time())); dba::delete('challenge', ["`expire` < ?", time()]);
$r = q("INSERT INTO `challenge` ( `challenge`, `dfrn-id`, `expire` , `type`, `last_update` ) $fields = ['challenge' => $hash, 'dfrn-id' => $dfrn_id, 'expire' => time() + 90,
VALUES( '%s', '%s', %d, '%s', '%s' ) ", 'type' => $type, 'last_update' => $last_update];
dbesc($hash), dba::insert('challenge', $fields);
dbesc($dfrn_id),
intval(time() + 90 ),
dbesc($type),
dbesc($last_update)
);
logger('dfrn_notify: challenge=' . $hash, LOGGER_DEBUG); logger('challenge=' . $hash, LOGGER_DATA);
$sql_extra = ''; $sql_extra = '';
switch($direction) { switch($direction) {
case (-1): case (-1):
$sql_extra = sprintf(" AND ( `issued-id` = '%s' OR `dfrn-id` = '%s' ) ", dbesc($dfrn_id), dbesc($dfrn_id)); $sql_extra = sprintf(" AND (`issued-id` = '%s' OR `dfrn-id` = '%s') ", dbesc($dfrn_id), dbesc($dfrn_id));
$my_id = $dfrn_id; $my_id = $dfrn_id;
break; break;
case 0: case 0:
@ -302,11 +332,11 @@ function dfrn_notify_content(App $a) {
dbesc($a->argv[1]) dbesc($a->argv[1])
); );
if (! DBM::is_result($r)) { if (!DBM::is_result($r)) {
$status = 1; $status = 1;
} }
logger("Remote rino version: ".$rino_remote." for ".$r[0]["url"], LOGGER_DEBUG); logger("Remote rino version: ".$rino_remote." for ".$r[0]["url"], LOGGER_DATA);
$challenge = ''; $challenge = '';
$encrypted_id = ''; $encrypted_id = '';
@ -316,7 +346,7 @@ function dfrn_notify_content(App $a) {
$pub_key = trim($r[0]['pubkey']); $pub_key = trim($r[0]['pubkey']);
$dplx = intval($r[0]['duplex']); $dplx = intval($r[0]['duplex']);
if ((($dplx) && (strlen($prv_key))) || ((strlen($prv_key)) && (!(strlen($pub_key))))) { if (($dplx && strlen($prv_key)) || (strlen($prv_key) && !strlen($pub_key))) {
openssl_private_encrypt($hash, $challenge, $prv_key); openssl_private_encrypt($hash, $challenge, $prv_key);
openssl_private_encrypt($id_str, $encrypted_id, $prv_key); openssl_private_encrypt($id_str, $encrypted_id, $prv_key);
} elseif (strlen($pub_key)) { } elseif (strlen($pub_key)) {
@ -334,7 +364,7 @@ function dfrn_notify_content(App $a) {
$rino = Config::get('system', 'rino_encrypt'); $rino = Config::get('system', 'rino_encrypt');
$rino = intval($rino); $rino = intval($rino);
logger("Local rino version: ". $rino, LOGGER_DEBUG); logger("Local rino version: ". $rino, LOGGER_DATA);
// if requested rino is lower than enabled local rino, lower local rino version // if requested rino is lower than enabled local rino, lower local rino version
// if requested rino is higher than enabled local rino, reply with local rino // if requested rino is higher than enabled local rino, reply with local rino
@ -342,7 +372,7 @@ function dfrn_notify_content(App $a) {
$rino = $rino_remote; $rino = $rino_remote;
} }
if((($r[0]['rel']) && ($r[0]['rel'] != CONTACT_IS_SHARING)) || ($r[0]['page-flags'] == PAGE_COMMUNITY)) { if (($r[0]['rel'] && ($r[0]['rel'] != CONTACT_IS_SHARING)) || ($r[0]['page-flags'] == PAGE_COMMUNITY)) {
$perm = 'rw'; $perm = 'rw';
} else { } else {
$perm = 'r'; $perm = 'r';
@ -362,5 +392,4 @@ function dfrn_notify_content(App $a) {
killme(); killme();
} }
} }

View file

@ -116,14 +116,14 @@ function friendica_content(App $a)
} else { } else {
$o .= '<p>' . L10n::t('No installed addons/apps') . '</p>' . PHP_EOL; $o .= '<p>' . L10n::t('No installed addons/apps') . '</p>' . PHP_EOL;
} }
if (Config::get('system', 'tosdisplay')) if (Config::get('system', 'tosdisplay'))
{ {
$o .= '<p>'.L10n::t('Read about the <a href="%1$s/tos">Terms of Service</a> of this node.', System::baseurl()).'</p>'; $o .= '<p>'.L10n::t('Read about the <a href="%1$s/tos">Terms of Service</a> of this node.', System::baseurl()).'</p>';
} }
$blocklist = Config::get('system', 'blocklist'); $blocklist = Config::get('system', 'blocklist', []);
if (count($blocklist)) { if (!empty($blocklist)) {
$o .= '<div id="about_blocklist"><p>' . L10n::t('On this server the following remote servers are blocked.') . '</p>' . PHP_EOL; $o .= '<div id="about_blocklist"><p>' . L10n::t('On this server the following remote servers are blocked.') . '</p>' . PHP_EOL;
$o .= '<table class="table"><thead><tr><th>' . L10n::t('Blocked domain') . '</th><th>' . L10n::t('Reason for the block') . '</th></thead><tbody>' . PHP_EOL; $o .= '<table class="table"><thead><tr><th>' . L10n::t('Blocked domain') . '</th><th>' . L10n::t('Reason for the block') . '</th></thead><tbody>' . PHP_EOL;
foreach ($blocklist as $b) { foreach ($blocklist as $b) {

View file

@ -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)) { if (!dba::connect($dbhost, $dbuser, $dbpass, $dbdata, true)) {
$a->data['db_conn_failed'] = true; $a->data['db_conn_failed'] = true;
} }
@ -140,11 +140,37 @@ 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']));
} }
list($checks, $checkspassed) = Install::check($phpath); check_php($phpath, $checks);
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, [

View file

@ -144,14 +144,13 @@ function invite_content(App $a) {
$o = replace_macros($tpl, [ $o = replace_macros($tpl, [
'$form_security_token' => get_form_security_token("send_invite"), '$form_security_token' => get_form_security_token("send_invite"),
'$invite' => L10n::t('Send invitations'), '$title' => L10n::t('Send invitations'),
'$addr_text' => L10n::t('Enter email addresses, one per line:'), '$recipients' => ['recipients', L10n::t('Enter email addresses, one per line:')],
'$msg_text' => L10n::t('Your message:'), '$message' => ['message', L10n::t('Your message:'),L10n::t('You are cordially invited to join me and other close friends on Friendica - and help us to create a better social web.') . "\r\n" . "\r\n"
'$default_message' => L10n::t('You are cordially invited to join me and other close friends on Friendica - and help us to create a better social web.') . "\r\n" . "\r\n"
. $linktxt . $linktxt
. "\r\n" . "\r\n" . (($invonly) ? L10n::t('You will need to supply this invitation code: $invite_code') . "\r\n" . "\r\n" : '') .L10n::t('Once you have registered, please connect with me via my profile page at:') . "\r\n" . "\r\n" . (($invonly) ? L10n::t('You will need to supply this invitation code: $invite_code') . "\r\n" . "\r\n" : '') .L10n::t('Once you have registered, please connect with me via my profile page at:')
. "\r\n" . "\r\n" . System::baseUrl() . '/profile/' . $a->user['nickname'] . "\r\n" . "\r\n" . System::baseUrl() . '/profile/' . $a->user['nickname']
. "\r\n" . "\r\n" . L10n::t('For more information about the Friendica project and why we feel it is important, please visit http://friendi.ca') . "\r\n" . "\r\n" , . "\r\n" . "\r\n" . L10n::t('For more information about the Friendica project and why we feel it is important, please visit http://friendi.ca') . "\r\n" . "\r\n"],
'$submit' => L10n::t('Submit') '$submit' => L10n::t('Submit')
]); ]);

View file

@ -23,9 +23,18 @@ function noscrape_init(App $a)
Profile::load($a, $which, $profile); Profile::load($a, $which, $profile);
$json_info = [
'addr' => $a->profile['addr'],
'nick' => $which,
'guid' => $a->profile['guid'],
'key' => $a->profile['pubkey'],
'homepage' => System::baseUrl()."/profile/{$which}",
'comm' => ($a->profile['account-type'] == ACCOUNT_TYPE_COMMUNITY),
];
if (!$a->profile['net-publish'] || $a->profile['hidewall']) { if (!$a->profile['net-publish'] || $a->profile['hidewall']) {
header('Content-type: application/json; charset=utf-8'); header('Content-type: application/json; charset=utf-8');
$json_info = ["hide" => true]; $json_info["hide"] = true;
echo json_encode($json_info); echo json_encode($json_info);
exit; exit;
} }
@ -36,17 +45,9 @@ function noscrape_init(App $a)
$contactPhoto = dba::selectFirst('contact', ['photo'], ['self' => true, 'uid' => $a->profile['uid']]); $contactPhoto = dba::selectFirst('contact', ['photo'], ['self' => true, 'uid' => $a->profile['uid']]);
$json_info = [ $json_info['fn'] = $a->profile['name'];
'fn' => $a->profile['name'], $json_info['photo'] = $contactPhoto["photo"];
'addr' => $a->profile['addr'], $json_info['tags'] = $keywords;
'nick' => $which,
'guid' => $a->profile['guid'],
'key' => $a->profile['pubkey'],
'homepage' => System::baseUrl()."/profile/{$which}",
'comm' => (x($a->profile, 'page-flags')) && ($a->profile['page-flags'] == PAGE_COMMUNITY),
'photo' => $contactPhoto["photo"],
'tags' => $keywords
];
if (is_array($a->profile) && !$a->profile['hide-friends']) { if (is_array($a->profile) && !$a->profile['hide-friends']) {
/// @todo What should this value tell us? /// @todo What should this value tell us?

View file

@ -191,7 +191,7 @@ function profile_content(App $a, $update = 0)
$o .= Widget::commonFriendsVisitor($a->profile['profile_uid']); $o .= Widget::commonFriendsVisitor($a->profile['profile_uid']);
if (x($_SESSION, 'new_member') && $is_owner) { if (x($_SESSION, 'new_member') && $is_owner) {
$o .= '<a href="newmember" id="newmember-tips" style="font-size: 1.2em;"><b>' . L10n::t('Tips for New Members') . '</b></a>' . EOL; $o .= '<div id="newmember-tips"><a href="newmember"><b>' . L10n::t('Tips for New Members') . '</b></a></div>';
} }
$commpage = $a->profile['page-flags'] == PAGE_COMMUNITY; $commpage = $a->profile['page-flags'] == PAGE_COMMUNITY;

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

@ -49,7 +49,7 @@ class ForumManager
"SELECT `contact`.`id`, `contact`.`url`, `contact`.`name`, `contact`.`micro`, `contact`.`thumb` "SELECT `contact`.`id`, `contact`.`url`, `contact`.`name`, `contact`.`micro`, `contact`.`thumb`
FROM `contact` FROM `contact`
WHERE `network`= 'dfrn' AND $select AND `uid` = ? WHERE `network`= 'dfrn' AND $select AND `uid` = ?
AND NOT `blocked` AND NOT `hidden` AND NOT `pending` AND NOT `archive` AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND `success_update` > `failure_update` AND `success_update` > `failure_update`
$order ", $order ",
$uid $uid

View file

@ -28,23 +28,23 @@ class Nav
if (!(x($a->page, 'nav'))) { if (!(x($a->page, 'nav'))) {
$a->page['nav'] = ''; $a->page['nav'] = '';
} }
$a->page['htmlhead'] .= replace_macros(get_markup_template('nav_head.tpl'), []); $a->page['htmlhead'] .= replace_macros(get_markup_template('nav_head.tpl'), []);
/* /*
* Placeholder div for popup panel * Placeholder div for popup panel
*/ */
$a->page['nav'] .= '<div id="panel" style="display: none;"></div>' ; $a->page['nav'] .= '<div id="panel" style="display: none;"></div>' ;
$nav_info = self::getInfo($a); $nav_info = self::getInfo($a);
/* /*
* Build the page * Build the page
*/ */
$tpl = get_markup_template('nav.tpl'); $tpl = get_markup_template('nav.tpl');
$a->page['nav'] .= replace_macros($tpl, [ $a->page['nav'] .= replace_macros($tpl, [
'$baseurl' => System::baseUrl(), '$baseurl' => System::baseUrl(),
'$sitelocation' => $nav_info['sitelocation'], '$sitelocation' => $nav_info['sitelocation'],
@ -57,10 +57,10 @@ class Nav
'$clear_notifs' => L10n::t('Clear notifications'), '$clear_notifs' => L10n::t('Clear notifications'),
'$search_hint' => L10n::t('@name, !forum, #tags, content') '$search_hint' => L10n::t('@name, !forum, #tags, content')
]); ]);
Addon::callHooks('page_header', $a->page['nav']); Addon::callHooks('page_header', $a->page['nav']);
} }
/** /**
* Prepares a list of navigation links * Prepares a list of navigation links
* *
@ -75,27 +75,27 @@ class Nav
private static function getInfo(App $a) private static function getInfo(App $a)
{ {
$ssl_state = ((local_user()) ? true : false); $ssl_state = ((local_user()) ? true : false);
/* /*
* Our network is distributed, and as you visit friends some of the * Our network is distributed, and as you visit friends some of the
* sites look exactly the same - it isn't always easy to know where you are. * sites look exactly the same - it isn't always easy to know where you are.
* Display the current site location as a navigation aid. * Display the current site location as a navigation aid.
*/ */
$myident = ((is_array($a->user) && isset($a->user['nickname'])) ? $a->user['nickname'] . '@' : ''); $myident = ((is_array($a->user) && isset($a->user['nickname'])) ? $a->user['nickname'] . '@' : '');
$sitelocation = $myident . substr(System::baseUrl($ssl_state), strpos(System::baseUrl($ssl_state), '//') + 2); $sitelocation = $myident . substr(System::baseUrl($ssl_state), strpos(System::baseUrl($ssl_state), '//') + 2);
// nav links: array of array('href', 'text', 'extra css classes', 'title') // nav links: array of array('href', 'text', 'extra css classes', 'title')
$nav = []; $nav = [];
// Display login or logout // Display login or logout
$nav['usermenu'] = []; $nav['usermenu'] = [];
$userinfo = null; $userinfo = null;
if (local_user()) { if (local_user()) {
$nav['logout'] = ['logout', L10n::t('Logout'), '', L10n::t('End this session')]; $nav['logout'] = ['logout', L10n::t('Logout'), '', L10n::t('End this session')];
// user menu // user menu
$nav['usermenu'][] = ['profile/' . $a->user['nickname'], L10n::t('Status'), '', L10n::t('Your posts and conversations')]; $nav['usermenu'][] = ['profile/' . $a->user['nickname'], L10n::t('Status'), '', L10n::t('Your posts and conversations')];
$nav['usermenu'][] = ['profile/' . $a->user['nickname'] . '?tab=profile', L10n::t('Profile'), '', L10n::t('Your profile page')]; $nav['usermenu'][] = ['profile/' . $a->user['nickname'] . '?tab=profile', L10n::t('Profile'), '', L10n::t('Your profile page')];
@ -103,7 +103,7 @@ class Nav
$nav['usermenu'][] = ['videos/' . $a->user['nickname'], L10n::t('Videos'), '', L10n::t('Your videos')]; $nav['usermenu'][] = ['videos/' . $a->user['nickname'], L10n::t('Videos'), '', L10n::t('Your videos')];
$nav['usermenu'][] = ['events/', L10n::t('Events'), '', L10n::t('Your events')]; $nav['usermenu'][] = ['events/', L10n::t('Events'), '', L10n::t('Your events')];
$nav['usermenu'][] = ['notes/', L10n::t('Personal notes'), '', L10n::t('Your personal notes')]; $nav['usermenu'][] = ['notes/', L10n::t('Personal notes'), '', L10n::t('Your personal notes')];
// user info // user info
$contact = dba::selectFirst('contact', ['micro'], ['uid' => $a->user['uid'], 'self' => true]); $contact = dba::selectFirst('contact', ['micro'], ['uid' => $a->user['uid'], 'self' => true]);
$userinfo = [ $userinfo = [
@ -113,120 +113,117 @@ class Nav
} else { } else {
$nav['login'] = ['login', L10n::t('Login'), ($a->module == 'login' ? 'selected' : ''), L10n::t('Sign in')]; $nav['login'] = ['login', L10n::t('Login'), ($a->module == 'login' ? 'selected' : ''), L10n::t('Sign in')];
} }
// "Home" should also take you home from an authenticated remote profile connection // "Home" should also take you home from an authenticated remote profile connection
$homelink = Profile::getMyURL(); $homelink = Profile::getMyURL();
if (! $homelink) { if (! $homelink) {
$homelink = ((x($_SESSION, 'visitor_home')) ? $_SESSION['visitor_home'] : ''); $homelink = ((x($_SESSION, 'visitor_home')) ? $_SESSION['visitor_home'] : '');
} }
if (($a->module != 'home') && (! (local_user()))) { if (($a->module != 'home') && (! (local_user()))) {
$nav['home'] = [$homelink, L10n::t('Home'), '', L10n::t('Home Page')]; $nav['home'] = [$homelink, L10n::t('Home'), '', L10n::t('Home Page')];
} }
if (($a->config['register_policy'] == REGISTER_OPEN) && (! local_user()) && (! remote_user())) { if (($a->config['register_policy'] == REGISTER_OPEN) && (! local_user()) && (! remote_user())) {
$nav['register'] = ['register', L10n::t('Register'), '', L10n::t('Create an account')]; $nav['register'] = ['register', L10n::t('Register'), '', L10n::t('Create an account')];
} }
$help_url = 'help'; $help_url = 'help';
if (!Config::get('system', 'hide_help')) { if (!Config::get('system', 'hide_help')) {
$nav['help'] = [$help_url, L10n::t('Help'), '', L10n::t('Help and documentation')]; $nav['help'] = [$help_url, L10n::t('Help'), '', L10n::t('Help and documentation')];
} }
if (count($a->apps) > 0) { if (count($a->apps) > 0) {
$nav['apps'] = ['apps', L10n::t('Apps'), '', L10n::t('Addon applications, utilities, games')]; $nav['apps'] = ['apps', L10n::t('Apps'), '', L10n::t('Addon applications, utilities, games')];
} }
if (local_user() || !Config::get('system', 'local_search')) { if (local_user() || !Config::get('system', 'local_search')) {
$nav['search'] = ['search', L10n::t('Search'), '', L10n::t('Search site content')]; $nav['search'] = ['search', L10n::t('Search'), '', L10n::t('Search site content')];
$nav['searchoption'] = [ $nav['searchoption'] = [
L10n::t('Full Text'), L10n::t('Full Text'),
L10n::t('Tags'), L10n::t('Tags'),
L10n::t('Contacts') L10n::t('Contacts')
]; ];
if (Config::get('system', 'poco_local_search')) { if (Config::get('system', 'poco_local_search')) {
$nav['searchoption'][] = L10n::t('Forums'); $nav['searchoption'][] = L10n::t('Forums');
} }
} }
$gdirpath = 'directory'; $gdirpath = 'directory';
if (strlen(Config::get('system', 'singleuser'))) { if (strlen(Config::get('system', 'singleuser'))) {
$gdir = Config::get('system', 'directory'); $gdir = Config::get('system', 'directory');
if (strlen($gdir)) { if (strlen($gdir)) {
$gdirpath = Profile::zrl($gdir, true); $gdirpath = Profile::zrl($gdir, true);
} }
} }
if (local_user() || Config::get('system', 'community_page_style') != CP_NO_COMMUNITY_PAGE) { if ((local_user() || Config::get('system', 'community_page_style') != CP_NO_COMMUNITY_PAGE) &&
!(Config::get('system', 'community_page_style') == CP_NO_INTERNAL_COMMUNITY)) {
$nav['community'] = ['community', L10n::t('Community'), '', L10n::t('Conversations on this and other servers')]; $nav['community'] = ['community', L10n::t('Community'), '', L10n::t('Conversations on this and other servers')];
} }
if (local_user()) { if (local_user()) {
$nav['events'] = ['events', L10n::t('Events'), '', L10n::t('Events and Calendar')]; $nav['events'] = ['events', L10n::t('Events'), '', L10n::t('Events and Calendar')];
} }
$nav['directory'] = [$gdirpath, L10n::t('Directory'), '', L10n::t('People directory')]; $nav['directory'] = [$gdirpath, L10n::t('Directory'), '', L10n::t('People directory')];
$nav['about'] = ['friendica', L10n::t('Information'), '', L10n::t('Information about this friendica instance')]; $nav['about'] = ['friendica', L10n::t('Information'), '', L10n::t('Information about this friendica instance')];
// The following nav links are only show to logged in users // The following nav links are only show to logged in users
if (local_user()) { if (local_user()) {
$nav['network'] = ['network', L10n::t('Network'), '', L10n::t('Conversations from your friends')]; $nav['network'] = ['network', L10n::t('Network'), '', L10n::t('Conversations from your friends')];
$nav['net_reset'] = ['network/0?f=&order=comment&nets=all', L10n::t('Network Reset'), '', L10n::t('Load Network page with no filters')]; $nav['net_reset'] = ['network/0?f=&order=comment&nets=all', L10n::t('Network Reset'), '', L10n::t('Load Network page with no filters')];
$nav['home'] = ['profile/' . $a->user['nickname'], L10n::t('Home'), '', L10n::t('Your posts and conversations')]; $nav['home'] = ['profile/' . $a->user['nickname'], L10n::t('Home'), '', L10n::t('Your posts and conversations')];
if (in_array($_SESSION['page_flags'], [PAGE_NORMAL, PAGE_SOAPBOX, PAGE_FREELOVE, PAGE_PRVGROUP])) { // Don't show notifications for public communities
// only show friend requests for normal pages. Other page types have automatic friendship. if ($_SESSION['page_flags'] != PAGE_COMMUNITY) {
if (in_array($_SESSION['page_flags'], [PAGE_NORMAL, PAGE_SOAPBOX, PAGE_PRVGROUP])) { $nav['introductions'] = ['notifications/intros', L10n::t('Introductions'), '', L10n::t('Friend Requests')];
$nav['introductions'] = ['notifications/intros', L10n::t('Introductions'), '', L10n::t('Friend Requests')]; $nav['notifications'] = ['notifications', L10n::t('Notifications'), '', L10n::t('Notifications')];
} $nav['notifications']['all'] = ['notifications/system', L10n::t('See all notifications'), '', ''];
if (in_array($_SESSION['page_flags'], [PAGE_NORMAL, PAGE_SOAPBOX, PAGE_FREELOVE])) { $nav['notifications']['mark'] = ['', L10n::t('Mark as seen'), '', L10n::t('Mark all system notifications seen')];
$nav['notifications'] = ['notifications', L10n::t('Notifications'), '', L10n::t('Notifications')];
$nav['notifications']['all'] = ['notifications/system', L10n::t('See all notifications'), '', ''];
$nav['notifications']['mark'] = ['', L10n::t('Mark as seen'), '', L10n::t('Mark all system notifications seen')];
}
} }
$nav['messages'] = ['message', L10n::t('Messages'), '', L10n::t('Private mail')]; $nav['messages'] = ['message', L10n::t('Messages'), '', L10n::t('Private mail')];
$nav['messages']['inbox'] = ['message', L10n::t('Inbox'), '', L10n::t('Inbox')]; $nav['messages']['inbox'] = ['message', L10n::t('Inbox'), '', L10n::t('Inbox')];
$nav['messages']['outbox'] = ['message/sent', L10n::t('Outbox'), '', L10n::t('Outbox')]; $nav['messages']['outbox'] = ['message/sent', L10n::t('Outbox'), '', L10n::t('Outbox')];
$nav['messages']['new'] = ['message/new', L10n::t('New Message'), '', L10n::t('New Message')]; $nav['messages']['new'] = ['message/new', L10n::t('New Message'), '', L10n::t('New Message')];
if (is_array($a->identities) && count($a->identities) > 1) { if (is_array($a->identities) && count($a->identities) > 1) {
$nav['manage'] = ['manage', L10n::t('Manage'), '', L10n::t('Manage other pages')]; $nav['manage'] = ['manage', L10n::t('Manage'), '', L10n::t('Manage other pages')];
} }
$nav['delegations'] = ['delegate', L10n::t('Delegations'), '', L10n::t('Delegate Page Management')]; $nav['delegations'] = ['delegate', L10n::t('Delegations'), '', L10n::t('Delegate Page Management')];
$nav['settings'] = ['settings', L10n::t('Settings'), '', L10n::t('Account settings')]; $nav['settings'] = ['settings', L10n::t('Settings'), '', L10n::t('Account settings')];
if (Feature::isEnabled(local_user(), 'multi_profiles')) { if (Feature::isEnabled(local_user(), 'multi_profiles')) {
$nav['profiles'] = ['profiles', L10n::t('Profiles'), '', L10n::t('Manage/Edit Profiles')]; $nav['profiles'] = ['profiles', L10n::t('Profiles'), '', L10n::t('Manage/Edit Profiles')];
} }
$nav['contacts'] = ['contacts', L10n::t('Contacts'), '', L10n::t('Manage/edit friends and contacts')]; $nav['contacts'] = ['contacts', L10n::t('Contacts'), '', L10n::t('Manage/edit friends and contacts')];
} }
// Show the link to the admin configuration page if user is admin // Show the link to the admin configuration page if user is admin
if (is_site_admin()) { if (is_site_admin()) {
$nav['admin'] = ['admin/', L10n::t('Admin'), '', L10n::t('Site setup and configuration')]; $nav['admin'] = ['admin/', L10n::t('Admin'), '', L10n::t('Site setup and configuration')];
} }
$nav['navigation'] = ['navigation/', L10n::t('Navigation'), '', L10n::t('Site map')]; $nav['navigation'] = ['navigation/', L10n::t('Navigation'), '', L10n::t('Site map')];
// Provide a banner/logo/whatever // Provide a banner/logo/whatever
$banner = Config::get('system', 'banner'); $banner = Config::get('system', 'banner');
if (is_null($banner)) { if (is_null($banner)) {
$banner = '<a href="https://friendi.ca"><img id="logo-img" src="images/friendica-32.png" alt="logo" /></a><span id="logo-text"><a href="https://friendi.ca">Friendica</a></span>'; $banner = '<a href="https://friendi.ca"><img id="logo-img" src="images/friendica-32.png" alt="logo" /></a><span id="logo-text"><a href="https://friendi.ca">Friendica</a></span>';
} }
Addon::callHooks('nav_info', $nav); Addon::callHooks('nav_info', $nav);
return [ return [
'sitelocation' => $sitelocation, 'sitelocation' => $sitelocation,
'nav' => $nav, 'nav' => $nav,
@ -234,7 +231,7 @@ class Nav
'userinfo' => $userinfo, 'userinfo' => $userinfo,
]; ];
} }
/** /**
* Set a menu item in navbar as selected * Set a menu item in navbar as selected
*/ */

View file

@ -343,159 +343,20 @@ class BBCode extends BaseObject
} }
/** /**
* @brief Convert a message into plaintext for connectors to other networks * @brief Converts a BBCode text into plaintext
* *
* @param array $b The message array that is about to be posted * @param bool $keep_urls Whether to keep URLs in the resulting plaintext
* @param int $limit The maximum number of characters when posting to that network
* @param bool $includedlinks Has an attached link to be included into the message?
* @param int $htmlmode This triggers the behaviour of the bbcode conversion
* @param string $target_network Name of the network where the post should go to.
* *
* @return string The converted message * @return string
*/ */
public static function toPlaintext($b, $limit = 0, $includedlinks = false, $htmlmode = 2, $target_network = "") public static function toPlaintext($text, $keep_urls = true)
{ {
// Remove the hash tags $naked_text = preg_replace('/\[(.+?)\]/','', $text);
$URLSearchString = "^\[\]"; if (!$keep_urls) {
$body = preg_replace("/([#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $b["body"]); $naked_text = preg_replace('#https?\://[^\s<]+[^\s\.\)]#i', '', $naked_text);
// Add an URL element if the text contains a raw link
$body = preg_replace("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url]$2[/url]', $body);
// Remove the abstract
$body = self::stripAbstract($body);
// At first look at data that is attached via "type-..." stuff
// This will hopefully replaced with a dedicated bbcode later
//$post = self::getAttachedData($b["body"]);
$post = self::getAttachedData($body, $b);
if (($b["title"] != "") && ($post["text"] != "")) {
$post["text"] = trim($b["title"]."\n\n".$post["text"]);
} elseif ($b["title"] != "") {
$post["text"] = trim($b["title"]);
} }
$abstract = ""; return $naked_text;
// Fetch the abstract from the given target network
if ($target_network != "") {
$default_abstract = self::getAbstract($b["body"]);
$abstract = self::getAbstract($b["body"], $target_network);
// If we post to a network with no limit we only fetch
// an abstract exactly for this network
if (($limit == 0) && ($abstract == $default_abstract)) {
$abstract = "";
}
} else {// Try to guess the correct target network
switch ($htmlmode) {
case 8:
$abstract = self::getAbstract($b["body"], NETWORK_TWITTER);
break;
case 7:
$abstract = self::getAbstract($b["body"], NETWORK_STATUSNET);
break;
case 6:
$abstract = self::getAbstract($b["body"], NETWORK_APPNET);
break;
default: // We don't know the exact target.
// We fetch an abstract since there is a posting limit.
if ($limit > 0) {
$abstract = self::getAbstract($b["body"]);
}
}
}
if ($abstract != "") {
$post["text"] = $abstract;
if ($post["type"] == "text") {
$post["type"] = "link";
$post["url"] = $b["plink"];
}
}
$html = self::convert($post["text"].$post["after"], false, $htmlmode);
$msg = HTML::toPlaintext($html, 0, true);
$msg = trim(html_entity_decode($msg, ENT_QUOTES, 'UTF-8'));
$link = "";
if ($includedlinks) {
if ($post["type"] == "link") {
$link = $post["url"];
} elseif ($post["type"] == "text") {
$link = $post["url"];
} elseif ($post["type"] == "video") {
$link = $post["url"];
} elseif ($post["type"] == "photo") {
$link = $post["image"];
}
if (($msg == "") && isset($post["title"])) {
$msg = trim($post["title"]);
}
if (($msg == "") && isset($post["description"])) {
$msg = trim($post["description"]);
}
// If the link is already contained in the post, then it neeedn't to be added again
// But: if the link is beyond the limit, then it has to be added.
if (($link != "") && strstr($msg, $link)) {
$pos = strpos($msg, $link);
// Will the text be shortened in the link?
// Or is the link the last item in the post?
if (($limit > 0) && ($pos < $limit) && (($pos + 23 > $limit) || ($pos + strlen($link) == strlen($msg)))) {
$msg = trim(str_replace($link, "", $msg));
} elseif (($limit == 0) || ($pos < $limit)) {
// The limit has to be increased since it will be shortened - but not now
// Only do it with Twitter (htmlmode = 8)
if (($limit > 0) && (strlen($link) > 23) && ($htmlmode == 8)) {
$limit = $limit - 23 + strlen($link);
}
$link = "";
if ($post["type"] == "text") {
unset($post["url"]);
}
}
}
}
if ($limit > 0) {
// Reduce multiple spaces
// When posted to a network with limited space, we try to gain space where possible
while (strpos($msg, " ") !== false) {
$msg = str_replace(" ", " ", $msg);
}
// Twitter is using its own limiter, so we always assume that shortened links will have this length
if (iconv_strlen($link, "UTF-8") > 0) {
$limit = $limit - 23;
}
if (iconv_strlen($msg, "UTF-8") > $limit) {
if (($post["type"] == "text") && isset($post["url"])) {
$post["url"] = $b["plink"];
} elseif (!isset($post["url"])) {
$limit = $limit - 23;
$post["url"] = $b["plink"];
// Which purpose has this line? It is now uncommented, but left as a reminder
//} elseif (strpos($b["body"], "[share") !== false) {
// $post["url"] = $b["plink"];
} elseif (PConfig::get($b["uid"], "system", "no_intelligent_shortening")) {
$post["url"] = $b["plink"];
}
$msg = Plaintext::shorten($msg, $limit);
}
}
$post["text"] = trim($msg);
return($post);
} }
public static function scaleExternalImages($srctext, $include_link = true, $scale_replace = false) public static function scaleExternalImages($srctext, $include_link = true, $scale_replace = false)
@ -1947,7 +1808,7 @@ class BBCode extends BaseObject
* @param string $addon The addon for which the abstract is meant for * @param string $addon The addon for which the abstract is meant for
* @return string The abstract * @return string The abstract
*/ */
private static function getAbstract($text, $addon = "") public static function getAbstract($text, $addon = "")
{ {
$abstract = ""; $abstract = "";
$abstracts = []; $abstracts = [];

View file

@ -55,19 +55,24 @@ class Widget
} }
} }
return replace_macros(get_markup_template('peoplefind.tpl'), array( $nv = [];
'$findpeople' => L10n::t('Find People'), $nv['findpeople'] = L10n::t('Find People');
'$desc' => L10n::t('Enter name or interest'), $nv['desc'] = L10n::t('Enter name or interest');
'$label' => L10n::t('Connect/Follow'), $nv['label'] = L10n::t('Connect/Follow');
'$hint' => L10n::t('Examples: Robert Morgenstein, Fishing'), $nv['hint'] = L10n::t('Examples: Robert Morgenstein, Fishing');
'$findthem' => L10n::t('Find'), $nv['findthem'] = L10n::t('Find');
'$suggest' => L10n::t('Friend Suggestions'), $nv['suggest'] = L10n::t('Friend Suggestions');
'$similar' => L10n::t('Similar Interests'), $nv['similar'] = L10n::t('Similar Interests');
'$random' => L10n::t('Random Profile'), $nv['random'] = L10n::t('Random Profile');
'$inv' => L10n::t('Invite Friends'), $nv['inv'] = L10n::t('Invite Friends');
'$directory' => L10n::t('View Global Directory'), $nv['directory'] = L10n::t('Global Directory');
'$global_dir' => $global_dir $nv['global_dir'] = $global_dir;
)); $nv['local_directory'] = L10n::t('Local Directory');
$aside = [];
$aside['$nv'] = $nv;
return replace_macros(get_markup_template('peoplefind.tpl'), $aside);
} }
/** /**

View file

@ -246,7 +246,7 @@ class Addon
} else { } else {
// remove orphan hooks // remove orphan hooks
$condition = ['hook' => $name, 'file' => $hook[0], 'function' => $hook[1]]; $condition = ['hook' => $name, 'file' => $hook[0], 'function' => $hook[1]];
dba::delete('hook', $condition); dba::delete('hook', $condition, ['cascade' => false]);
} }
} }

View file

@ -21,6 +21,7 @@ class Console extends \Asika\SimpleConsole\Console
'extract' => __NAMESPACE__ . '\Console\Extract', 'extract' => __NAMESPACE__ . '\Console\Extract',
'globalcommunityblock' => __NAMESPACE__ . '\Console\GlobalCommunityBlock', 'globalcommunityblock' => __NAMESPACE__ . '\Console\GlobalCommunityBlock',
'globalcommunitysilence' => __NAMESPACE__ . '\Console\GlobalCommunitySilence', 'globalcommunitysilence' => __NAMESPACE__ . '\Console\GlobalCommunitySilence',
'archivecontact' => __NAMESPACE__ . '\Console\ArchiveContact',
'autoinstall' => __NAMESPACE__ . '\Console\AutomaticInstallation', 'autoinstall' => __NAMESPACE__ . '\Console\AutomaticInstallation',
'maintenance' => __NAMESPACE__ . '\Console\Maintenance', 'maintenance' => __NAMESPACE__ . '\Console\Maintenance',
'newpassword' => __NAMESPACE__ . '\Console\NewPassword', 'newpassword' => __NAMESPACE__ . '\Console\NewPassword',
@ -42,6 +43,7 @@ Commands:
extract Generate translation string file for the Friendica project (deprecated) extract Generate translation string file for the Friendica project (deprecated)
globalcommunityblock Block remote profile from interacting with this node globalcommunityblock Block remote profile from interacting with this node
globalcommunitysilence Silence remote profile from global community page globalcommunitysilence Silence remote profile from global community page
archivecontact Archive a contact when you know that it isn't existing anymore
help Show help about a command, e.g (bin/console help config) help Show help about a command, e.g (bin/console help config)
autoinstall Starts automatic installation of friendica based on values from htconfig.php autoinstall Starts automatic installation of friendica based on values from htconfig.php
maintenance Set maintenance mode for this node maintenance Set maintenance mode for this node

View file

@ -0,0 +1,79 @@
<?php
namespace Friendica\Core\Console;
use Friendica\Core\L10n;
use dba;
/**
* @brief tool to archive a contact on the server
*
* With this tool you can archive a contact when you know that it isn't existing anymore.
* Normally this does happen automatically after a few days.
*
* License: AGPLv3 or later, same as Friendica
*
*/
class ArchiveContact extends \Asika\SimpleConsole\Console
{
protected $helpOptions = ['h', 'help', '?'];
protected function getHelp()
{
$help = <<<HELP
console archivecontact - archive a contact
Usage
bin/console archivecontact <profile_url> [-h|--help|-?] [-v]
Description
Archive a contact when you know that it isn't existing anymore. Normally this does happen automatically after a few days.
Options
-h|--help|-? Show help information
-v Show more debug information.
HELP;
return $help;
}
protected function doExecute()
{
$a = get_app();
if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__);
$this->out('Arguments: ' . var_export($this->args, true));
$this->out('Options: ' . var_export($this->options, true));
}
if (count($this->args) == 0) {
$this->out($this->getHelp());
return 0;
}
if (count($this->args) > 1) {
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
}
require_once '.htconfig.php';
$result = \dba::connect($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data);
if (!$result) {
throw new \RuntimeException('Unable to connect to database');
}
$nurl = normalise_link($this->getArgument(0));
if (!dba::exists('contact', ['nurl' => $nurl, 'archive' => false])) {
throw new \RuntimeException(L10n::t('Could not find any unarchived contact entry for this URL (%s)', $nurl));
}
if (dba::update('contact', ['archive' => true], ['nurl' => $nurl])) {
$condition = ["`cid` IN (SELECT `id` FROM `contact` WHERE `archive`)"];
dba::delete('queue', $condition);
$this->out(L10n::t('The contact entries have been archived'));
} else {
throw new \RuntimeException('The contact archival failed.');
}
return 0;
}
}

View file

@ -423,7 +423,7 @@ class Contact extends BaseObject
// Fetch the data from the gcontact table // Fetch the data from the gcontact table
if (!DBM::is_result($r)) { if (!DBM::is_result($r)) {
$s = dba::p("SELECT 0 AS `id`, 0 AS `cid`, `id` AS `gid`, 0 AS `zid`, 0 AS `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, '' AS `xmpp`, $s = dba::p("SELECT 0 AS `id`, 0 AS `cid`, `id` AS `gid`, 0 AS `zid`, 0 AS `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, '' AS `xmpp`,
`keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, `community` AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self` `keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, 0 AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`
FROM `gcontact` WHERE `nurl` = ?", normalise_link($url)); FROM `gcontact` WHERE `nurl` = ?", normalise_link($url));
$r = dba::inArray($s); $r = dba::inArray($s);
} }

View file

@ -7,6 +7,7 @@
namespace Friendica\Model; namespace Friendica\Model;
use Friendica\BaseObject; use Friendica\BaseObject;
use Friendica\Content\Text;
use Friendica\Core\Addon; use Friendica\Core\Addon;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\L10n; use Friendica\Core\L10n;
@ -838,6 +839,101 @@ class Item extends BaseObject
return $current_post; return $current_post;
} }
/**
* @brief Distributes public items to the receivers
*
* @param integer $itemid Item ID that should be added
*/
public static function distribute($itemid)
{
$condition = ["`id` IN (SELECT `parent` FROM `item` WHERE `id` = ?)", $itemid];
$parent = dba::selectFirst('item', ['owner-id'], $condition);
if (!DBM::is_result($parent)) {
return;
}
// Only distribute public items from native networks
$condition = ['id' => $itemid, 'uid' => 0,
'network' => [NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, ""],
'visible' => true, 'deleted' => false, 'moderated' => false, 'private' => false];
$item = dba::selectFirst('item', [], ['id' => $itemid]);
if (!DBM::is_result($item)) {
return;
}
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']);
$users = [];
$condition = ["`nurl` IN (SELECT `nurl` FROM `contact` WHERE `id` = ?) AND `uid` != 0 AND NOT `blocked` AND NOT `readonly` AND `rel` IN (?, ?)",
$parent['owner-id'], CONTACT_IS_SHARING, CONTACT_IS_FRIEND];
$contacts = dba::select('contact', ['uid'], $condition);
while ($contact = dba::fetch($contacts)) {
$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);
}
}
/**
* @brief Store public items for the receivers
*
* @param integer $itemid Item ID that should be added
* @param array $item The item entry that will be stored
* @param integer $uid The user that will receive the item entry
*/
private static function storeForUser($itemid, $item, $uid)
{
$item['uid'] = $uid;
$item['origin'] = 0;
$item['wall'] = 0;
if ($item['uri'] == $item['parent-uri']) {
$item['contact-id'] = Contact::getIdForURL($item['owner-link'], $uid);
} else {
$item['contact-id'] = Contact::getIdForURL($item['author-link'], $uid);
}
if (empty($item['contact-id'])) {
$self = dba::selectFirst('contact', ['id'], ['self' => true, 'uid' => $uid]);
if (!DBM::is_result($self)) {
return;
}
$item['contact-id'] = $self['id'];
}
if (in_array($item['type'], ["net-comment", "wall-comment"])) {
$item['type'] = 'remote-comment';
} elseif ($item['type'] == 'wall') {
$item['type'] = 'remote';
}
/// @todo Handling of "event-id"
$distributed = self::insert($item, false, false, true);
if (!$distributed) {
logger("Distributed public item " . $itemid . " for user " . $uid . " wasn't stored", LOGGER_DEBUG);
} else {
logger("Distributed public item " . $itemid . " for user " . $uid . " with id " . $distributed, LOGGER_DEBUG);
}
}
/** /**
* @brief Add a shadow entry for a given item id that is a thread starter * @brief Add a shadow entry for a given item id that is a thread starter
* *
@ -849,8 +945,8 @@ class Item extends BaseObject
*/ */
public static function addShadow($itemid) public static function addShadow($itemid)
{ {
$fields = ['uid', 'wall', 'private', 'moderated', 'visible', 'contact-id', 'deleted', 'network', 'author-id', 'owner-id']; $fields = ['uid', 'private', 'moderated', 'visible', 'deleted', 'network'];
$condition = ["`id` = ? AND (`parent` = ? OR `parent` = 0)", $itemid, $itemid]; $condition = ['id' => $itemid, 'parent' => [0, $itemid]];
$item = dba::selectFirst('item', $fields, $condition); $item = dba::selectFirst('item', $fields, $condition);
if (!DBM::is_result($item)) { if (!DBM::is_result($item)) {
@ -872,35 +968,22 @@ class Item extends BaseObject
return; return;
} }
// Only do these checks if the post isn't a wall post
if (!$item["wall"]) {
// Check, if hide-friends is activated - then don't do a shadow entry
if (dba::exists('profile', ['is-default' => true, 'uid' => $item['uid'], 'hide-friends' => true])) {
return;
}
// Check if the contact is hidden or blocked
if (!dba::exists('contact', ['hidden' => false, 'blocked' => false, 'id' => $item['contact-id']])) {
return;
}
}
// Only add a shadow, if the profile isn't hidden
if (dba::exists('user', ['uid' => $item['uid'], 'hidewall' => true])) {
return;
}
$item = dba::selectFirst('item', [], ['id' => $itemid]); $item = dba::selectFirst('item', [], ['id' => $itemid]);
if (DBM::is_result($item) && ($item["allow_cid"] == '') && ($item["allow_gid"] == '') && if (DBM::is_result($item) && ($item["allow_cid"] == '') && ($item["allow_gid"] == '') &&
($item["deny_cid"] == '') && ($item["deny_gid"] == '')) { ($item["deny_cid"] == '') && ($item["deny_gid"] == '')) {
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 {
@ -954,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"])) {
@ -970,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);
}
}
} }
/** /**
@ -977,35 +1077,35 @@ class Item extends BaseObject
* if possible and not already present. * if possible and not already present.
* Expects "body" element to exist in $arr. * Expects "body" element to exist in $arr.
*/ */
private static function addLanguageInPostopts(&$arr) private static function addLanguageInPostopts(&$item)
{ {
if (x($arr, 'postopts')) { if (!empty($item['postopts'])) {
if (strstr($arr['postopts'], 'lang=')) { if (strstr($item['postopts'], 'lang=')) {
// do not override // do not override
return; return;
} }
$postopts = $arr['postopts']; $postopts = $item['postopts'];
} else { } else {
$postopts = ""; $postopts = "";
} }
$naked_body = preg_replace('/\[(.+?)\]/','', $arr['body']); $naked_body = Text\BBCode::toPlaintext($item['body'], false);
$l = new Text_LanguageDetect();
$lng = $l->detect($naked_body, 3);
if (sizeof($lng) > 0) { $languages = (new Text_LanguageDetect())->detect($naked_body, 3);
if ($postopts != "") {
if (sizeof($languages) > 0) {
if ($postopts != '') {
$postopts .= '&'; // arbitrary separator, to be reviewed $postopts .= '&'; // arbitrary separator, to be reviewed
} }
$postopts .= 'lang='; $postopts .= 'lang=';
$sep = ""; $sep = "";
foreach ($lng as $language => $score) { foreach ($languages as $language => $score) {
$postopts .= $sep . $language . ";" . $score; $postopts .= $sep . $language . ";" . $score;
$sep = ':'; $sep = ':';
} }
$arr['postopts'] = $postopts; $item['postopts'] = $postopts;
} }
} }

176
src/Model/ItemContent.php Normal file
View file

@ -0,0 +1,176 @@
<?php
/**
* @file src/Model/ItemContent.php
*/
namespace Friendica\Model;
use Friendica\BaseObject;
use Friendica\Content\Text;
use Friendica\Core\PConfig;
require_once 'boot.php';
require_once 'include/items.php';
require_once 'include/text.php';
class ItemContent extends BaseObject
{
/**
* @brief Convert a message into plaintext for connectors to other networks
*
* @param array $item The message array that is about to be posted
* @param int $limit The maximum number of characters when posting to that network
* @param bool $includedlinks Has an attached link to be included into the message?
* @param int $htmlmode This controls the behavior of the BBCode conversion
* @param string $target_network Name of the network where the post should go to.
*
* @see \Friendica\Content\Text\BBCode::getAttachedData
*
* @return array Same array structure than \Friendica\Content\Text\BBCode::getAttachedData
*/
public static function getPlaintextPost($item, $limit = 0, $includedlinks = false, $htmlmode = 2, $target_network = '')
{
// Remove hashtags
$URLSearchString = '^\[\]';
$body = preg_replace("/([#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $item['body']);
// Add an URL element if the text contains a raw link
$body = preg_replace('/([^\]\=\'"]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism',
'$1[url]$2[/url]', $body);
// Remove the abstract
$body = Text\BBCode::stripAbstract($body);
// At first look at data that is attached via "type-..." stuff
// This will hopefully replaced with a dedicated bbcode later
//$post = self::getAttachedData($b['body']);
$post = Text\BBCode::getAttachedData($body, $item);
if (($item['title'] != '') && ($post['text'] != '')) {
$post['text'] = trim($item['title'] . "\n\n" . $post['text']);
} elseif ($item['title'] != '') {
$post['text'] = trim($item['title']);
}
$abstract = '';
// Fetch the abstract from the given target network
if ($target_network != '') {
$default_abstract = Text\BBCode::getAbstract($item['body']);
$abstract = Text\BBCode::getAbstract($item['body'], $target_network);
// If we post to a network with no limit we only fetch
// an abstract exactly for this network
if (($limit == 0) && ($abstract == $default_abstract)) {
$abstract = '';
}
} else {// Try to guess the correct target network
switch ($htmlmode) {
case 8:
$abstract = Text\BBCode::getAbstract($item['body'], NETWORK_TWITTER);
break;
case 7:
$abstract = Text\BBCode::getAbstract($item['body'], NETWORK_STATUSNET);
break;
case 6:
$abstract = Text\BBCode::getAbstract($item['body'], NETWORK_APPNET);
break;
default: // We don't know the exact target.
// We fetch an abstract since there is a posting limit.
if ($limit > 0) {
$abstract = Text\BBCode::getAbstract($item['body']);
}
}
}
if ($abstract != '') {
$post['text'] = $abstract;
if ($post['type'] == 'text') {
$post['type'] = 'link';
$post['url'] = $item['plink'];
}
}
$html = Text\BBCode::convert($post['text'] . $post['after'], false, $htmlmode);
$msg = Text\HTML::toPlaintext($html, 0, true);
$msg = trim(html_entity_decode($msg, ENT_QUOTES, 'UTF-8'));
$link = '';
if ($includedlinks) {
if ($post['type'] == 'link') {
$link = $post['url'];
} elseif ($post['type'] == 'text') {
$link = $post['url'];
} elseif ($post['type'] == 'video') {
$link = $post['url'];
} elseif ($post['type'] == 'photo') {
$link = $post['image'];
}
if (($msg == '') && isset($post['title'])) {
$msg = trim($post['title']);
}
if (($msg == '') && isset($post['description'])) {
$msg = trim($post['description']);
}
// If the link is already contained in the post, then it neeedn't to be added again
// But: if the link is beyond the limit, then it has to be added.
if (($link != '') && strstr($msg, $link)) {
$pos = strpos($msg, $link);
// Will the text be shortened in the link?
// Or is the link the last item in the post?
if (($limit > 0) && ($pos < $limit) && (($pos + 23 > $limit) || ($pos + strlen($link) == strlen($msg)))) {
$msg = trim(str_replace($link, '', $msg));
} elseif (($limit == 0) || ($pos < $limit)) {
// The limit has to be increased since it will be shortened - but not now
// Only do it with Twitter (htmlmode = 8)
if (($limit > 0) && (strlen($link) > 23) && ($htmlmode == 8)) {
$limit = $limit - 23 + strlen($link);
}
$link = '';
if ($post['type'] == 'text') {
unset($post['url']);
}
}
}
}
if ($limit > 0) {
// Reduce multiple spaces
// When posted to a network with limited space, we try to gain space where possible
while (strpos($msg, ' ') !== false) {
$msg = str_replace(' ', ' ', $msg);
}
// Twitter is using its own limiter, so we always assume that shortened links will have this length
if (iconv_strlen($link, 'UTF-8') > 0) {
$limit = $limit - 23;
}
if (iconv_strlen($msg, 'UTF-8') > $limit) {
if (($post['type'] == 'text') && isset($post['url'])) {
$post['url'] = $item['plink'];
} elseif (!isset($post['url'])) {
$limit = $limit - 23;
$post['url'] = $item['plink'];
} elseif (strpos($item['body'], '[share') !== false) {
$post['url'] = $item['plink'];
} elseif (PConfig::get($item['uid'], 'system', 'no_intelligent_shortening')) {
$post['url'] = $item['plink'];
}
$msg = Text\Plaintext::shorten($msg, $limit);
}
}
$post['text'] = trim($msg);
return $post;
}
}

View file

@ -92,14 +92,14 @@ class Profile
{ {
$user = dba::selectFirst('user', ['uid'], ['nickname' => $nickname]); $user = dba::selectFirst('user', ['uid'], ['nickname' => $nickname]);
if (!$user && !count($user) && !count($profiledata)) { if (!DBM::is_result($user) && empty($profiledata)) {
logger('profile error: ' . $a->query_string, LOGGER_DEBUG); logger('profile error: ' . $a->query_string, LOGGER_DEBUG);
notice(L10n::t('Requested account is not available.') . EOL); notice(L10n::t('Requested account is not available.') . EOL);
$a->error = 404; $a->error = 404;
return; return;
} }
if (!x($a->page, 'aside')) { if (empty($a->page['aside'])) {
$a->page['aside'] = ''; $a->page['aside'] = '';
} }
@ -157,10 +157,6 @@ class Profile
require_once $theme_info_file; require_once $theme_info_file;
} }
if (!x($a->page, 'aside')) {
$a->page['aside'] = '';
}
if (local_user() && local_user() == $a->profile['uid'] && $profiledata) { if (local_user() && local_user() == $a->profile['uid'] && $profiledata) {
$a->page['aside'] .= replace_macros( $a->page['aside'] .= replace_macros(
get_markup_template('profile_edlink.tpl'), get_markup_template('profile_edlink.tpl'),
@ -644,26 +640,26 @@ class Profile
$classtoday = ''; $classtoday = '';
$s = dba::p( $s = dba::p(
"SELECT * "SELECT `event`.*
FROM `event` FROM `event`
WHERE `event`.`uid` = ? INNER JOIN `item`
AND `event`.`type` != 'birthday' ON `item`.`uid` = `event`.`uid`
AND `event`.`start` < ?
AND `event`.`start` >= ?
AND NOT EXISTS (
SELECT `id`
FROM `item`
WHERE `item`.`uid` = `event`.`uid`
AND `item`.`parent-uri` = `event`.`uri` AND `item`.`parent-uri` = `event`.`uri`
AND `item`.`verb` = ? WHERE `event`.`uid` = ?
AND `item`.`visible` AND `event`.`type` != 'birthday'
AND NOT `item`.`deleted` AND `event`.`start` < ?
) AND `event`.`start` >= ?
AND `item`.`author-id` = ?
AND (`item`.`verb` = ? OR `item`.`verb` = ?)
AND `item`.`visible`
AND NOT `item`.`deleted`
ORDER BY `event`.`start` ASC", ORDER BY `event`.`start` ASC",
local_user(), local_user(),
DateTimeFormat::utc('now + 7 days'), DateTimeFormat::utc('now + 7 days'),
DateTimeFormat::utc('now - 1 days'), DateTimeFormat::utc('now - 1 days'),
ACTIVITY_ATTENDNO public_contact(),
ACTIVITY_ATTEND,
ACTIVITY_ATTENDMAYBE
); );
$r = []; $r = [];
@ -954,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

@ -78,7 +78,7 @@ class Post extends BaseObject
} }
// Prepare the children // Prepare the children
if (count($data['children'])) { if (!empty($data['children'])) {
foreach ($data['children'] as $item) { foreach ($data['children'] as $item) {
// Only add will be displayed // Only add will be displayed
if ($item['network'] === NETWORK_MAIL && local_user() != $item['uid']) { if ($item['network'] === NETWORK_MAIL && local_user() != $item['uid']) {

View file

@ -1197,6 +1197,7 @@ class DFRN
$ret = Network::curl($url); $ret = Network::curl($url);
if ($ret['errno'] == CURLE_OPERATION_TIMEDOUT) { if ($ret['errno'] == CURLE_OPERATION_TIMEDOUT) {
Contact::markForArchival($contact);
return -2; // timed out return -2; // timed out
} }
@ -1204,24 +1205,28 @@ class DFRN
$curl_stat = $a->get_curl_code(); $curl_stat = $a->get_curl_code();
if (empty($curl_stat)) { if (empty($curl_stat)) {
Contact::markForArchival($contact);
return -3; // timed out return -3; // timed out
} }
logger('dfrn_deliver: ' . $xml, LOGGER_DATA); logger('dfrn_deliver: ' . $xml, LOGGER_DATA);
if (empty($xml)) { if (empty($xml)) {
Contact::markForArchival($contact);
return 3; return 3;
} }
if (strpos($xml, '<?xml') === false) { if (strpos($xml, '<?xml') === false) {
logger('dfrn_deliver: no valid XML returned'); logger('dfrn_deliver: no valid XML returned');
logger('dfrn_deliver: returned XML: ' . $xml, LOGGER_DATA); logger('dfrn_deliver: returned XML: ' . $xml, LOGGER_DATA);
Contact::markForArchival($contact);
return 3; return 3;
} }
$res = XML::parseString($xml); $res = XML::parseString($xml);
if ((intval($res->status) != 0) || (! strlen($res->challenge)) || (! strlen($res->dfrn_id))) { if ((intval($res->status) != 0) || !strlen($res->challenge) || !strlen($res->dfrn_id)) {
Contact::markForArchival($contact);
return ($res->status ? $res->status : 3); return ($res->status ? $res->status : 3);
} }
@ -1274,6 +1279,7 @@ class DFRN
if ($final_dfrn_id != $orig_id) { if ($final_dfrn_id != $orig_id) {
logger('dfrn_deliver: wrong dfrn_id.'); logger('dfrn_deliver: wrong dfrn_id.');
// did not decode properly - cannot trust this site // did not decode properly - cannot trust this site
Contact::markForArchival($contact);
return 3; return 3;
} }
@ -1309,6 +1315,7 @@ class DFRN
break; break;
default: default:
logger("rino: invalid requested version '$rino_remote_version'"); logger("rino: invalid requested version '$rino_remote_version'");
Contact::markForArchival($contact);
return -8; return -8;
} }
@ -1346,22 +1353,26 @@ class DFRN
$curl_stat = $a->get_curl_code(); $curl_stat = $a->get_curl_code();
if (empty($curl_stat) || empty($xml)) { if (empty($curl_stat) || empty($xml)) {
Contact::markForArchival($contact);
return -9; // timed out return -9; // timed out
} }
if (($curl_stat == 503) && stristr($a->get_curl_headers(), 'retry-after')) { if (($curl_stat == 503) && stristr($a->get_curl_headers(), 'retry-after')) {
Contact::markForArchival($contact);
return -10; return -10;
} }
if (strpos($xml, '<?xml') === false) { if (strpos($xml, '<?xml') === false) {
logger('dfrn_deliver: phase 2: no valid XML returned'); logger('dfrn_deliver: phase 2: no valid XML returned');
logger('dfrn_deliver: phase 2: returned XML: ' . $xml, LOGGER_DATA); logger('dfrn_deliver: phase 2: returned XML: ' . $xml, LOGGER_DATA);
Contact::markForArchival($contact);
return 3; return 3;
} }
$res = XML::parseString($xml); $res = XML::parseString($xml);
if (!isset($res->status)) { if (!isset($res->status)) {
Contact::markForArchival($contact);
return -11; return -11;
} }
@ -1374,7 +1385,7 @@ class DFRN
logger('Delivery returned status '.$res->status.' - '.$res->message, LOGGER_DEBUG); logger('Delivery returned status '.$res->status.' - '.$res->message, LOGGER_DEBUG);
} }
if ($res->status == 200) { if (($res->status >= 200) && ($res->status <= 299)) {
Contact::unmarkForArchival($contact); Contact::unmarkForArchival($contact);
} }
@ -1394,28 +1405,41 @@ class DFRN
{ {
$a = get_app(); $a = get_app();
if (empty($contact['addr'])) { if (!$public_batch) {
logger('Empty contact handle for ' . $contact['id'] . ' - ' . $contact['url'] . ' - trying to update it.');
if (Contact::updateFromProbe($contact['id'])) {
$new_contact = dba::selectFirst('contact', ['addr'], ['id' => $contact['id']]);
$contact['addr'] = $new_contact['addr'];
}
if (empty($contact['addr'])) { if (empty($contact['addr'])) {
logger('Unable to find contact handle for ' . $contact['id'] . ' - ' . $contact['url']); logger('Empty contact handle for ' . $contact['id'] . ' - ' . $contact['url'] . ' - trying to update it.');
return -21; if (Contact::updateFromProbe($contact['id'])) {
} $new_contact = dba::selectFirst('contact', ['addr'], ['id' => $contact['id']]);
} $contact['addr'] = $new_contact['addr'];
}
$fcontact = Diaspora::personByHandle($contact['addr']); if (empty($contact['addr'])) {
if (empty($fcontact)) { logger('Unable to find contact handle for ' . $contact['id'] . ' - ' . $contact['url']);
logger('Unable to find contact details for ' . $contact['id'] . ' - ' . $contact['addr']); Contact::markForArchival($contact);
return -22; return -21;
}
}
$fcontact = Diaspora::personByHandle($contact['addr']);
if (empty($fcontact)) {
logger('Unable to find contact details for ' . $contact['id'] . ' - ' . $contact['addr']);
Contact::markForArchival($contact);
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);
$dest_url = ($public_batch ? $fcontact["batch"] : $contact["notify"]); // Create the endpoint for public posts. This is some WIP and should later be added to the probing
if ($public_batch && empty($contact["batch"])) {
$parts = parse_url($contact["notify"]);
$path_parts = explode('/', $parts['path']);
array_pop($path_parts);
$parts['path'] = implode('/', $path_parts);
$contact["batch"] = Network::unparseURL($parts);
}
$dest_url = ($public_batch ? $contact["batch"] : $contact["notify"]);
$content_type = ($public_batch ? "application/magic-envelope+xml" : "application/json"); $content_type = ($public_batch ? "application/magic-envelope+xml" : "application/json");
@ -1424,22 +1448,26 @@ class DFRN
$curl_stat = $a->get_curl_code(); $curl_stat = $a->get_curl_code();
if (empty($curl_stat) || empty($xml)) { if (empty($curl_stat) || empty($xml)) {
logger('Empty answer from ' . $contact['id'] . ' - ' . $dest_url); logger('Empty answer from ' . $contact['id'] . ' - ' . $dest_url);
Contact::markForArchival($contact);
return -9; // timed out return -9; // timed out
} }
if (($curl_stat == 503) && (stristr($a->get_curl_headers(), 'retry-after'))) { if (($curl_stat == 503) && (stristr($a->get_curl_headers(), 'retry-after'))) {
Contact::markForArchival($contact);
return -10; return -10;
} }
if (strpos($xml, '<?xml') === false) { if (strpos($xml, '<?xml') === false) {
logger('No valid XML returned from ' . $contact['id'] . ' - ' . $dest_url); logger('No valid XML returned from ' . $contact['id'] . ' - ' . $dest_url);
logger('Returned XML: ' . $xml, LOGGER_DATA); logger('Returned XML: ' . $xml, LOGGER_DATA);
Contact::markForArchival($contact);
return 3; return 3;
} }
$res = XML::parseString($xml); $res = XML::parseString($xml);
if (empty($res->status)) { if (empty($res->status)) {
Contact::markForArchival($contact);
return -23; return -23;
} }
@ -1447,7 +1475,7 @@ class DFRN
logger('Transmit to ' . $dest_url . ' returned status '.$res->status.' - '.$res->message, LOGGER_DEBUG); logger('Transmit to ' . $dest_url . ' returned status '.$res->status.' - '.$res->message, LOGGER_DEBUG);
} }
if ($res->status == 200) { if (($res->status >= 200) && ($res->status <= 299)) {
Contact::unmarkForArchival($contact); Contact::unmarkForArchival($contact);
} }
@ -1467,33 +1495,33 @@ class DFRN
// Check for duplicates // Check for duplicates
$r = q( $r = q(
"SELECT `id` FROM `event` WHERE `uid` = %d AND `cid` = %d AND `start` = '%s' AND `type` = '%s' LIMIT 1", "SELECT `id` FROM `event` WHERE `uid` = %d AND `cid` = %d AND `start` = '%s' AND `type` = '%s' LIMIT 1",
intval($contact["uid"]), intval($contact['uid']),
intval($contact["id"]), intval($contact['id']),
dbesc(DateTimeFormat::utc($birthday)), dbesc(DateTimeFormat::utc($birthday)),
dbesc("birthday") dbesc('birthday')
); );
if (DBM::is_result($r)) { if (DBM::is_result($r)) {
return; return;
} }
logger("updating birthday: ".$birthday." for contact ".$contact["id"]); logger('updating birthday: ' . $birthday . ' for contact ' . $contact['id']);
$bdtext = L10n::t("%s\'s birthday", $contact["name"]); $bdtext = L10n::t('%s\'s birthday', $contact['name']);
$bdtext2 = L10n::t("Happy Birthday %s", " [url=".$contact["url"]."]".$contact["name"]."[/url]"); $bdtext2 = L10n::t('Happy Birthday %s', ' [url=' . $contact['url'] . ']' . $contact['name'] . '[/url]');
$r = q( $r = q(
"INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`summary`,`desc`,`type`) "INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`summary`,`desc`,`type`)
VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s') ",
intval($contact["uid"]), intval($contact['uid']),
intval($contact["id"]), intval($contact['id']),
dbesc(DateTimeFormat::utcNow()), dbesc(DateTimeFormat::utcNow()),
dbesc(DateTimeFormat::utcNow()), dbesc(DateTimeFormat::utcNow()),
dbesc(DateTimeFormat::utc($birthday)), dbesc(DateTimeFormat::utc($birthday)),
dbesc(DateTimeFormat::utc($birthday . " + 1 day ")), dbesc(DateTimeFormat::utc($birthday . ' + 1 day ')),
dbesc($bdtext), dbesc($bdtext),
dbesc($bdtext2), dbesc($bdtext2),
dbesc("birthday") dbesc('birthday')
); );
} }
@ -2747,6 +2775,10 @@ class DFRN
if ($posted_id) { if ($posted_id) {
logger("Reply from contact ".$item["contact-id"]." was stored with id ".$posted_id, LOGGER_DEBUG); logger("Reply from contact ".$item["contact-id"]." was stored with id ".$posted_id, LOGGER_DEBUG);
if ($item['uid'] == 0) {
Item::distribute($posted_id);
}
$item["id"] = $posted_id; $item["id"] = $posted_id;
$r = q( $r = q(
@ -2771,7 +2803,7 @@ class DFRN
logger('ignoring read-only contact '.$importer["id"]); logger('ignoring read-only contact '.$importer["id"]);
return; return;
} }
if ($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;
} }
@ -2801,6 +2833,10 @@ class DFRN
logger("Item was stored with id ".$posted_id, LOGGER_DEBUG); logger("Item was stored with id ".$posted_id, LOGGER_DEBUG);
if ($item['uid'] == 0) {
Item::distribute($posted_id);
}
if (stristr($item["verb"], ACTIVITY_POKE)) { if (stristr($item["verb"], ACTIVITY_POKE)) {
self::doPoke($item, $importer, $posted_id); self::doPoke($item, $importer, $posted_id);
} }
@ -2923,6 +2959,9 @@ class DFRN
logger("Import DFRN message for user " . $importer["importer_uid"] . " from contact " . $importer["id"], LOGGER_DEBUG); logger("Import DFRN message for user " . $importer["importer_uid"] . " from contact " . $importer["id"], LOGGER_DEBUG);
// is it a public forum? Private forums aren't exposed with this method
$forum = intval($xpath->evaluate("/atom:feed/dfrn:community/text()")->item(0)->nodeValue);
// The account type is new since 3.5.1 // The account type is new since 3.5.1
if ($xpath->query("/atom:feed/dfrn:account_type")->length > 0) { if ($xpath->query("/atom:feed/dfrn:account_type")->length > 0) {
$accounttype = intval($xpath->evaluate("/atom:feed/dfrn:account_type/text()")->item(0)->nodeValue); $accounttype = intval($xpath->evaluate("/atom:feed/dfrn:account_type/text()")->item(0)->nodeValue);
@ -2930,17 +2969,17 @@ class DFRN
if ($accounttype != $importer["contact-type"]) { if ($accounttype != $importer["contact-type"]) {
dba::update('contact', ['contact-type' => $accounttype], ['id' => $importer["id"]]); dba::update('contact', ['contact-type' => $accounttype], ['id' => $importer["id"]]);
} }
} // A forum contact can either have set "forum" or "prv" - but not both
if (($accounttype == ACCOUNT_TYPE_COMMUNITY) && (($forum != $importer["forum"]) || ($forum == $importer["prv"]))) {
// is it a public forum? Private forums aren't supported with this method $condition = ['(`forum` != ? OR `prv` != ?) AND `id` = ?', $forum, !$forum, $importer["id"]];
// This is deprecated since 3.5.1 dba::update('contact', ['forum' => $forum, 'prv' => !$forum], $condition);
$forum = intval($xpath->evaluate("/atom:feed/dfrn:community/text()")->item(0)->nodeValue); }
} elseif ($forum != $importer["forum"]) { // Deprecated since 3.5.1
if ($forum != $importer["forum"]) {
$condition = ['`forum` != ? AND `id` = ?', $forum, $importer["id"]]; $condition = ['`forum` != ? AND `id` = ?', $forum, $importer["id"]];
dba::update('contact', ['forum' => $forum], $condition); dba::update('contact', ['forum' => $forum], $condition);
} }
// We are processing relocations even if we are ignoring a contact // We are processing relocations even if we are ignoring a contact
$relocations = $xpath->query("/atom:feed/dfrn:relocate"); $relocations = $xpath->query("/atom:feed/dfrn:relocate");
foreach ($relocations as $relocation) { foreach ($relocations as $relocation) {

View file

@ -590,59 +590,15 @@ class Diaspora
return false; return false;
} }
if (!($postdata = self::validPosting($msg))) { if (!($fields = self::validPosting($msg))) {
logger("Invalid posting"); logger("Invalid posting");
return false; return false;
} }
$fields = $postdata['fields']; $importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE];
$success = self::dispatch($importer, $msg, $fields);
// Is it a an action (comment, like, ...) for our own post? return $success;
if (isset($fields->parent_guid) && !$postdata["relayed"]) {
$guid = notags(unxmlify($fields->parent_guid));
$importer = self::importerForGuid($guid);
if (is_array($importer)) {
logger("delivering to origin: ".$importer["name"]);
$message_id = self::dispatch($importer, $msg, $fields);
return $message_id;
}
}
// Process item retractions. This has to be done separated from the other stuff,
// since retractions for comments could come even from non followers.
if (!empty($fields) && in_array($fields->getName(), ['retraction'])) {
$target = notags(unxmlify($fields->target_type));
if (in_array($target, ["Comment", "Like", "Post", "Reshare", "StatusMessage"])) {
logger('processing retraction for '.$target, LOGGER_DEBUG);
$importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE];
$message_id = self::dispatch($importer, $msg, $fields);
return $message_id;
}
}
// Now distribute it to the followers
$r = q(
"SELECT `user`.* FROM `user` WHERE `user`.`uid` IN
(SELECT `contact`.`uid` FROM `contact` WHERE `contact`.`network` = '%s' AND `contact`.`addr` = '%s')
AND NOT `account_expired` AND NOT `account_removed`",
dbesc(NETWORK_DIASPORA),
dbesc($msg["author"])
);
if (DBM::is_result($r)) {
foreach ($r as $rr) {
logger("delivering to: ".$rr["username"]);
self::dispatch($rr, $msg, $fields);
}
} elseif (!Config::get('system', 'relay_subscribe', false)) {
logger("Unwanted message from ".$msg["author"]." send by ".$_SERVER["REMOTE_ADDR"]." with ".$_SERVER["HTTP_USER_AGENT"].": ".print_r($msg, true), LOGGER_DEBUG);
} else {
// Use a dummy importer to import the data for the public copy
$importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE];
$message_id = self::dispatch($importer, $msg, $fields);
}
return $message_id;
} }
/** /**
@ -662,11 +618,13 @@ class Diaspora
// This is only needed for private postings since this is already done for public ones before // This is only needed for private postings since this is already done for public ones before
if (is_null($fields)) { if (is_null($fields)) {
if (!($postdata = self::validPosting($msg))) { $private = true;
if (!($fields = self::validPosting($msg))) {
logger("Invalid posting"); logger("Invalid posting");
return false; return false;
} }
$fields = $postdata['fields']; } else {
$private = false;
} }
$type = $fields->getName(); $type = $fields->getName();
@ -675,27 +633,47 @@ class Diaspora
switch ($type) { switch ($type) {
case "account_migration": case "account_migration":
if (!$private) {
logger('Message with type ' . $type . ' is not private, quitting.');
return false;
}
return self::receiveAccountMigration($importer, $fields); return self::receiveAccountMigration($importer, $fields);
case "account_deletion": case "account_deletion":
return self::receiveAccountDeletion($importer, $fields); return self::receiveAccountDeletion($fields);
case "comment": case "comment":
return self::receiveComment($importer, $sender, $fields, $msg["message"]); return self::receiveComment($importer, $sender, $fields, $msg["message"]);
case "contact": case "contact":
if (!$private) {
logger('Message with type ' . $type . ' is not private, quitting.');
return false;
}
return self::receiveContactRequest($importer, $fields); return self::receiveContactRequest($importer, $fields);
case "conversation": case "conversation":
if (!$private) {
logger('Message with type ' . $type . ' is not private, quitting.');
return false;
}
return self::receiveConversation($importer, $msg, $fields); return self::receiveConversation($importer, $msg, $fields);
case "like": case "like":
return self::receiveLike($importer, $sender, $fields); return self::receiveLike($importer, $sender, $fields);
case "message": case "message":
if (!$private) {
logger('Message with type ' . $type . ' is not private, quitting.');
return false;
}
return self::receiveMessage($importer, $fields); return self::receiveMessage($importer, $fields);
case "participation": case "participation":
if (!$private) {
logger('Message with type ' . $type . ' is not private, quitting.');
return false;
}
return self::receiveParticipation($importer, $fields); return self::receiveParticipation($importer, $fields);
case "photo": // Not implemented case "photo": // Not implemented
@ -705,6 +683,10 @@ class Diaspora
return self::receivePollParticipation($importer, $fields); return self::receivePollParticipation($importer, $fields);
case "profile": case "profile":
if (!$private) {
logger('Message with type ' . $type . ' is not private, quitting.');
return false;
}
return self::receiveProfile($importer, $fields); return self::receiveProfile($importer, $fields);
case "reshare": case "reshare":
@ -840,7 +822,7 @@ class Diaspora
// Only some message types have signatures. So we quit here for the other types. // Only some message types have signatures. So we quit here for the other types.
if (!in_array($type, ["comment", "like"])) { if (!in_array($type, ["comment", "like"])) {
return ["fields" => $fields, "relayed" => false]; return $fields;
} }
// No author_signature? This is a must, so we quit. // No author_signature? This is a must, so we quit.
if (!isset($author_signature)) { if (!isset($author_signature)) {
@ -849,25 +831,29 @@ class Diaspora
} }
if (isset($parent_author_signature)) { if (isset($parent_author_signature)) {
$relayed = true;
$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);
return false; return false;
} }
} else {
$relayed = false;
} }
$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);
return false; return false;
} else { } else {
return ["fields" => $fields, "relayed" => $relayed]; return $fields;
} }
} }
@ -1650,25 +1636,23 @@ class Diaspora
/** /**
* @brief Processes an account deletion * @brief Processes an account deletion
* *
* @param array $importer Array of the importer user
* @param object $data The message object * @param object $data The message object
* *
* @return bool Success * @return bool Success
*/ */
private static function receiveAccountDeletion($importer, $data) private static function receiveAccountDeletion($data)
{ {
/// @todo Account deletion should remove the contact from the global contacts as well
$author = notags(unxmlify($data->author)); $author = notags(unxmlify($data->author));
$contact = self::contactByHandle($importer["uid"], $author); $contacts = dba::select('contact', ['id'], ['addr' => $author]);
if (!$contact) { while ($contact = dba::fetch($contacts)) {
logger("cannot find contact for author: ".$author); Contact::remove($contact["id"]);
return false;
} }
// We now remove the contact dba::delete('gcontact', ['addr' => $author]);
Contact::remove($contact["id"]);
logger('Removed contacts for ' . $author);
return true; return true;
} }
@ -1836,6 +1820,9 @@ class Diaspora
if ($message_id) { if ($message_id) {
logger("Stored comment ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); logger("Stored comment ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
if ($datarray['uid'] == 0) {
Item::distribute($message_id);
}
} }
// If we are the origin of the parent we store the original data and notify our followers // If we are the origin of the parent we store the original data and notify our followers
@ -2157,6 +2144,9 @@ class Diaspora
if ($message_id) { if ($message_id) {
logger("Stored like ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); logger("Stored like ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
if ($datarray['uid'] == 0) {
Item::distribute($message_id);
}
} }
// like on comments have the comment as parent. So we need to fetch the toplevel parent // like on comments have the comment as parent. So we need to fetch the toplevel parent
@ -2739,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)) {
@ -2752,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"]));
@ -2767,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)) {
@ -2883,6 +2883,9 @@ class Diaspora
if ($message_id) { if ($message_id) {
logger("Stored reshare ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); logger("Stored reshare ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
if ($datarray['uid'] == 0) {
Item::distribute($message_id);
}
return true; return true;
} else { } else {
return false; return false;
@ -3107,6 +3110,9 @@ class Diaspora
if ($message_id) { if ($message_id) {
logger("Stored item ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); logger("Stored item ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
if ($datarray['uid'] == 0) {
Item::distribute($message_id);
}
return true; return true;
} else { } else {
return false; return false;

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

@ -59,7 +59,7 @@ class Temporal
$o = '<select id="timezone_select" name="timezone">'; $o = '<select id="timezone_select" name="timezone">';
usort($timezone_identifiers, [self, 'timezoneCompareCallback']); usort($timezone_identifiers, [__CLASS__, 'timezoneCompareCallback']);
$continent = ''; $continent = '';
foreach ($timezone_identifiers as $value) { foreach ($timezone_identifiers as $value) {
$ex = explode("/", $value); $ex = explode("/", $value);

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'])) {
INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
WHERE `item`.`id` = ? AND `visible` AND NOT `moderated`", $item_id);
if (!DBM::is_result($target_item) || !intval($target_item['parent'])) {
return; return;
} }
$parent_id = intval($item['parent']);
$parent_id = intval($target_item['parent']); $itemdata = dba::p("SELECT `item`.*, `contact`.`uid` AS `cuid`,
$uid = $target_item['cuid']; `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer`
$updated = $target_item['edited']; FROM `item`
INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
$items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id`
FROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d AND visible = 1 AND moderated = 0 ORDER BY `id` ASC", WHERE `item`.`id` IN (?, ?) AND `visible` AND NOT `moderated`
intval($parent_id) ORDER BY `item`.`id`",
); $item_id, $parent_id);
$items = [];
if (!count($items)) { while ($item = dba::fetch($itemdata)) {
return; if ($item['id'] == $parent_id) {
} $parent = $item;
$icontacts = null;
$contacts_arr = [];
foreach ($items as $item) {
if (!in_array($item['contact-id'],$contacts_arr)) {
$contacts_arr[] = intval($item['contact-id']);
} }
if ($item['id'] == $item_id) {
$target_item = $item;
}
$items[] = $item;
} }
if (count($contacts_arr)) { dba::close($itemdata);
$str_contacts = implode(',',$contacts_arr);
$icontacts = q("SELECT * FROM `contact` $uid = $target_item['cuid'];
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);
break;
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;
}
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) {
$item = $target_item;
$item['body'] = Item::fixPrivatePhotos($item['body'], $owner['uid'], null, $item['contact-id']);
$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;
}
}
$atom = DFRN::entries($msgitems, $owner);
} }
foreach ($contacts as $contact) {
if ($contact['id'] == $item['contact-id']) { logger('Notifier entry: ' . $contact["url"] . ' ' . $target_item["guid"] . ' entry: ' . $atom, LOGGER_DATA);
return $contact;
$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;
} }
} }
return false; Email::send($addr, $subject, $headers, $target_item);
} }
} }

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

@ -63,7 +63,7 @@ class Queue
return; return;
} }
if (empty($contact['notify'])) { if (empty($contact['notify']) || $contact['archive']) {
QueueModel::removeItem($q_item['id']); QueueModel::removeItem($q_item['id']);
return; return;
} }

View file

@ -7,12 +7,14 @@ namespace Friendica\Test;
use Friendica\App; use Friendica\App;
use Friendica\BaseObject; use Friendica\BaseObject;
use PHPUnit_Framework_TestCase; // backward compatibility
if (!class_exists('\PHPUnit\Framework\TestCase')) {
class_alias('\PHPUnit_Framework_TestCase', '\PHPUnit\Framework\TestCase');
}
/** /**
* Tests for the BaseObject class. * Tests for the BaseObject class.
*/ */
class BaseObjectTest extends PHPUnit_Framework_TestCase class BaseObjectTest extends \PHPUnit\Framework\TestCase
{ {
/** /**

View file

@ -5,12 +5,15 @@
namespace Friendica\Test; namespace Friendica\Test;
use PHPUnit_Framework_TestCase; // backward compatibility
if (!class_exists('\PHPUnit\Framework\TestCase')) {
class_alias('\PHPUnit_Framework_TestCase', '\PHPUnit\Framework\TestCase');
}
/** /**
* Tests for text functions. * Tests for text functions.
*/ */
class TextTest extends PHPUnit_Framework_TestCase class TextTest extends \PHPUnit\Framework\TestCase
{ {
/** /**
@ -61,10 +64,10 @@ class TextTest extends PHPUnit_Framework_TestCase
public function testAutonameLength1() public function testAutonameLength1()
{ {
$autoname1=autoname(1); $autoname1=autoname(1);
$this->assertEquals(1, count($autoname1)); $this->assertEquals(1, strlen($autoname1));
$autoname2=autoname(1); $autoname2=autoname(1);
$this->assertEquals(1, count($autoname2)); $this->assertEquals(1, strlen($autoname2));
} }
/** /**

View file

@ -12,6 +12,7 @@ Alexandre Alapetite
AlfredSK AlfredSK
Andi Stadler Andi Stadler
Andreas H. Andreas H.
Andreas Neustifter
Andrej Stieben Andrej Stieben
André Alves André Alves
André Lohan André Lohan
@ -209,4 +210,4 @@ zotlabs
zottel zottel
Zvi ben Yaakov (a.k.a rdc) Zvi ben Yaakov (a.k.a rdc)
Михаил Михаил
朱陈锬 朱陈锬

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

@ -202,9 +202,17 @@ blockquote.shared_content {
} }
#profile-photo-wrapper { #profile-photo-wrapper {
clear: both;
overflow: hidden; overflow: hidden;
} }
#newmember-tips {
font-size: 1.2em;
float: right;
margin-top: -32px;
padding-right: 10px;
}
/* headers */ /* headers */
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
margin: 5px 0px 5px 0px; margin: 5px 0px 5px 0px;

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

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

@ -1,31 +1,18 @@
<form action="invite" method="post" id="invite-form" > <form action="invite" method="post" id="invite-form" >
<input type='hidden' name='form_security_token' value='{{$form_security_token}}'> <input type='hidden' name='form_security_token' value='{{$form_security_token}}'>
<div id="invite-wrapper"> <div id="invite-wrapper">
<h3>{{$invite}}</h3> <h3>{{$title}}</h3>
<div id="invite-recipient-text"> {{include file="field_textarea.tpl" field=$recipients}}
{{$addr_text}} {{include file="field_textarea.tpl" field=$message}}
</div>
<div id="invite-recipient-textarea"> <div id="invite-submit-wrapper">
<textarea id="invite-recipients" name="recipients" rows="8" cols="32" ></textarea> <input type="submit" name="submit" value="{{$submit|escape:'html'}}" />
</div> </div>
<div id="invite-message-text"> </div>
{{$msg_text}}
</div>
<div id="invite-message-textarea">
<textarea id="invite-message" name="message" rows="10" cols="72" >{{$default_message}}</textarea>
</div>
<div id="invite-submit-wrapper">
<input type="submit" name="submit" value="{{$submit|escape:'html'}}" />
</div>
</div>
</form> </form>

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,16 +20,11 @@
</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'}}" />
@ -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

@ -1,5 +1,5 @@
{{if $pager && ($pager.prev || $pager.next)}}
<div class="pager"> <div class="pager">
{{if $pager}}
{{if $pager.prev}}<span class="pager_prev {{$pager.prev.class}}"><a href="{{$pager.prev.url}}">{{$pager.prev.text}}</a></span>{{/if}} {{if $pager.prev}}<span class="pager_prev {{$pager.prev.class}}"><a href="{{$pager.prev.url}}">{{$pager.prev.text}}</a></span>{{/if}}
{{if $pager.first}}<span class="pager_first {{$pager.first.class}}"><a href="{{$pager.first.url}}">{{$pager.first.text}}</a></span>{{/if}} {{if $pager.first}}<span class="pager_first {{$pager.first.class}}"><a href="{{$pager.first.url}}">{{$pager.first.text}}</a></span>{{/if}}
@ -9,5 +9,5 @@
{{if $pager.last}}&nbsp;<span class="pager_last {{$pager.last.class}}"><a href="{{$pager.last.url}}">{{$pager.last.text}}</a></span>{{/if}} {{if $pager.last}}&nbsp;<span class="pager_last {{$pager.last.class}}"><a href="{{$pager.last.url}}">{{$pager.last.text}}</a></span>{{/if}}
{{if $pager.next}}<span class="pager_next {{$pager.next.class}}"><a href="{{$pager.next.url}}">{{$pager.next.text}}</a></span>{{/if}} {{if $pager.next}}<span class="pager_next {{$pager.next.class}}"><a href="{{$pager.next.url}}">{{$pager.next.text}}</a></span>{{/if}}
{{/if}}
</div> </div>
{{/if}}

View file

@ -1,16 +1,17 @@
<div id="peoplefind-sidebar" class="widget"> <div id="peoplefind-sidebar" class="widget">
<h3>{{$findpeople}}</h3> <h3>{{$nv.findpeople}}</h3>
<div id="peoplefind-desc">{{$desc}}</div> <div id="peoplefind-desc">{{$nv.desc}}</div>
<form action="dirfind" method="get" /> <form action="dirfind" method="get" />
<input id="side-peoplefind-url" type="text" name="search" size="24" title="{{$hint|escape:'html'}}" /><input id="side-peoplefind-submit" type="submit" name="submit" value="{{$findthem|escape:'html'}}" /> <input id="side-peoplefind-url" type="text" name="search" size="24" title="{{$nv.hint|escape:'html'}}" /><input id="side-peoplefind-submit" type="submit" name="submit" value="{{$nv.findthem|escape:'html'}}" />
</form> </form>
<div class="side-link" id="side-match-link"><a href="match" >{{$similar}}</a></div> <div class="side-link" id="side-match-link"><a href="match" >{{$nv.similar}}</a></div>
<div class="side-link" id="side-suggest-link"><a href="suggest" >{{$suggest}}</a></div> <div class="side-link" id="side-suggest-link"><a href="suggest" >{{$nv.suggest}}</a></div>
<div class="side-link" id="side-directory-link"><a href="{{$global_dir}}" target="extlink" >{{$directory}}</a></div> <div class="side-link" id="side-directory-link"><a href="directory" >{{$nv.local_directory}}</a></div>
<div class="side-link" id="side-random-profile-link" ><a href="randprof" target="extlink" >{{$random}}</a></div> <div class="side-link" id="side-directory-link"><a href="{{$nv.global_dir}}" target="extlink" >{{$nv.directory}}</a></div>
{{if $inv}} <div class="side-link" id="side-random-profile-link" ><a href="randprof" target="extlink" >{{$nv.random}}</a></div>
<div class="side-link" id="side-invite-link" ><a href="invite" >{{$inv}}</a></div> {{if $nv.inv}}
<div class="side-link" id="side-invite-link" ><a href="invite" >{{$nv.inv}}</a></div>
{{/if}} {{/if}}
</div> </div>

View file

@ -0,0 +1,22 @@
{{if count($reasons) > 1}}
<ul class="content-filter-reasons">
{{foreach $reasons as $reason}}
<li>{{$reason|escape:html}}</li>
{{/foreach}}
</ul>
<p>
<button type="button" id="content-filter-wrap-{{$rnd}}" class="btn btn-default btn-small content-filter-button" onclick="openClose('content-filter-{{$rnd}}');">
<i class="glyphicon glyphicon-eye-open"></i> {{$openclose}}
</button>
</p>
{{else}}
<p>
{{$reasons.0|escape:html}}
<button type="button" id="content-filter-wrap-{{$rnd}}" class="btn btn-default btn-xs content-filter-button" onclick="openClose('content-filter-{{$rnd}}');">
<i class="glyphicon glyphicon-eye-open"></i> {{$openclose}}
</button>
</p>
{{/if}}
<div id="content-filter-{{$rnd}}" class="content-filter-content" style="display: none;">
{{$html}}
</div>

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,128 +8,134 @@ 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)) {
$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];
} }
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];
}
$o = replace_macros($t, $ctx); $o = replace_macros($t, $ctx);

View file

@ -1,17 +1,20 @@
#admin-users.adminpage { padding-left:0; padding-right: 0;}
#admin-users.adminpage > h1 { padding: 0 15px; } #admin-users.adminpage > h1 { padding: 0 15px; }
#admin-users.adminpage .panel-collapse { margin-left: -15px; margin-right: -15px; }
#admin-users td { word-break: break-all; }
#admin-users #users th:first-of-type { width: 1em; } #admin-users #users th:first-of-type { width: 1em; }
#admin-users #users th:nth-of-type(2) { width: 40px; } #admin-users #users th:nth-of-type(2) { width: 40px; }
#admin-users #users th:last-of-type { width: 1em; } #admin-users #users th:last-of-type { width: 1em; }
#admin-users .admin-settings-footer-elements { padding-left: 8px; padding-right: 8px; }
#admin-users #deleted th:first-of-type { width: 40px; } #admin-users #deleted th:first-of-type { width: 40px; }
#admin-users #users img.avatar-nano, #deleted img.avatar-nano { height: 24px; width: 24px; } #admin-users #users img.avatar-nano, #deleted img.avatar-nano { height: 24px; width: 24px; }
.opened .caret { transform: rotate(180deg); } .opened .caret { transform: rotate(180deg); }
tr.details td, tr.details td,
tr.details th tr.details th {
{ border-top: 0!important; } border-top: 0!important;
}
.adminpage td > .checkbox { margin: 0; }
.adminpage td { word-break: break-all; }

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;*/
@ -2115,9 +2116,10 @@ ul.dropdown-menu li:hover {
.allfriends-content-wrapper, .match-content-wrapper, .dirfind-content-wrapper, .allfriends-content-wrapper, .match-content-wrapper, .dirfind-content-wrapper,
.directory-content-wrapper, .manage-content-wrapper, .notes-content-wrapper, .directory-content-wrapper, .manage-content-wrapper, .notes-content-wrapper,
.message-content-wrapper, .apps-content-wrapper, .photos-content-wrapper, .message-content-wrapper, .apps-content-wrapper, .photos-content-wrapper,
#adminpage, .viewcontacts-content-wrapper, .dfrn_request-content-wrapper, #adminpage, .delegate-content-wrapper, .uexport-content-wrapper,
.viewcontacts-content-wrapper, .dfrn_request-content-wrapper,
.friendica-content-wrapper, .credits-content-wrapper, .nogroup-content-wrapper, .friendica-content-wrapper, .credits-content-wrapper, .nogroup-content-wrapper,
.profperm-content-wrapper { .profperm-content-wrapper, .invite-content-wrapper {
min-height: calc(100vh - 150px); min-height: calc(100vh - 150px);
padding: 15px; padding: 15px;
padding-bottom: 20px; padding-bottom: 20px;
@ -2409,10 +2411,13 @@ ul li:hover .contact-wrapper .contact-action-link:hover {
height: 48px; height: 48px;
width: 48px; width: 48px;
} }
#prvmail-end { #prvmail-end {
clear:both; clear:both;
} }
#modal #prvmail-text-edit-bb .bb-img {
display: none;
}
/* photos */ /* photos */
.photo-album-actions { .photo-album-actions {
margin-bottom: 10px; margin-bottom: 10px;
@ -2650,7 +2655,8 @@ ul li:hover .contact-wrapper .contact-action-link:hover {
margin-left: -15px; margin-left: -15px;
margin-right: -15px; margin-right: -15px;
} }
.panel-group-settings > .panel { .panel-group-settings > .panel,
.panel-group-settings > form > .panel {
padding-left: 15px; padding-left: 15px;
padding-right: 15px; padding-right: 15px;
} }
@ -2935,6 +2941,22 @@ section.help-content-wrapper li {
#adminpage .plugin .desc { #adminpage .plugin .desc {
padding-left: 10px; padding-left: 10px;
} }
.adminpage .admin-settings-action-link,
.adminpage .admin-settings-action-link:hover {
color: #555;
}
.adminpage .admin-settings-action-link:hover {
opacity: 1;
}
.adminpage .admin-settings-action-link {
opacity: 0.8;
}
#admin-users tr.blocked {
background-color: #f8efc0;
}
.adminpage .table-hover > tbody > tr:hover + tr.details {
background-color: #f5f5f5;
}
/* Register Page*/ /* Register Page*/
#register-openid-wrapper, #register-name-wrapper, #register-invite-wrapper, #profile-publish-wrapper { #register-openid-wrapper, #register-name-wrapper, #register-invite-wrapper, #profile-publish-wrapper {
@ -3115,12 +3137,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 {
@ -3145,12 +3185,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);
@ -3164,11 +3207,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,
@ -3176,7 +3223,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;
@ -3189,7 +3236,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

@ -231,7 +231,6 @@ var FileBrowser = {
$(".fbrowser .fbswitcher [data-mode=" + FileBrowser.type + "]").addClass("active"); $(".fbrowser .fbswitcher [data-mode=" + FileBrowser.type + "]").addClass("active");
// We need to add the AjaxUpload to the button // We need to add the AjaxUpload to the button
FileBrowser.uploadButtons(); FileBrowser.uploadButtons();
}, },
// Load new content (e.g. change photo album) // Load new content (e.g. change photo album)

View file

@ -9,7 +9,9 @@ $(function() {
selectnone($(this).data('selectNone')); selectnone($(this).data('selectNone'));
}); });
$('body').on('change', 'input[type=checkbox].select', function() { // Toggle checkbox status to all or none for all checkboxes of a specific
// css class.
$('body').on('change', 'input[type=checkbox].selecttoggle', function() {
$this = $(this); $this = $(this);
if ($this.prop('checked')) { if ($this.prop('checked')) {
selectall($this.data('selectClass')); selectall($this.data('selectClass'));
@ -20,6 +22,26 @@ $(function() {
} }
}); });
// Use AJAX calls to reorder the table (so we don't need to reload the page).
$('body').on('click', '.table-order', function(e) {
e.preventDefault();
// Get the parent table element.
var table = $(this).parents('table');
var orderUrl = this.getAttribute("data-order-url");
table.fadeTo("fast", 0.33);
$("body").css("cursor", "wait");
$.get(orderUrl, function(data) {
// Find the table element in the html we got.
var result = $(data).find('#' + table[0].id);
// And add the new table html to the parent.
$(table).parent().html(result);
$("body").css("cursor", "auto");
});
});
function selectall(cls) { function selectall(cls) {
$('.' + cls).prop('checked', true); $('.' + cls).prop('checked', true);
@ -39,7 +61,7 @@ function confirm_delete(msg, uname){
} }
function details(uid) { function details(uid) {
$("#user-"+uid+"-detail").toggleClass("hidden"); $("#user-" + uid + "-detail").toggleClass("hidden");
$("#user-"+uid).toggleClass("opened"); $("#user-" + uid).toggleClass("opened");
return false; return false;
} }

View file

@ -152,6 +152,7 @@ Dialog._load = function(url) {
var jsbrowser = function() { var jsbrowser = function() {
FileBrowser.init(nickname, type, hash); FileBrowser.init(nickname, type, hash);
}; };
loadScript("view/js/ajaxupload.js");
loadScript("view/theme/frio/js/filebrowser.js", jsbrowser); loadScript("view/theme/frio/js/filebrowser.js", jsbrowser);
}; };
@ -206,6 +207,10 @@ function addToModal(url) {
//Get first element with the class "heading" //Get first element with the class "heading"
//and use it as title. //and use it as title.
loadModalTitle(); loadModalTitle();
// We need to initialize autosize again for new
// modal conent.
autosize($('.modal .text-autosize'));
} }
}); });
} }

View file

@ -446,8 +446,16 @@ function justifyPhotosAjax() {
$('#photo-album-contents').justifiedGallery('norewind').on('jg.complete', function(e){ justifiedGalleryActive = false; }); $('#photo-album-contents').justifiedGallery('norewind').on('jg.complete', function(e){ justifiedGalleryActive = false; });
} }
// Load a js script to the html head.
function loadScript(url, callback) { function loadScript(url, callback) {
// Adding the script tag to the head as suggested before // Check if the script is already in the html head.
var oscript = $('head script[src="' + url + '"]');
// Delete the old script from head.
if (oscript.length > 0) {
oscript.remove();
}
// Adding the script tag to the head as suggested before.
var head = document.getElementsByTagName('head')[0]; var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script'); var script = document.createElement('script');
script.type = 'text/javascript'; script.type = 'text/javascript';
@ -458,7 +466,7 @@ function loadScript(url, callback) {
script.onreadystatechange = callback; script.onreadystatechange = callback;
script.onload = callback; script.onload = callback;
// Fire the loading // Fire the loading.
head.appendChild(script); head.appendChild(script);
} }

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

@ -26,40 +26,43 @@ if (!isset($minimal)) {
<script type="text/javascript">var baseurl = "<?php echo System::baseUrl(); ?>";</script> <script type="text/javascript">var baseurl = "<?php echo System::baseUrl(); ?>";</script>
<script type="text/javascript">var frio = "<?php echo 'view/theme/frio'; ?>";</script> <script type="text/javascript">var frio = "<?php echo 'view/theme/frio'; ?>";</script>
<?php <?php
$baseurl = System::baseUrl(); $basepath = $a->path ? "/" . $a->path . "/" : "/";
$frio = "view/theme/frio"; $frio = "view/theme/frio";
// Because we use minimal for modals the header and the included js stuff should be only loaded
// if the page is an standard page (so we don't have it twice for modals)
//
/// @todo Think about to move js stuff in the footer
if (!$minimal && x($page, 'htmlhead')) {
echo $page['htmlhead'];
}
// Add the theme color meta
// It makes mobile Chrome UI match Frio's top bar color.
$uid = $a->profile_uid;
if (is_null($uid)) {
$uid = Profile::getThemeUid();
}
$schema = PConfig::get($uid, 'frio', 'schema');
if (($schema) && ($schema != '---')) {
if (file_exists('view/theme/frio/schema/' . $schema . '.php')) {
$schemefile = 'view/theme/frio/schema/' . $schema . '.php';
require_once $schemefile;
}
} else {
$nav_bg = PConfig::get($uid, 'frio', 'nav_bg');
}
if (!$nav_bg) {
$nav_bg = "#708fa0";
}
echo '
<meta name="theme-color" content="' . $nav_bg . '" />';
$is_singleuser = Config::get('system','singleuser'); // Because we use minimal for modals the header and the included js stuff should be only loaded
$is_singleuser_class = $is_singleuser ? "is-singleuser" : "is-not-singleuser"; // if the page is an standard page (so we don't have it twice for modals)
//
/// @todo Think about to move js stuff in the footer
if (!$minimal && x($page, 'htmlhead')) {
echo $page['htmlhead'];
}
// Add the theme color meta
// It makes mobile Chrome UI match Frio's top bar color.
$uid = $a->profile_uid;
if (is_null($uid)) {
$uid = Profile::getThemeUid();
}
$scheme = PConfig::get($uid, 'frio', 'scheme', PConfig::get($uid, 'frio', 'schema'));
if (($scheme) && ($scheme != '---')) {
if (file_exists('view/theme/frio/scheme/' . $scheme . '.php')) {
$schemefile = 'view/theme/frio/scheme/' . $scheme . '.php';
require_once $schemefile;
}
} else {
$nav_bg = PConfig::get($uid, 'frio', 'nav_bg');
}
if (!$nav_bg) {
$nav_bg = "#708fa0";
}
echo '
<meta name="theme-color" content="' . $nav_bg . '" />';
$is_singleuser = Config::get('system','singleuser');
$is_singleuser_class = $is_singleuser ? "is-singleuser" : "is-not-singleuser";
?> ?>
</head> </head>
<body id="top" class="mod-<?php echo $a->module." ".$is_singleuser_class;?>"> <body id="top" class="mod-<?php echo $a->module." ".$is_singleuser_class;?>">
<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
@ -90,8 +93,8 @@ if (!isset($minimal)) {
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<?php <?php
if ((!x($_REQUEST, 'pagename') || $_REQUEST['pagename'] != "lostpass") && ($_SERVER['REQUEST_URI'] != "/")) { if ((!x($_REQUEST, 'pagename') || $_REQUEST['pagename'] != "lostpass") && ($_SERVER['REQUEST_URI'] != $basepath)) {
echo ' echo '
<aside class="col-lg-3 col-md-3 offcanvas-sm offcanvas-xs">'; <aside class="col-lg-3 col-md-3 offcanvas-sm offcanvas-xs">';
if (x($page, 'aside')) { if (x($page, 'aside')) {
@ -107,18 +110,18 @@ if (!isset($minimal)) {
<div class="col-lg-7 col-md-7 col-sm-12 col-xs-12" id="content"> <div class="col-lg-7 col-md-7 col-sm-12 col-xs-12" id="content">
<section class="sectiontop '; <section class="sectiontop ';
echo $a->argv[0]; echo $a->argv[0];
echo '-content-wrapper">'; echo '-content-wrapper">';
if (x($page, 'content')) { if (x($page, 'content')) {
echo $page['content']; echo $page['content'];
} }
echo ' echo '
<div id="pause"></div> <!-- The pause/resume Ajax indicator --> <div id="pause"></div> <!-- The pause/resume Ajax indicator -->
</section> </section>
</div> </div>
'; ';
} else { } else {
echo ' echo '
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12" id="content" style="margin-top:50px;">'; <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12" id="content" style="margin-top:50px;">';
if (x($page, 'content')) { if (x($page, 'content')) {
echo $page['content']; echo $page['content'];
@ -126,7 +129,7 @@ if (!isset($minimal)) {
echo ' echo '
</div> </div>
'; ';
} }
?> ?>
</div><!--row--> </div><!--row-->
</div><!-- container --> </div><!-- container -->

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,71 @@
<?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;
function get_scheme_info($scheme)
{
$theme = current_theme();
$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,29 +152,35 @@ 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;
} }
// Convert transparency level from percentage to opacity value. // Convert transparency level from percentage to opacity value.
$contentbg_transp = $contentbg_transp / 100; $contentbg_transp = $contentbg_transp / 100;
$options = [ $options = [
'$nav_bg' => $nav_bg, '$nav_bg' => $nav_bg,
'$nav_icon_color' => $nav_icon_color, '$nav_icon_color' => $nav_icon_color,
'$nav_icon_hover_color' => $nav_icon_hover_color, '$nav_icon_hover_color' => $nav_icon_hover_color,
@ -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)) {

Some files were not shown because too many files have changed in this diff Show more