1
1
Fork 0

Merge remote-tracking branch 'upstream/develop' into dfrn-reshare

This commit is contained in:
Michael 2018-04-18 03:12:13 +00:00
commit 88353ce56f
291 changed files with 98692 additions and 89038 deletions

15
.github/issue_template.md vendored Normal file
View file

@ -0,0 +1,15 @@
### Expected behavior
### Actual behavior
### Steps to reproduce the problem
### Friendica version you encountered the problem
see `example.com/friendica` on your Friendica node for the version information.
### Friendica source (git, zip)
### PHP version
### SQL version

3
.gitignore vendored
View file

@ -53,7 +53,8 @@ nbproject
venv/ venv/
#ignore Composer dependencies #ignore Composer dependencies
vendor /vendor
/view/asset
#ignore config files from JetBrains #ignore config files from JetBrains
/.idea /.idea

4
.travis.yml Normal file
View file

@ -0,0 +1,4 @@
---
language: php
php: 5.6
install: composer install

128
CHANGELOG
View file

@ -1,3 +1,129 @@
Version 3.6 (2018-03-23)
Friendica Core:
Updates to the translations (DE, EN_GB, EN_US, ES, FR, IT, ZH_CN) [translation teams]
Updates for the Danish and French regions [Alkarex]
Update for the documentation [andyhee, annando, rabuzarus, ratten, rudloff, silke, tobiasd]
Updates to the themes [Andi-K, annando, fabrixxm, hoergen, rebeka-catalina, rabuzarus]
Enhancements to the ARIA support in frio [rabuzarus]
Enhancements to the DB handling and structure [annando]
Enhancements to the API [annando, fabrixxm, MrPetovan, rudloff]
Enhancements to the support of Open Graph with images [hoergen]
Enhancements to the Diaspora federation (participation signal, relay of dislikes, basic forum support for D*, Birthdays) [annando]
Enhancements to the OStatus federation [annando]
Enhancements to the handling of feed contacts [MrPetovan]
Enhancements to the display of threaded discussions (optional) [MrPetovan]
Enhancements to the display of events [hoergen]
Enhancements to the ACL dialog (selection of forums) [rabuzarus]
Enhancements to the handling of new connections [annando]
Enhancements to the vitality check of contacts [annando]
Enhancements to the daemon script [annando]
Enhancements to the federation stats [annando, tobiasd]
Enhancements to the interaction with public posts [annando]
Enhancements to the structure of the admin panel [tobiasd]
Enhancements to the community page [annando]
Enhancements to the delegation of accounts [annando, MrPetovan]
Enhancements to the user import and server relocation functionality [annando]
Enhancements to the menu layout in the admin panel [tobiasd]
Enhancements to the extraction of strings to be translated [fabrixxm, MrPetovan]
Enhancements to the installation wizard [annando, tobias]
Enhancements to the events [annando, hoergen, MrPetovan, rabuzarus]
Enhancements to the handling of email contacts [annando]
Enhancements to the Vagrant configuration of the development VM [tobias]
Enhancements to the probing of pump.io profiles [annando]
Enhancements to the handling of BBCode tags [MrPetovan]
Enhancements to the OEmbed handling [MrPetovan]
Fixed a bug that triggered the display of activities on the cummunity page [annando]
Fixed a bug with personal notes [annando]
Fixed a display issue of long postings when using the showmore option [annando]
Fixed a bug that caused Twidere to crash on reload [annando]
Fixed a bug in the exported data to the-federation.info [annando]
Fixed a bug in URL completion for feed fragments [annando]
Fixed a bug in the notification system about new registrations [annando]
Fixed the display of dislikes [annando]
Fixed the display of orphans childs in threads [MrPetovan]
Fixed some SQL problems [annando]
Fixed the CLI config script [tobiasd]
Fixed the forum selection on the network display [annando]
Fixed a bug during the import of accounts [annando]
Fixed a problem with UTF8 encoding during account export [annando]
Fixed a problem with archiving "self" contacts [annando]
Fixes to file permissions lintian reported [tobiasd]
Fixed a session problem leading to double login problem [MrPetovan]
Fixed a bug that caused code blocks on Diaspora being displayed wrongly [MrPetovan]
Fixed a bug that suggested it was possible to use some bridges without an account on the other side [annando]
Fixed the situation that an OStatus activity was triggered when publishing a image without sending out a posting for it [annando]
Fixed some issues with the display of exported events on GNU social and diaspora [annando]
Fixed the issue that Atom feeds of forums had no postings listed [annando]
Fixed a problem with the expiration of accounts [annando]
Added Atom feed for conversations [annando]
Added the possibility to address forums with !forumname [annando]
Added option to compare version against upstream version [tobiasd]
Added an optional hint that a global community page is global [tobiasd]
Added an option to always display the preview image in shared articles even if larger ones exist [annando]
Added CLI script to silence accounts on the community page [tobiasd]
Added CLI script to block postings to a node from accounts [tobiasd]
Added account block interface to the admin panel [MrPetovan]
Added browser bookmarklet code snippet [hoergen]
Added an additional feature to display a tag cloud on the profile page [rabuzarus]
Added retrieval of Mastodon server statistics [annando]
Added Atom feed that only contains top level postings of a user [annando]
Added tag following via saved search for #hashtag [annando]
Added PHP version information to the admin panel [MrPetovan]
Added the possibility to change relationships between Friendica contacts [annando]
Added the membersince functionality from the addon to the core [rabuzarus]
Added support of nodeinfo 2.0 [annando]
Removed the long deprecated internal templating engine [annando]
Removed the obsolete mysql support, you have to use MySQLI or PDO [annando]
Removed the unused mood module [annando]
Removed connect link from side panel when it should not be there [annando]
Removed very old updating routines [annando]
Dependencies are now (mostly) handled by composer [MrPetovan, zeroadam]
General code refactoring and beautification work [annando, MrPetovan, tobiasd, zeroadam]
ejabberd logs are now handled by syslog [annando]
Moved the poller script to the "scripts" directory and renamed it to worker [annando]
Threaded display of conversations is now always enabled [annando]
Images send to public forums are now always public as well [annando]
The DB cleanup option now includes the conversation table [annando]
Hash tags now always search locally [annando]
Consistent naming of addons (instead of plugins and addons) [zeroadam]
Community page is split between local and global and always visible for local users [annando]
Updated the credits to include new contributors [tobiasd]
Friendica Addons:
Updates to the translations (DE, EN_GB, ES, FR, IT, NL, ZH_CN) [translation teams]
all bridges don't relay postings anymore that are posted to a public forum [annando]
DAV addon marked unsupported [tobiasd]
Current Weather: fixing a problem with the weathermap link [zeroadam]
NSFW added config examples, reworked the description, now ignores the CW from Mastodon [andyhee, annando, rebeka-catalina]
Twitter support 280 chars limit [annando]
OpenWeatherMap fix broken map link [zeroadam]
CommunityHome added settings to admin panel, removed active users feature [annando, fabrixxm]
General code refactoring and beautification work [annando, MrPetovan, tobiasd, zeroadam]
Public Server reworked [annando]
pageheader settings beautifications [tobiasd]
mailstream settings beautifications [tobiasd]
Membersince is now part of the core [rabuzarus]
Forum posts are not transmitted over the connectors anymore [annando]
Friendica Dir:
Fixed a problem with the maintenance cron [MrPetovan]
Fixed a problem with the location widget [MrPetovan]
Work on the UI [MrPetovan]
Closed Issues:
929, 1050, 1056, 1125, 1215, 1251, 1289, 1312, 1429, 1488, 1540,
1610, 1858, 2786, 2845, 3020, 3039, 3337, 3379, 3394, 3396, 3566,
3583, 3661, 3671, 3680, 3801, 3822, 3824, 3828, 3839, 3855, 3857,
3860, 3863, 3867, 3905, 3911, 3916, 3942, 3946, 3999, 4013, 4020,
4023, 4041, 4042, 4061, 4069, 4070, 4071, 4075, 4078, 4082, 4094,
4105, 4115, 4116, 4137, 4141, 4144, 4150, 4155, 4161, 4163, 4173,
4184, 4199, 4200, 4207, 4227, 4228, 4236, 4251, 4272, 4273, 4278,
4279, 4281, 4290, 4294, 4295, 4296, 4304, 4306, 4319, 4348, 4362,
4368, 4369, 4377, 4390, 4395, 4396, 4409, 4412, 4426, 4431, 4445,
4450, 4452, 4458, 4463, 4481, 4482, 4495, 4497, 4498, 4508, 4518,
4520, 4522, 4535, 4543, 4550, 4555, 4556, 4571, 4575, 4610, 4611,
4620
Version 3.5.4 (2017-10-16) Version 3.5.4 (2017-10-16)
Friendica Core: Friendica Core:
Updates to the translations (DE) [translation teams] Updates to the translations (DE) [translation teams]
@ -90,7 +216,7 @@ Version 3.5.2 (2017-06-06)
Updates to the translations (DE, EN-GB, EN-US, ES, IT, PT-BR, RU) [translation teams] Updates to the translations (DE, EN-GB, EN-US, ES, IT, PT-BR, RU) [translation teams]
Updates to the documentation [annando, beardyunixer, rabuzarus, tobiasd] Updates to the documentation [annando, beardyunixer, rabuzarus, tobiasd]
Updated the nginx example configuration [beardyunixer] Updated the nginx example configuration [beardyunixer]
Code revision and refactoring [annando, hypolite, Quix0r, rebeka-catalina] Code revision and refactoring [annando, MrPetovan, Quix0r, rebeka-catalina]
Background process is now done by the new worker process [annando] Background process is now done by the new worker process [annando]
Added support of Composer for dependencies [Hypolite] Added support of Composer for dependencies [Hypolite]
Added support of Web app manifests [Rudloff] Added support of Web app manifests [Rudloff]

View file

@ -37,10 +37,12 @@ local .htaccess file
- PHP *command line* access with register_argc_argv set to true in the - PHP *command line* access with register_argc_argv set to true in the
php.ini file [or see 'poormancron' in section 8] php.ini file [or see 'poormancron' in section 8]
- curl, gd (with at least jpeg support), mysql, mbstring, xml and openssl extensions - curl, gd (with at least jpeg support), mysql, mbstring, xml, zip and openssl extensions
- 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
- The POSIX module of PHP needs to be activated (e.g. RHEL, CentOS have disabled it)
- 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.)
- ability to schedule jobs with cron (Linux/Mac) or Scheduled Tasks - ability to schedule jobs with cron (Linux/Mac) or Scheduled Tasks
@ -66,7 +68,7 @@ OR
git clone https://github.com/friendica/friendica [web server folder] git clone https://github.com/friendica/friendica [web server folder]
cd [web server folder] cd [web server folder]
php util/composer.phar install php bin/composer.phar install
3. Create an empty database and note the access details (hostname, username, 3. Create an empty database and note the access details (hostname, username,
password, database name). password, database name).
@ -113,14 +115,14 @@ tables, so that you can start fresh.
8. Set up a cron job or scheduled task to run the worker once every 5-10 8. Set up a cron job or scheduled task to run the worker once every 5-10
minutes to pick up the recent "public" postings of your friends. Example: minutes to pick up the recent "public" postings of your friends. Example:
cd /base/directory; /path/to/php scripts/worker.php cd /base/directory; /path/to/php bin/worker.php
Change "/base/directory", and "/path/to/php" as appropriate for your situation. Change "/base/directory", and "/path/to/php" as appropriate for your situation.
If you are using a Linux server, run "crontab -e" and add a line like the If you are using a Linux server, run "crontab -e" and add a line like the
one shown, substituting for your unique paths and settings: one shown, substituting for your unique paths and settings:
*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php scripts/worker.php */10 * * * * cd /home/myname/mywebsite; /usr/bin/php bin/worker.php
You can generally find the location of PHP by executing "which php". If you You can generally find the location of PHP by executing "which php". If you
have troubles with this section please contact your hosting provider for have troubles with this section please contact your hosting provider for
@ -129,24 +131,16 @@ assistance. Friendica will not work correctly if you cannot perform this step.
You should also be sure that $a->config['php_path'] is set correctly, it should You should also be sure that $a->config['php_path'] is set correctly, it should
look like (changing it to the correct PHP location) look like (changing it to the correct PHP location)
$a->config['php_path'] = '/usr/local/php53/bin/php' $a->config['php_path'] = '/usr/local/php56/bin/php'
Alternative: You may be able to use the 'poormancron' addon to perform this Alternative: If you cannot use a cron job as described above, you can use
step if you are using a recent Friendica release. 'poormancron' may result in the frontend worker and an external cron service to trigger the execution
perfomance and memory issues and is only suitable for small sites with one or of the worker script. You can enable the frontend worker after the installation
two users and a handful of contacts. To do this, edit the file from the admin panel of your node and call
".htconfig.php" and look for a line describing your addons. On a fresh
installation, it will look like
$a->config['system']['addon'] = 'js_upload'; https://example.com/worker
This indicates the "js_upload" addon module is enabled. You may add additional with the service of your choice.
addons using this same line in the configuration file. Change it to
read
$a->config['system']['addon'] = 'js_upload,poormancron';
and save your changes.
9. (Recommended) Set up a backup plan 9. (Recommended) Set up a backup plan
@ -293,14 +287,14 @@ cron by using something like
*/10 * * * * cd /var/www/friendica/friendica/ && sudo -u www-data /usr/bin/php */10 * * * * cd /var/www/friendica/friendica/ && sudo -u www-data /usr/bin/php
-d suhosin.executor.func.blacklist=none -d suhosin.executor.eval.blacklist=none -d suhosin.executor.func.blacklist=none -d suhosin.executor.eval.blacklist=none
-f scripts/worker.php -f bin/worker.php
This worked well for simple test cases, but the friendica-cron still failed with This worked well for simple test cases, but the friendica-cron still failed with
a fatal error: a fatal error:
suhosin[22962]: ALERT - function within blacklist called: proc_open() (attacker suhosin[22962]: ALERT - function within blacklist called: proc_open() (attacker
'REMOTE_ADDR not set', file '/var/www/friendica/friendica/boot.php', line 1341) 'REMOTE_ADDR not set', file '/var/www/friendica/friendica/boot.php', line 1341)
After a while I noticed, that scripts/worker.php calls further php script via After a while I noticed, that bin/worker.php calls further php script via
proc_open. These scripts themselves also use proc_open and fail, because they proc_open. These scripts themselves also use proc_open and fail, because they
are NOT called with -d suhosin.executor.func.blacklist=none. are NOT called with -d suhosin.executor.func.blacklist=none.

View file

@ -27,17 +27,18 @@ The location of the translated files in the source tree is
/view/lang/LNG-CODE/ /view/lang/LNG-CODE/
where LNG-CODE is the language code used, e.g. de for German or fr for French. where LNG-CODE is the language code used, e.g. de for German or fr for French.
The translated strings come as a "message.po" file from transifex which needs to be translated into the PHP file friendica uses. The translated strings come as a "message.po" file from transifex which needs to be translated into the PHP file friendica uses.
To do so, place the file in the directory mentioned above and use the "po2php" utility from the util directory of your friendica installation. To do so, place the file in the directory mentioned above and use the "po2php" command from the console.
*Please note that the console tool has to be called from the base directory of your Friendica installation.*
Assuming you want to convert the German localization which is placed in view/lang/de/message.po you would do the following. Assuming you want to convert the German localization which is placed in view/lang/de/message.po you would do the following.
1. Navigate at the command prompt to the base directory of your 1. Navigate at the command prompt to the base directory of your
friendica installation friendica installation
2. Execute the po2php script, which will place the translation 2. Execute the po2php command, which will place the translation
in the strings.php file that is used by friendica. in the strings.php file that is used by friendica.
$> php util/po2php.php view/lang/de/messages.po $> php bin/console.php po2php view/lang/de/messages.po
The output of the script will be placed at view/lang/de/strings.php where The output of the script will be placed at view/lang/de/strings.php where
friendica is expecting it, so you can test your translation immediately. friendica is expecting it, so you can test your translation immediately.
@ -62,7 +63,7 @@ Otherwise your work might get lost, when the translation from Transifex is inclu
Utilities Utilities
--------- ---------
Additional to the po2php script there are some more utilities for translation in the "util" directory of the friendica source tree. Additional to the po2php command there are some more utilities for translation in the console.
If you only want to translate friendica into another language you wont need any of these tools most likely but it gives you an idea how the translation process of friendica works. If you only want to translate friendica into another language you wont need any of these tools most likely but it gives you an idea how the translation process of friendica works.
For further information see the utils/README file. For further information see the utils/README file.
@ -90,9 +91,9 @@ To update the translation files after you have translated strings of e.g. Espera
$> tx pull -l eo $> tx pull -l eo
And then use the `po2php` utility described above to convert the `messages.po` file to the `strings.php` file Friendica is loading. And then use the `po2php` command described above to convert the `messages.po` file to the `strings.php` file Friendica is loading.
$> php util/po2php.php view/lang/eo/messages.po $> php bin/console.php po2php view/lang/eo/messages.po
Afterwards, just commit the two changed files to a feature branch of your Friendica repository, push the changes to github and open a pull request for your changes. Afterwards, just commit the two changed files to a feature branch of your Friendica repository, push the changes to github and open a pull request for your changes.

View file

@ -1 +1 @@
3.6-dev 2018-05-dev

4
Vagrantfile vendored
View file

@ -17,7 +17,7 @@ Vagrant.configure(2) do |config|
# Create a hostname, don't forget to put it to the `hosts` file # Create a hostname, don't forget to put it to the `hosts` file
# This will point to the server's default virtual host # This will point to the server's default virtual host
# TO DO: Make this work with virtualhost along-side xip.io URL # TO DO: Make this work with virtualhost along-side xip.io URL
config.vm.hostname = "friendica.dev" config.vm.hostname = "friendica.local"
# Create a static IP # Create a static IP
config.vm.network :private_network, ip: server_ip config.vm.network :private_network, ip: server_ip
@ -37,7 +37,7 @@ Vagrant.configure(2) do |config|
end end
# Enable provisioning with a shell script. # Enable provisioning with a shell script.
config.vm.provision "shell", path: "./util/vagrant_provision.sh" config.vm.provision "shell", path: "./bin/dev/vagrant_provision.sh"
# run: "always" # run: "always"
# run: "once" # run: "once"
end end

View file

@ -13,14 +13,14 @@
* Installation: * Installation:
* *
* - Change it's owner to whichever user is running the server, ie. ejabberd * - Change it's owner to whichever user is running the server, ie. ejabberd
* $ chown ejabberd:ejabberd /path/to/friendica/scripts/auth_ejabberd.php * $ chown ejabberd:ejabberd /path/to/friendica/bin/auth_ejabberd.php
* *
* - Change the access mode so it is readable only to the user ejabberd and has exec * - Change the access mode so it is readable only to the user ejabberd and has exec
* $ chmod 700 /path/to/friendica/scripts/auth_ejabberd.php * $ chmod 700 /path/to/friendica/bin/auth_ejabberd.php
* *
* - Edit your ejabberd.cfg file, comment out your auth_method and add: * - Edit your ejabberd.cfg file, comment out your auth_method and add:
* {auth_method, external}. * {auth_method, external}.
* {extauth_program, "/path/to/friendica/script/auth_ejabberd.php"}. * {extauth_program, "/path/to/friendica/bin/auth_ejabberd.php"}.
* *
* - Restart your ejabberd service, you should be able to login with your friendica auth info * - Restart your ejabberd service, you should be able to login with your friendica auth info
* *
@ -33,6 +33,8 @@
*/ */
use Friendica\App; use Friendica\App;
use Friendica\BaseObject;
use Friendica\Core\Config;
use Friendica\Util\ExAuth; use Friendica\Util\ExAuth;
if (sizeof($_SERVER["argv"]) == 0) { if (sizeof($_SERVER["argv"]) == 0) {
@ -53,6 +55,7 @@ require_once "boot.php";
require_once "include/dba.php"; require_once "include/dba.php";
$a = new App(dirname(__DIR__)); $a = new App(dirname(__DIR__));
BaseObject::setApp($a);
@include ".htconfig.php"; @include ".htconfig.php";
dba::connect($db_host, $db_user, $db_pass, $db_data); dba::connect($db_host, $db_user, $db_pass, $db_data);

10
bin/console Executable file
View file

@ -0,0 +1,10 @@
#!/bin/bash
dir=$(cd "${0%[/\\]*}" > /dev/null; pwd)
if [[ -d /proc/cygdrive && $(which php) == $(readlink -n /proc/cygdrive)/* ]]; then
# We are in Cgywin using Windows php, so the path must be translated
dir=$(cygpath -m "$dir");
fi
php "${dir}/console.php" "$@"

4
bin/console.bat Executable file
View file

@ -0,0 +1,4 @@
@echo OFF
:: in case DelayedExpansion is on and a path contains !
setlocal DISABLEDELAYEDEXPANSION
php "%~dp0console.php" %*

9
bin/console.php Executable file
View file

@ -0,0 +1,9 @@
#!/usr/bin/env php
<?php
include_once dirname(__DIR__) . '/boot.php';
$a = new Friendica\App(dirname(__DIR__));
\Friendica\BaseObject::setApp($a);
(new Friendica\Core\Console($argv))->execute();

View file

@ -1,7 +1,7 @@
#!/usr/bin/env php #!/usr/bin/env php
<?php <?php
/** /**
* @file scripts/daemon.php * @file bin/daemon.php
* @brief Run the worker from a daemon. * @brief Run the worker from a daemon.
* *
* This script was taken from http://php.net/manual/en/function.pcntl-fork.php * This script was taken from http://php.net/manual/en/function.pcntl-fork.php
@ -104,7 +104,7 @@ while (true) {
set_time_limit(0); set_time_limit(0);
// Call the worker // Call the worker
$cmdline = $php.' scripts/worker.php'; $cmdline = $php.' bin/worker.php';
$executed = false; $executed = false;

View file

@ -13,6 +13,7 @@ sudo apt-get install virtualbox-guest-x11
echo ">>> Installing *.xip.io self-signed SSL" echo ">>> Installing *.xip.io self-signed SSL"
SSL_DIR="/etc/ssl/xip.io" SSL_DIR="/etc/ssl/xip.io"
DOMAIN="*.xip.io" DOMAIN="*.xip.io"
EXTRADOMAIN="friendica.local"
PASSPHRASE="vaprobash" PASSPHRASE="vaprobash"
SUBJ=" SUBJ="
C=US C=US
@ -20,6 +21,7 @@ ST=Connecticut
O=Vaprobash O=Vaprobash
localityName=New Haven localityName=New Haven
commonName=$DOMAIN commonName=$DOMAIN
subjectAltName=DNS:$EXTRADOMAIN
organizationalUnitName= organizationalUnitName=
emailAddress= emailAddress=
" "
@ -33,18 +35,17 @@ sudo openssl x509 -req -days 365 -in "$SSL_DIR/xip.io.csr" -signkey "$SSL_DIR/xi
echo ">>> Installing Apache2 webserver" echo ">>> Installing Apache2 webserver"
sudo apt-get install -y apache2 sudo apt-get install -y apache2
sudo a2enmod rewrite actions ssl sudo a2enmod rewrite actions ssl
sudo cp /vagrant/util/vagrant_vhost.sh /usr/local/bin/vhost sudo cp /vagrant/bin/dev/vagrant_vhost.sh /usr/local/bin/vhost
sudo chmod guo+x /usr/local/bin/vhost sudo chmod guo+x /usr/local/bin/vhost
sudo vhost -s 192.168.22.10.xip.io -d /var/www -p /etc/ssl/xip.io -c xip.io -a friendica-xenial.dev sudo vhost -s 192.168.22.10.xip.io -d /var/www -p /etc/ssl/xip.io -c xip.io -a friendica.local
sudo a2dissite 000-default sudo a2dissite 000-default
sudo service apache2 restart sudo service apache2 restart
#Install php #Install php
echo ">>> Installing PHP7" echo ">>> Installing PHP7"
sudo apt-get install -y php libapache2-mod-php php-cli php-mysql php-curl php-gd php-mbstring php-xml imagemagick php-imagick sudo apt-get install -y php libapache2-mod-php php-cli php-mysql php-curl php-gd php-mbstring php-xml imagemagick php-imagick php-zip
sudo systemctl restart apache2 sudo systemctl restart apache2
#Install mysql #Install mysql
echo ">>> Installing Mysql" echo ">>> Installing Mysql"
sudo debconf-set-selections <<< "mysql-server mysql-server/root_password password root" sudo debconf-set-selections <<< "mysql-server mysql-server/root_password password root"
@ -69,8 +70,8 @@ systemctl restart mysql
#configure rudimentary mail server (local delivery only) #configure rudimentary mail server (local delivery only)
#add Friendica accounts for local user accounts, use email address like vagrant@friendica.dev, read the email with 'mail'. #add Friendica accounts for local user accounts, use email address like vagrant@friendica.local, read the email with 'mail'.
debconf-set-selections <<< "postfix postfix/mailname string friendica-xenial.dev" debconf-set-selections <<< "postfix postfix/mailname string friendica.local"
debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Local Only'" debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Local Only'"
sudo apt-get install -y postfix mailutils libmailutils-dev sudo apt-get install -y postfix mailutils libmailutils-dev
sudo echo -e "friendica1: vagrant\nfriendica2: vagrant\nfriendica3: vagrant\nfriendica4: vagrant\nfriendica5: vagrant" >> /etc/aliases && sudo newaliases sudo echo -e "friendica1: vagrant\nfriendica2: vagrant\nfriendica3: vagrant\nfriendica4: vagrant\nfriendica5: vagrant" >> /etc/aliases && sudo newaliases
@ -79,19 +80,23 @@ sudo echo -e "friendica1: vagrant\nfriendica2: vagrant\nfriendica3: vagrant\nfri
sudo rm -rf /var/www/ sudo rm -rf /var/www/
sudo ln -fs /vagrant /var/www sudo ln -fs /vagrant /var/www
# install deps with composer
sudo apt install unzip
cd /var/www
php bin/composer.phar install
# initial config file for friendica in vagrant # initial config file for friendica in vagrant
cp /vagrant/util/htconfig.vagrant.php /vagrant/.htconfig.php cp /vagrant/util/htconfig.vagrant.php /vagrant/.htconfig.php
# create the friendica database # create the friendica database
echo "create database friendica DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" | mysql -u root -proot echo "create database friendica DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" | $MYSQL -u root -proot
# import test database # import test database
$MYSQL -uroot -proot friendica < /vagrant/friendica_test_data.sql $MYSQL -uroot -proot friendica < /vagrant/friendica_test_data.sql
# create cronjob - activate if you have enough memory in you dev VM # create cronjob - activate if you have enough memory in you dev VM
echo "*/10 * * * * cd /vagrant; /usr/bin/php scripts/worker.php" >> friendicacron echo "*/10 * * * * cd /vagrant; /usr/bin/php bin/worker.php" >> friendicacron
sudo crontab friendicacron sudo crontab friendicacron
sudo rm friendicacron sudo rm friendicacron
# friendica needs write access to /tmp # friendica needs write access to /tmp
sudo chmod 777 /tmp sudo chmod 777 /tmp

View file

@ -45,7 +45,7 @@ case "$MODE" in
;; ;;
'default') 'default')
cd "$FULLPATH/.." cd "$FULLPATH/.."
OUTFILE="$FULLPATH/messages.po" OUTFILE="$FULLPATH/../util/messages.po"
FINDSTARTDIR="." FINDSTARTDIR="."
# skip addon folder # skip addon folder
FINDOPTS="( -wholename */addon -or -wholename */addons-extra -or -wholename */smarty3 ) -prune -o" FINDOPTS="( -wholename */addon -or -wholename */addons-extra -or -wholename */smarty3 ) -prune -o"

View file

@ -1,11 +1,12 @@
#!/usr/bin/env php #!/usr/bin/env php
<?php <?php
/** /**
* @file scripts/worker.php * @file bin/worker.php
* @brief Starts the background processing * @brief Starts the background processing
*/ */
use Friendica\App; use Friendica\App;
use Friendica\BaseObject;
use Friendica\Core\Addon; use Friendica\Core\Addon;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\Worker; use Friendica\Core\Worker;
@ -26,6 +27,7 @@ require_once "boot.php";
require_once "include/dba.php"; require_once "include/dba.php";
$a = new App(dirname(__DIR__)); $a = new App(dirname(__DIR__));
BaseObject::setApp($a);
require_once ".htconfig.php"; require_once ".htconfig.php";
dba::connect($db_host, $db_user, $db_pass, $db_data); dba::connect($db_host, $db_user, $db_pass, $db_data);
@ -37,7 +39,7 @@ Config::load();
check_db(true); check_db(true);
// Quit when in maintenance // Quit when in maintenance
if (Config::get('system', 'maintenance', true)) { if (Config::get('system', 'maintenance', false, true)) {
return; return;
} }

View file

@ -20,6 +20,7 @@
require_once __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php'; require_once __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
use Friendica\App; use Friendica\App;
use Friendica\BaseObject;
use Friendica\Core\Addon; use Friendica\Core\Addon;
use Friendica\Core\Cache; use Friendica\Core\Cache;
use Friendica\Core\Config; use Friendica\Core\Config;
@ -37,10 +38,10 @@ use Friendica\Util\DateTimeFormat;
require_once 'include/text.php'; require_once 'include/text.php';
define('FRIENDICA_PLATFORM', 'Friendica'); define('FRIENDICA_PLATFORM', 'Friendica');
define('FRIENDICA_CODENAME', 'Asparagus'); define('FRIENDICA_CODENAME', 'The Tazmans Flax-lily');
define('FRIENDICA_VERSION', '3.6-dev'); define('FRIENDICA_VERSION', '2018-05-dev');
define('DFRN_PROTOCOL_VERSION', '2.23'); define('DFRN_PROTOCOL_VERSION', '2.23');
define('DB_UPDATE_VERSION', 1256); define('DB_UPDATE_VERSION', 1259);
define('NEW_UPDATE_ROUTINE_VERSION', 1170); define('NEW_UPDATE_ROUTINE_VERSION', 1170);
/** /**
@ -211,12 +212,16 @@ define('PAGE_PRVGROUP', 5);
* *
* ACCOUNT_TYPE_COMMUNITY - the account is community forum * ACCOUNT_TYPE_COMMUNITY - the account is community forum
* Associated page types: PAGE_COMMUNITY, PAGE_PRVGROUP * Associated page types: PAGE_COMMUNITY, PAGE_PRVGROUP
*
* ACCOUNT_TYPE_RELAY - the account is a relay
* This will only be assigned to contacts, not to user accounts
* @{ * @{
*/ */
define('ACCOUNT_TYPE_PERSON', 0); define('ACCOUNT_TYPE_PERSON', 0);
define('ACCOUNT_TYPE_ORGANISATION', 1); define('ACCOUNT_TYPE_ORGANISATION', 1);
define('ACCOUNT_TYPE_NEWS', 2); define('ACCOUNT_TYPE_NEWS', 2);
define('ACCOUNT_TYPE_COMMUNITY', 3); define('ACCOUNT_TYPE_COMMUNITY', 3);
define('ACCOUNT_TYPE_RELAY', 4);
/** /**
* @} * @}
*/ */
@ -536,6 +541,7 @@ function get_app()
if (empty($a)) { if (empty($a)) {
$a = new App(dirname(__DIR__)); $a = new App(dirname(__DIR__));
BaseObject::setApp($a);
} }
return $a; return $a;
@ -947,10 +953,12 @@ function public_contact()
*/ */
function remote_user() function remote_user()
{ {
// You cannot be both local and remote // You cannot be both local and remote.
if (local_user()) { // Unncommented by rabuzarus because remote authentication to local
return false; // profiles wasn't possible anymore (2018-04-12).
} // if (local_user()) {
// return false;
// }
if (x($_SESSION, 'authenticated') && x($_SESSION, 'visitor_id')) { if (x($_SESSION, 'authenticated') && x($_SESSION, 'visitor_id')) {
return intval($_SESSION['visitor_id']); return intval($_SESSION['visitor_id']);
} }

View file

@ -15,6 +15,8 @@
"require": { "require": {
"php": ">5.6", "php": ">5.6",
"ext-xml": "*", "ext-xml": "*",
"asika/simple-console": "^1.0",
"divineomega/password_exposed": "^2.4",
"ezyang/htmlpurifier": "~4.7.0", "ezyang/htmlpurifier": "~4.7.0",
"league/html-to-markdown": "~4.4.1", "league/html-to-markdown": "~4.4.1",
"lightopenid/lightopenid": "dev-master", "lightopenid/lightopenid": "dev-master",
@ -32,7 +34,8 @@
"npm-asset/jquery-colorbox": "^1.6", "npm-asset/jquery-colorbox": "^1.6",
"npm-asset/jquery-datetimepicker": "^2.4.0", "npm-asset/jquery-datetimepicker": "^2.4.0",
"npm-asset/jgrowl": "^1.4", "npm-asset/jgrowl": "^1.4",
"npm-asset/fullcalendar": "^3.0.1" "npm-asset/fullcalendar": "^3.0.1",
"npm-asset/cropperjs": "1.2.2"
}, },
"repositories": [ "repositories": [
{ {
@ -54,8 +57,8 @@
"preferred-install": "dist", "preferred-install": "dist",
"fxp-asset": { "fxp-asset": {
"installer-paths": { "installer-paths": {
"npm-asset-library": "vendor/asset", "npm-asset-library": "view/asset",
"bower-asset-library": "vendor/asset" "bower-asset-library": "view/asset"
} }
} }
}, },

747
composer.lock generated
View file

@ -4,8 +4,41 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "3ff4187b4f7167583a3b8caa5f7c2a8a", "content-hash": "12b8df66213734281765cb6e2c5a786e",
"packages": [ "packages": [
{
"name": "asika/simple-console",
"version": "1.0.3",
"source": {
"type": "git",
"url": "https://github.com/asika32764/php-simple-console.git",
"reference": "0b624c1a999849dc6481a47182e58d593bf65068"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/asika32764/php-simple-console/zipball/0b624c1a999849dc6481a47182e58d593bf65068",
"reference": "0b624c1a999849dc6481a47182e58d593bf65068",
"shasum": ""
},
"type": "library",
"autoload": {
"psr-4": {
"Asika\\SimpleConsole\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Simon Asika",
"email": "asika32764@gmail.com"
}
],
"description": "One file console framework to help you write build scripts.",
"time": "2018-03-08T12:05:40+00:00"
},
{ {
"name": "bower-asset/Chart-js", "name": "bower-asset/Chart-js",
"version": "v2.7.1", "version": "v2.7.1",
@ -100,6 +133,54 @@
"description": "Minimalistic but perfect custom scrollbar plugin", "description": "Minimalistic but perfect custom scrollbar plugin",
"time": "2017-01-10T01:04:09+00:00" "time": "2017-01-10T01:04:09+00:00"
}, },
{
"name": "divineomega/password_exposed",
"version": "v2.5.1",
"source": {
"type": "git",
"url": "https://github.com/DivineOmega/password_exposed.git",
"reference": "c928bf722eb02398df11076add60df070cb55581"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/DivineOmega/password_exposed/zipball/c928bf722eb02398df11076add60df070cb55581",
"reference": "c928bf722eb02398df11076add60df070cb55581",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^6.3",
"paragonie/certainty": "^1",
"php": ">=5.6",
"rapidwebltd/rw-file-cache-psr-6": "^1.0"
},
"require-dev": {
"fzaninotto/faker": "^1.7",
"phpunit/phpunit": "^5.7",
"satooshi/php-coveralls": "^2.0",
"vimeo/psalm": "^1"
},
"type": "library",
"autoload": {
"psr-4": {
"DivineOmega\\PasswordExposed\\": "src/"
},
"files": [
"src/PasswordExposedFunction.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0-only"
],
"authors": [
{
"name": "Jordan Hall",
"email": "jordan@hall05.co.uk"
}
],
"description": "This PHP package provides a `password_exposed` helper function, that uses the haveibeenpwned.com API to check if a password has been exposed in a data breach.",
"time": "2018-04-02T18:16:36+00:00"
},
{ {
"name": "ezyang/htmlpurifier", "name": "ezyang/htmlpurifier",
"version": "v4.7.0", "version": "v4.7.0",
@ -203,6 +284,187 @@
], ],
"time": "2017-10-20T06:53:56+00:00" "time": "2017-10-20T06:53:56+00:00"
}, },
{
"name": "guzzlehttp/guzzle",
"version": "6.3.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/f4db5a78a5ea468d4831de7f0bf9d9415e348699",
"reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699",
"shasum": ""
},
"require": {
"guzzlehttp/promises": "^1.0",
"guzzlehttp/psr7": "^1.4",
"php": ">=5.5"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "^4.0 || ^5.0",
"psr/log": "^1.0"
},
"suggest": {
"psr/log": "Required for using the Log middleware"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.2-dev"
}
},
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle is a PHP HTTP client library",
"homepage": "http://guzzlephp.org/",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"rest",
"web service"
],
"time": "2017-06-22T18:50:49+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "v1.3.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
"shasum": ""
},
"require": {
"php": ">=5.5.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle promises library",
"keywords": [
"promise"
],
"time": "2016-12-20T10:07:11+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "1.4.2",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
"reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
"shasum": ""
},
"require": {
"php": ">=5.4.0",
"psr/http-message": "~1.0"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Tobias Schultze",
"homepage": "https://github.com/Tobion"
}
],
"description": "PSR-7 message implementation that also provides common utility methods",
"keywords": [
"http",
"message",
"request",
"response",
"stream",
"uri",
"url"
],
"time": "2017-03-20T17:10:46+00:00"
},
{ {
"name": "league/html-to-markdown", "name": "league/html-to-markdown",
"version": "4.4.1", "version": "4.4.1",
@ -398,6 +660,100 @@
], ],
"time": "2017-12-18T10:38:51+00:00" "time": "2017-12-18T10:38:51+00:00"
}, },
{
"name": "npm-asset/cropperjs",
"version": "1.2.2",
"dist": {
"type": "tar",
"url": "https://registry.npmjs.org/cropperjs/-/cropperjs-1.2.2.tgz",
"reference": null,
"shasum": "30dc7a7ce872155b23a33bd10ad4c76c0d613f55"
},
"require-dev": {
"npm-asset/babel-core": ">=6.26.0,<7.0.0",
"npm-asset/babel-plugin-external-helpers": ">=6.22.0,<7.0.0",
"npm-asset/babel-preset-env": ">=1.6.1,<2.0.0",
"npm-asset/cpy-cli": ">=1.0.1,<2.0.0",
"npm-asset/cssnano": ">=3.10.0,<4.0.0",
"npm-asset/del-cli": ">=1.1.0,<2.0.0",
"npm-asset/eslint": ">=4.14.0,<5.0.0",
"npm-asset/eslint-config-airbnb-base": ">=12.1.0,<13.0.0",
"npm-asset/eslint-plugin-import": ">=2.8.0,<3.0.0",
"npm-asset/node-qunit-phantomjs": ">=2.0.0,<3.0.0",
"npm-asset/npm-run-all": ">=4.1.2,<5.0.0",
"npm-asset/postcss-cli": ">=4.1.1,<5.0.0",
"npm-asset/postcss-cssnext": ">=3.0.2,<4.0.0",
"npm-asset/postcss-header": ">=1.0.0,<2.0.0",
"npm-asset/postcss-url": ">=7.3.0,<8.0.0",
"npm-asset/rollup": ">=0.53.3,<0.54.0",
"npm-asset/rollup-plugin-babel": ">=3.0.3,<4.0.0",
"npm-asset/rollup-watch": ">=4.3.1,<5.0.0",
"npm-asset/stylefmt": ">=6.0.0,<7.0.0",
"npm-asset/uglify-js": ">=3.3.4,<4.0.0"
},
"type": "npm-asset-library",
"extra": {
"npm-asset-bugs": {
"url": "https://github.com/fengyuanchen/cropperjs/issues"
},
"npm-asset-files": [
"src",
"dist"
],
"npm-asset-main": "dist/cropper.common.js",
"npm-asset-directories": [],
"npm-asset-repository": {
"type": "git",
"url": "git+https://github.com/fengyuanchen/cropperjs.git"
},
"npm-asset-scripts": {
"build": "npm run build:css && npm run build:js",
"build:css": "postcss src/css/cropper.css -o dist/cropper.css --no-map",
"build:js": "rollup -c",
"clear": "del-cli dist",
"compress": "npm run compress:css && npm run compress:js",
"compress:css": "postcss dist/cropper.css -u cssnano -o dist/cropper.min.css --no-map",
"compress:js": "uglifyjs dist/cropper.js -o dist/cropper.min.js -c -m --comments /^!/",
"copy": "cpy dist/cropper.css docs/css",
"lint": "eslint src/js --fix",
"release": "npm run clear && npm run lint && npm run build && npm run compress && npm run copy && npm test",
"start": "npm-run-all --parallel watch:*",
"test": "node-qunit-phantomjs test/index.html --timeout 10",
"watch:css": "postcss src/css/cropper.css -o docs/css/cropper.css -m -w",
"watch:js": "rollup -c -m -w"
}
},
"license": [
"MIT"
],
"authors": [
{
"name": "Chen Fengyuan",
"url": "http://chenfengyuan.com"
}
],
"description": "JavaScript image cropper.",
"homepage": "https://fengyuanchen.github.io/cropperjs",
"keywords": [
"crop",
"cropper",
"cropper.js",
"cropperjs",
"cropping",
"css",
"development",
"front-end",
"html",
"image",
"javascript",
"move",
"rotate",
"scale",
"web",
"zoom"
],
"time": "2018-01-03T13:39:39+00:00"
},
{ {
"name": "npm-asset/fullcalendar", "name": "npm-asset/fullcalendar",
"version": "3.8.2", "version": "3.8.2",
@ -937,6 +1293,129 @@
"homepage": "https://github.com/kartik-v/php-date-formatter", "homepage": "https://github.com/kartik-v/php-date-formatter",
"time": "2016-02-18T15:15:55+00:00" "time": "2016-02-18T15:15:55+00:00"
}, },
{
"name": "paragonie/certainty",
"version": "v1.0.2",
"source": {
"type": "git",
"url": "https://github.com/paragonie/certainty.git",
"reference": "a2d14f5b0b85c58329dee248d77d34e7e1202a32"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/certainty/zipball/a2d14f5b0b85c58329dee248d77d34e7e1202a32",
"reference": "a2d14f5b0b85c58329dee248d77d34e7e1202a32",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^6",
"paragonie/constant_time_encoding": "^1|^2",
"paragonie/sodium_compat": "^1.6",
"php": "^5.6|^7"
},
"require-dev": {
"phpunit/phpunit": "^5|^6",
"vimeo/psalm": "^1"
},
"bin": [
"bin/certainty-cert-symlink"
],
"type": "library",
"autoload": {
"psr-4": {
"ParagonIE\\Certainty\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"ISC"
],
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com",
"homepage": "https://paragonie.com"
}
],
"description": "Up-to-date, verifiable repository for Certificate Authorities",
"keywords": [
"CA-Cert",
"Ed25519",
"Public-Key Infractructure",
"ca",
"ca-cert.pem",
"cacert",
"cacert.pem",
"certificate authority",
"pki",
"ssl",
"tls"
],
"time": "2018-03-12T18:34:23+00:00"
},
{
"name": "paragonie/constant_time_encoding",
"version": "v1.0.2",
"source": {
"type": "git",
"url": "https://github.com/paragonie/constant_time_encoding.git",
"reference": "6111a38faf6fdebc14e36652d22036f379ba58d3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/6111a38faf6fdebc14e36652d22036f379ba58d3",
"reference": "6111a38faf6fdebc14e36652d22036f379ba58d3",
"shasum": ""
},
"require": {
"php": "^5.3|^7"
},
"require-dev": {
"paragonie/random_compat": "^1|^2",
"phpunit/phpunit": "4.*|5.*",
"vimeo/psalm": "^1"
},
"type": "library",
"autoload": {
"psr-4": {
"ParagonIE\\ConstantTime\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com",
"homepage": "https://paragonie.com",
"role": "Maintainer"
},
{
"name": "Steve 'Sc00bz' Thomas",
"email": "steve@tobtu.com",
"homepage": "https://www.tobtu.com",
"role": "Original Developer"
}
],
"description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
"keywords": [
"base16",
"base32",
"base32_decode",
"base32_encode",
"base64",
"base64_decode",
"base64_encode",
"bin2hex",
"encoding",
"hex",
"hex2bin",
"rfc4648"
],
"time": "2018-03-10T19:46:06+00:00"
},
{ {
"name": "paragonie/random_compat", "name": "paragonie/random_compat",
"version": "v2.0.11", "version": "v2.0.11",
@ -985,6 +1464,88 @@
], ],
"time": "2017-09-27T21:40:39+00:00" "time": "2017-09-27T21:40:39+00:00"
}, },
{
"name": "paragonie/sodium_compat",
"version": "v1.6.0",
"source": {
"type": "git",
"url": "https://github.com/paragonie/sodium_compat.git",
"reference": "1f6e5682eff4a5a6a394b14331a1904f1740e432"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/1f6e5682eff4a5a6a394b14331a1904f1740e432",
"reference": "1f6e5682eff4a5a6a394b14331a1904f1740e432",
"shasum": ""
},
"require": {
"paragonie/random_compat": "^1|^2",
"php": "^5.2.4|^5.3|^5.4|^5.5|^5.6|^7"
},
"require-dev": {
"phpunit/phpunit": "^3|^4|^5"
},
"suggest": {
"ext-libsodium": "PHP < 7.0: Better performance, password hashing (Argon2i), secure memory management (memzero), and better security.",
"ext-sodium": "PHP >= 7.0: Better performance, password hashing (Argon2i), secure memory management (memzero), and better security."
},
"type": "library",
"autoload": {
"files": [
"autoload.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"ISC"
],
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com"
},
{
"name": "Frank Denis",
"email": "jedisct1@pureftpd.org"
}
],
"description": "Pure PHP implementation of libsodium; uses the PHP extension if it exists",
"keywords": [
"Authentication",
"BLAKE2b",
"ChaCha20",
"ChaCha20-Poly1305",
"Chapoly",
"Curve25519",
"Ed25519",
"EdDSA",
"Edwards-curve Digital Signature Algorithm",
"Elliptic Curve Diffie-Hellman",
"Poly1305",
"Pure-PHP cryptography",
"RFC 7748",
"RFC 8032",
"Salpoly",
"Salsa20",
"X25519",
"XChaCha20-Poly1305",
"XSalsa20-Poly1305",
"Xchacha20",
"Xsalsa20",
"aead",
"cryptography",
"ecdh",
"elliptic curve",
"elliptic curve cryptography",
"encryption",
"libsodium",
"php",
"public-key cryptography",
"secret-key cryptography",
"side-channel resistant"
],
"time": "2018-02-15T05:50:20+00:00"
},
{ {
"name": "pear/console_getopt", "name": "pear/console_getopt",
"version": "v1.4.1", "version": "v1.4.1",
@ -1227,6 +1788,190 @@
"homepage": "http://pear.php.net/package/Text_LanguageDetect", "homepage": "http://pear.php.net/package/Text_LanguageDetect",
"time": "2017-03-02T16:14:08+00:00" "time": "2017-03-02T16:14:08+00:00"
}, },
{
"name": "psr/cache",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/cache.git",
"reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
"reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Cache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for caching libraries",
"keywords": [
"cache",
"psr",
"psr-6"
],
"time": "2016-08-06T20:24:11+00:00"
},
{
"name": "psr/http-message",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"homepage": "https://github.com/php-fig/http-message",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
],
"time": "2016-08-06T14:39:51+00:00"
},
{
"name": "rapidwebltd/rw-file-cache",
"version": "v1.2.5",
"source": {
"type": "git",
"url": "https://github.com/rapidwebltd/RW-File-Cache.git",
"reference": "4a1d5aaefa6ffafec8e2d60787f12bcd9890977e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/rapidwebltd/RW-File-Cache/zipball/4a1d5aaefa6ffafec8e2d60787f12bcd9890977e",
"reference": "4a1d5aaefa6ffafec8e2d60787f12bcd9890977e",
"shasum": ""
},
"require": {
"php": ">=5.2.1"
},
"require-dev": {
"phpunit/phpunit": "^5.7"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-4": {
"rapidweb\\RWFileCache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0-only"
],
"description": "RW File Cache is a PHP File-based Caching Library. Its syntax is designed to closely resemble the PHP memcache extension.",
"homepage": "https://github.com/rapidwebltd/RW-File-Cache",
"keywords": [
"cache",
"caching",
"caching library",
"file cache",
"library",
"php"
],
"time": "2018-01-23T17:20:58+00:00"
},
{
"name": "rapidwebltd/rw-file-cache-psr-6",
"version": "v1.0.0",
"source": {
"type": "git",
"url": "https://github.com/rapidwebltd/RW-File-Cache-PSR-6.git",
"reference": "b74ea201d4c964f0e6db0fb036d1ab28a570df66"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/rapidwebltd/RW-File-Cache-PSR-6/zipball/b74ea201d4c964f0e6db0fb036d1ab28a570df66",
"reference": "b74ea201d4c964f0e6db0fb036d1ab28a570df66",
"shasum": ""
},
"require": {
"psr/cache": "^1.0",
"rapidwebltd/rw-file-cache": "^1.2.3"
},
"require-dev": {
"cache/integration-tests": "^0.16.0",
"phpunit/phpunit": "^5.7"
},
"type": "library",
"autoload": {
"psr-4": {
"rapidweb\\RWFileCachePSR6\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0-only"
],
"authors": [
{
"name": "Jordan Hall",
"email": "jordan.hall@rapidweb.biz"
}
],
"description": "PSR-6 adapter for RW File Cache",
"time": "2018-01-30T19:13:45+00:00"
},
{ {
"name": "smarty/smarty", "name": "smarty/smarty",
"version": "v3.1.31", "version": "v3.1.31",

View file

@ -1,6 +1,6 @@
-- ------------------------------------------ -- ------------------------------------------
-- Friendica 3.6-dev (Asparagus) -- Friendica 2018-05-dev (The Tazmans Flax-lily)
-- DB_UPDATE_VERSION 1256 -- DB_UPDATE_VERSION 1259
-- ------------------------------------------ -- ------------------------------------------
@ -122,9 +122,9 @@ CREATE TABLE IF NOT EXISTS `contact` (
`xmpp` varchar(255) NOT NULL DEFAULT '' COMMENT '', `xmpp` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`attag` varchar(255) NOT NULL DEFAULT '' COMMENT '', `attag` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '', `avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`photo` varchar(255) NOT NULL DEFAULT '' COMMENT '', `photo` varchar(255) DEFAULT '' COMMENT '',
`thumb` varchar(255) NOT NULL DEFAULT '' COMMENT '', `thumb` varchar(255) DEFAULT '' COMMENT '',
`micro` varchar(255) NOT NULL DEFAULT '' COMMENT '', `micro` varchar(255) DEFAULT '' COMMENT '',
`site-pubkey` text COMMENT '', `site-pubkey` text COMMENT '',
`issued-id` varchar(255) NOT NULL DEFAULT '' COMMENT '', `issued-id` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`dfrn-id` varchar(255) NOT NULL DEFAULT '' COMMENT '', `dfrn-id` varchar(255) NOT NULL DEFAULT '' COMMENT '',
@ -397,6 +397,8 @@ CREATE TABLE IF NOT EXISTS `gserver` (
`noscrape` varchar(255) NOT NULL DEFAULT '' COMMENT '', `noscrape` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`network` char(4) NOT NULL DEFAULT '' COMMENT '', `network` char(4) NOT NULL DEFAULT '' COMMENT '',
`platform` varchar(255) NOT NULL DEFAULT '' COMMENT '', `platform` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`relay-subscribe` boolean NOT NULL DEFAULT '0' COMMENT 'Has the server subscribed to the relay system',
`relay-scope` varchar(10) NOT NULL DEFAULT '' COMMENT 'The scope of messages that the server wants to get',
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
`last_poco_query` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '', `last_poco_query` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '',
`last_contact` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '', `last_contact` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '',
@ -405,6 +407,16 @@ CREATE TABLE IF NOT EXISTS `gserver` (
UNIQUE INDEX `nurl` (`nurl`(190)) UNIQUE INDEX `nurl` (`nurl`(190))
) DEFAULT COLLATE utf8mb4_general_ci; ) DEFAULT COLLATE utf8mb4_general_ci;
--
-- TABLE gserver-tag
--
CREATE TABLE IF NOT EXISTS `gserver-tag` (
`gserver-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'The id of the gserver',
`tag` varchar(100) NOT NULL DEFAULT '' COMMENT 'Tag that the server has subscribed',
PRIMARY KEY(`gserver-id`,`tag`),
INDEX `tag` (`tag`)
) DEFAULT COLLATE utf8mb4_general_ci;
-- --
-- TABLE hook -- TABLE hook
-- --
@ -466,6 +478,7 @@ CREATE TABLE IF NOT EXISTS `item` (
`author-link` varchar(255) NOT NULL DEFAULT '' COMMENT '', `author-link` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`author-avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '', `author-avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`title` varchar(255) NOT NULL DEFAULT '' COMMENT '', `title` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`content-warning` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`body` mediumtext COMMENT '', `body` mediumtext COMMENT '',
`app` varchar(255) NOT NULL DEFAULT '' COMMENT '', `app` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`verb` varchar(100) NOT NULL DEFAULT '' COMMENT '', `verb` varchar(100) NOT NULL DEFAULT '' COMMENT '',
@ -1078,3 +1091,4 @@ CREATE TABLE IF NOT EXISTS `workerqueue` (
INDEX `executed` (`executed`) INDEX `executed` (`executed`)
) DEFAULT COLLATE utf8mb4_general_ci; ) DEFAULT COLLATE utf8mb4_general_ci;

View file

@ -1,81 +1,88 @@
Accesskeys in Friendica Accesskeys reference
======================= =======================
* [Home](help) * [Home](help)
For an overview of the modifier key of the different browsers we suggest this [Wikipedia](https://en.wikipedia.org/wiki/Access_key) article. Access keys are keyboard shortcuts that allow you to easily navigate the user interface.
Access keys are currently not available with the Frio theme.
The specific key combinations depend on how your browser's the modifier key setting.
For an overview of modifier keys in different browsers, have a lookat [Wikipedia](https://en.wikipedia.org/wiki/Access_key) article.
For example, for moving to profile page in Firefox, press these three keys simultaneously.
[Shift] [Alt] [p]
General General
------- -------
* p: profile * p - Profile
* n: network * n - Network
* c: community * c - Community
* s: search * s - Search
* a: admin * a - Admin
* f: notifications * f - Notifications
* u: user menu (in themes "vier" and "quattro") * u - User menu
/community ../community
-------- --------
* l: Local community * l - Local community
* g: Global community * g - Global community
/profile ../profile
-------- --------
* m: Status Messages and Posts * m - Status Messages and Posts
* r: Profile Details * r - Profile Details
* h: Photo Albums * h - Photo Albums
* v: Videos * v - Videos
* e: Events and Calendar * e - Events and Calendar
* t: Personal Notes * t - Personal Notes
* k: View Contacts * k - View Contacts
/contacts (contact list) ../contacts (contact list)
--------- ---------
* g: Suggestions * g - Suggestions
* l: Show all Contacts * l - Show all Contacts
* o: Only show unblocked contacts * o - Only show unblocked contacts
* b: Only show blocked contacts * b - Only show blocked contacts
* i: Only show ignored contacts * i - Only show ignored contacts
* y: Only show archived contacts * y - Only show archived contacts
* h: Only show hidden contacts * h - Only show hidden contacts
/contacts (single contact view) ../contacts (single contact view)
------------------------------- -------------------------------
* m: Status messages * m - Status messages
* o: Profile * o - Profile
* t: Contacts * t - Contacts
* d: Common friends * d - Common friends
* r: Advanced * r - Advanced
/message ../message
-------- --------
* m: New message * m - New message
/network ../network
-------- --------
* e: Sort by Comment Date * e - Sort by Comment Date
* t: Sort by Post Date * t - Sort by Post Date
* r: Conversation (Posts that mention or involve you) * r - Conversation (Posts that mention or involve you)
* w: New posts * w - New posts
* b: Bookmarks * b - Bookmarks
* m: Favourite Posts * m - Favourite Posts
/notifications ../notifications
-------------- --------------
* y: System * y - System
* w: Network * w - Network
* r: Personal * r - Personal
* h: Home * h - Home
* i: Introductions * i - Introductions
/settings ../settings
--------- ---------
* o: Account * o - Account
* t: Additional features * t - Additional features
* w: Social Networks * w - Social Networks
* l: Addons * l - Addons
* d: Delegations * d - Delegations
* b: Connected apps * b - Connected apps
* e: Export personal data * e - Export personal data
* r: Remove account * r - Remove account

View file

@ -7,10 +7,10 @@ Registration
--- ---
Not all Friendica sites allow open registration. Not all Friendica sites allow open registration.
If registration is allowed, you will see a "Register" link immediately below the login prompt on the site home page. If registration is allowed, you will see a "Register" link immediately below the login prompt on the site's home page.
Following this link will take you to the site registration page. Following this link will take you to the site registration page.
The strength of our network is that lots of different sites are all completely compatible with each other. The strength of our network is that lots of different sites are all completely compatible with each other.
If the site you're visting doesn't allow registration, or you think you might prefer another one, you can find a [list of public servers here](https://dir.friendica.social/servers), and find one that meets your needs. If the site you're visting doesn't allow registration, or you think you might prefer another one, there is a [list of public servers here](https://dir.friendica.social/servers) and hopefully you will find one that meets your needs.
If you'd like to have your own server, you can do that too. 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.
@ -44,12 +44,12 @@ A nickname is used to generate web addresses for many of your personal pages, an
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.
It must contain only US-ASCII text characters and numbers, and must also start with a text character. It must contain only US-ASCII text characters and numbers, and must also start with a text character.
It also must be unique on this system. It also must be unique on this system.
This is used in many places to identify your account, and once set - 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. 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.
We recommend that you select 'Yes' so that other people (friends, family, etc.) will be able to find you. We recommend that you select 'Yes' so that other people (friends, family, etc.) will be able to find you.
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.
@ -59,7 +59,7 @@ Whichever you choose, this can be changed any time from your Settings page after
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.
Please watch your email (including spam folders) for your registration details and initial password. Please check your email (including spam folders) for your registration details and initial password.
Login Page Login Page
--- ---
@ -67,9 +67,9 @@ Login Page
On the 'Login' page, please enter your login information that was provided during registration. On the 'Login' page, please enter your login information that was provided during registration.
You may use either your nickname or email address as a Login Name. You may use either your nickname or email address as a Login Name.
If you use your account to manage multiple '[Pages](help/Pages)' and these all have the same email address, please enter the nickname for the account you wish to manage. If you use your account to manage other accounts and these all have the same email address, please enter the nickname for the account you wish to manage.
*If* your account has been OpenID enabled, you may use your OpenID address as a login name and leave the password blank. If your account has been OpenID enabled, you may use your OpenID address as a login name and leave the password blank.
You will be redirected to your OpenID provider to complete your authorisation. You will be redirected to your OpenID provider to complete your authorisation.
Otherwise, enter your password. Otherwise, enter your password.
@ -84,7 +84,7 @@ After your first login, please visit the 'Settings' page from the top menu bar a
Getting Started Getting Started
--- ---
A ['Tips for New Members'](newmember) link will show up on your network and home pages for two weeks to provide some important Getting Started information. A link with ['Tips for New Members'](newmember) will show up on your network and home pages for two weeks providing key information for getting started.
Retrieving Personal Data Retrieving Personal Data
--- ---
@ -99,6 +99,8 @@ See Also
* [Profiles](help/Profiles) * [Profiles](help/Profiles)
* [Global Directory](help/Making-Friends#1_1)
* [Groups and Privacy](help/Groups-and-Privacy) * [Groups and Privacy](help/Groups-and-Privacy)
* [Move Account](help/Move-Account) * [Move Account](help/Move-Account)

View file

@ -284,192 +284,221 @@ $b is an array with:
'template' => filename of template 'template' => filename of template
'vars' => array of vars passed to template 'vars' => array of vars passed to template
### ''acl_lookup_end' ### 'acl_lookup_end'
is called after the other queries have passed. is called after the other queries have passed.
The registered function can add, change or remove the acl_lookup() variables. The registered function can add, change or remove the acl_lookup() variables.
'results' => array of the acl_lookup() vars 'results' => array of the acl_lookup() vars
### 'prepare_body_init'
Called at the start of prepare_body
Hook data:
'item' => item array (input/output)
### 'prepare_body_content_filter'
Called before the HTML conversion in prepare_body. If the item matches a content filter rule set by an addon, it should
just add the reason to the filter_reasons element of the hook data.
Hook data:
'item' => item array (input)
'filter_reasons' => reasons array (input/output)
### 'prepare_body'
Called after the HTML conversion in prepare_body.
Hook data:
'item' => item array (input)
'html' => converted item body (input/output)
'is_preview' => post preview flag (input)
'filter_reasons' => reasons array (input)
### 'prepare_body_final'
Called at the end of prepare_body.
Hook data:
'item' => item array (input)
'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 14-Feb-2012). 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.
boot.php: Addon::callHooks('login_hook',$o); index.php: Addon::callHooks('init_1');
index.php: Addon::callHooks('app_menu', $arr);
boot.php: Addon::callHooks('profile_sidebar_enter', $profile); index.php: Addon::callHooks('page_content_top', $a->page['content']);
index.php: Addon::callHooks($a->module.'_mod_init', $placeholder);
boot.php: Addon::callHooks('profile_sidebar', $arr); index.php: Addon::callHooks($a->module.'_mod_init', $placeholder);
index.php: Addon::callHooks($a->module.'_mod_post', $_POST);
boot.php: Addon::callHooks("proc_run", $arr); index.php: Addon::callHooks($a->module.'_mod_afterpost', $placeholder);
index.php: Addon::callHooks($a->module.'_mod_content', $arr);
include/contact_selectors.php: Addon::callHooks('network_to_name', $nets); 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); include/api.php: Addon::callHooks('logged_in', $a->user);
include/api.php: Addon::callHooks('authenticate', $addon_auth);
include/api.php: Addon::callHooks('logged_in', $a->user); include/api.php: Addon::callHooks('logged_in', $a->user);
include/queue.php: Addon::callHooks('queue_predeliver', $a, $r); include/enotify.php: Addon::callHooks('enotify', $h);
include/enotify.php: Addon::callHooks('enotify_store', $datarray);
include/enotify.php: Addon::callHooks('enotify_mail', $datarray);
include/enotify.php: Addon::callHooks('check_item_notification', $notification_data);
include/queue.php: Addon::callHooks('queue_deliver', $a, $params); include/conversation.php: Addon::callHooks('conversation_start', $cb);
include/conversation.php: Addon::callHooks('render_location', $locate);
include/text.php: Addon::callHooks('contact_block_end', $arr); include/conversation.php: Addon::callHooks('display_item', $arr);
include/conversation.php: Addon::callHooks('display_item', $arr);
include/text.php: Addon::callHooks('smilie', $s); include/conversation.php: Addon::callHooks('item_photo_menu', $args);
include/conversation.php: Addon::callHooks('jot_tool', $jotplugins);
include/text.php: Addon::callHooks('prepare_body_init', $item);
include/text.php: Addon::callHooks('prepare_body', $prep_arr);
include/text.php: Addon::callHooks('prepare_body_final', $prep_arr);
include/nav.php: Addon::callHooks('page_header', $a->page['nav']);
include/auth.php: Addon::callHooks('authenticate', $addon_auth);
include/bbcode.php: Addon::callHooks('bbcode',$Text);
include/oauth.php: Addon::callHooks('logged_in', $a->user);
include/acl_selectors.php: Addon::callHooks($a->module . '_pre_' . $selname, $arr);
include/acl_selectors.php: Addon::callHooks($a->module . '_post_' . $selname, $o);
include/acl_selectors.php: Addon::callHooks('contact_select_options', $x);
include/acl_selectors.php: Addon::callHooks($a->module . '_pre_' . $selname, $arr);
include/acl_selectors.php: Addon::callHooks($a->module . '_post_' . $selname, $o);
include/acl_selectors.php: Addon::callHooks($a->module . '_pre_' . $selname, $arr);
include/acl_selectors.php: Addon::callHooks($a->module . '_post_' . $selname, $o);
include/acl_selectors.php Addon::callHooks('acl_lookup_end', $results);
include/notifier.php: Addon::callHooks('notifier_normal',$target_item);
include/notifier.php: Addon::callHooks('notifier_end',$target_item);
include/items.php: Addon::callHooks('atom_feed', $atom);
include/items.php: Addon::callHooks('atom_feed_end', $atom);
include/items.php: Addon::callHooks('atom_feed_end', $atom);
include/items.php: Addon::callHooks('parse_atom', $arr);
include/items.php: Addon::callHooks('post_remote',$arr);
include/items.php: Addon::callHooks('atom_author', $o);
include/items.php: Addon::callHooks('atom_entry', $o);
include/bb2diaspora.php: Addon::callHooks('bb2diaspora',$Text);
include/cronhooks.php: Addon::callHooks('cron', $d);
include/security.php: Addon::callHooks('logged_in', $a->user); include/security.php: Addon::callHooks('logged_in', $a->user);
include/html2bbcode.php: Addon::callHooks('html2bbcode', $text); include/text.php: Addon::callHooks('contact_block_end', $arr);
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/Contact.php: Addon::callHooks('remove_user',$r[0]); include/items.php: Addon::callHooks('page_info_data', $data);
include/Contact.php: Addon::callHooks('contact_photo_menu', $args);
include/conversation.php: Addon::callHooks('conversation_start',$cb);
include/conversation.php: Addon::callHooks('render_location',$locate);
include/conversation.php: Addon::callHooks('display_item', $arr);
include/conversation.php: Addon::callHooks('render_location',$locate);
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/conversation.php: Addon::callHooks('jot_networks', $jotnets);
index.php: Addon::callHooks('init_1');
index.php:Addon::callHooks('app_menu', $arr);
index.php:Addon::callHooks('page_end', $a->page['content']);
mod/photos.php: Addon::callHooks('photo_post_init', $_POST);
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',intval($item_id));
mod/photos.php: Addon::callHooks('photo_upload_form',$ret);
mod/friendica.php: Addon::callHooks('about_hook', $o);
mod/editpost.php: Addon::callHooks('jot_tool', $jotplugins);
mod/editpost.php: Addon::callHooks('jot_networks', $jotnets);
mod/parse_url.php: Addon::callHooks('parse_link', $arr);
mod/home.php: Addon::callHooks('home_init',$ret);
mod/home.php: Addon::callHooks("home_content",$o);
mod/contacts.php: Addon::callHooks('contact_edit_post', $_POST);
mod/contacts.php: Addon::callHooks('contact_edit', $arr);
mod/settings.php: Addon::callHooks('addon_settings_post', $_POST);
mod/settings.php: Addon::callHooks('connector_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('settings_form',$o);
mod/register.php: Addon::callHooks('register_account', $newuid);
mod/like.php: Addon::callHooks('post_local_end', $arr);
mod/xrd.php: Addon::callHooks('personal_xrd', $arr);
mod/item.php: Addon::callHooks('post_local_start', $_REQUEST);
mod/item.php: Addon::callHooks('post_local',$datarray);
mod/item.php: Addon::callHooks('post_local_end', $datarray);
mod/profile.php: Addon::callHooks('profile_advanced',$o);
mod/profiles.php: Addon::callHooks('profile_post', $_POST);
mod/profiles.php: Addon::callHooks('profile_edit', $arr);
mod/tagger.php: Addon::callHooks('post_local_end', $arr);
mod/cb.php: Addon::callHooks('cb_init');
mod/cb.php: Addon::callHooks('cb_post', $_POST);
mod/cb.php: Addon::callHooks('cb_afterpost');
mod/cb.php: Addon::callHooks('cb_content', $o);
mod/directory.php: Addon::callHooks('directory_item', $arr); mod/directory.php: Addon::callHooks('directory_item', $arr);
src/Model/Item.php Addon::callHooks('tagged', $arr); mod/xrd.php: Addon::callHooks('personal_xrd', $arr);
mod/ping.php: Addon::callHooks('network_ping', $arr);
mod/parse_url.php: Addon::callHooks("parse_link", $arr);
mod/manage.php: Addon::callHooks('home_init', $ret);
mod/acl.php: Addon::callHooks('acl_lookup_end', $results);
mod/network.php: Addon::callHooks('network_content_init', $arr);
mod/network.php: Addon::callHooks('network_tabs', $arr);
mod/friendica.php: Addon::callHooks('about_hook', $o);
mod/subthread.php: Addon::callHooks('post_local_end', $arr);
mod/profiles.php: Addon::callHooks('profile_post', $_POST);
mod/profiles.php: Addon::callHooks('profile_edit', $arr);
mod/settings.php: Addon::callHooks('addon_settings_post', $_POST);
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/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/home.php: Addon::callHooks('home_init', $ret);
mod/home.php: Addon::callHooks("home_content", $content);
mod/poke.php: Addon::callHooks('post_local_end', $arr);
mod/contacts.php: Addon::callHooks('contact_edit_post', $_POST);
mod/contacts.php: Addon::callHooks('contact_edit', $arr);
mod/tagger.php: Addon::callHooks('post_local_end', $arr);
mod/lockview.php: Addon::callHooks('lockview_content', $item);
mod/uexport.php: Addon::callHooks('uexport_options', $options);
mod/register.php: Addon::callHooks('register_post', $arr);
mod/register.php: Addon::callHooks('register_form', $arr);
mod/item.php: Addon::callHooks('post_local_start', $_REQUEST);
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);
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);
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);
src/Model/Contact.php: Addon::callHooks('follow', $arr);
src/Model/Profile.php: Addon::callHooks('profile_sidebar_enter', $profile);
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']);
src/Model/Event.php: Addon::callHooks("event_created", $event['id']);
src/Model/User.php: Addon::callHooks('register_account', $uid);
src/Model/User.php: Addon::callHooks('remove_user', $user);
src/Content/Text/BBCode.php: Addon::callHooks('bbcode', $text);
src/Content/Text/BBCode.php: 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);
src/Content/Feature.php: Addon::callHooks('get', $arr);
src/Content/ContactSelector.php: Addon::callHooks('network_to_name', $nets);
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);
src/Content/Nav.php: Addon::callHooks('page_header', $a->page['nav']);
src/Content/Nav.php: 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);
src/Worker/Queue.php: Addon::callHooks('queue_deliver', $params);
src/Module/Login.php: Addon::callHooks('authenticate', $addon_auth);
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);
src/Object/Post.php: Addon::callHooks('display_item', $arr);
src/Core/ACL.php: Addon::callHooks('contact_select_options', $x);
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);
src/Util/Emailer.php: Addon::callHooks('emailer_send_prepare', $params);
src/Util/Emailer.php: Addon::callHooks("emailer_send", $hookdata);
src/Util/Map.php: Addon::callHooks('generate_map', $arr);
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);
src/Util/ParseUrl.php: Addon::callHooks("getsiteinfo", $siteinfo);
src/Protocol/DFRN.php: Addon::callHooks('atom_feed_end', $atom);
src/Protocol/DFRN.php: Addon::callHooks('atom_feed_end', $atom);

View file

@ -12,7 +12,7 @@ It's a command-line tool that downloads required libraries into the `vendor` fol
## How to use Composer ## How to use Composer
If you don't have Composer installed on your system, Friendica ships with a copy of it at `util/composer.phar`. If you don't have Composer installed on your system, Friendica ships with a copy of it at `bin/composer.phar`.
For the purpose of this help, all examples will use this path to run Composer commands, however feel free to replace them with your own way of calling Composer. For the purpose of this help, all examples will use this path to run Composer commands, however feel free to replace them with your own way of calling Composer.
Composer requires PHP CLI and the following examples assume it's available system-wide. Composer requires PHP CLI and the following examples assume it's available system-wide.
@ -30,7 +30,7 @@ Here are the typical commands you will have to run to do so:
```` ````
~> git clone https://github.com/friendica/friendica.git friendica ~> git clone https://github.com/friendica/friendica.git friendica
~/friendica> cd friendica ~/friendica> cd friendica
~/friendica> util/composer.phar install ~/friendica> bin/composer.phar install
```` ````
That's it! Composer will take care of fetching all the required libraries in the `vendor` folder and build the autoloader to make those libraries available to Friendica. That's it! Composer will take care of fetching all the required libraries in the `vendor` folder and build the autoloader to make those libraries available to Friendica.
@ -42,7 +42,7 @@ Updating Friendica to the current stable or the latest develop version is easy w
```` ````
~> cd friendica ~> cd friendica
~/friendica> git pull ~/friendica> git pull
~/friendica> util/composer.phar install ~/friendica> bin/composer.phar install
```` ````
And that's it. If any library used by Friendica has been upgraded, Composer will fetch the version currently used by Friendica and refresh the autoloader to ensure the best performances. And that's it. If any library used by Friendica has been upgraded, Composer will fetch the version currently used by Friendica and refresh the autoloader to ensure the best performances.
@ -87,13 +87,13 @@ Or you can specify the exact version of the library if you code requires it, and
To add a library, just add its Packagist identifier to the `require` list and set a target version string. To add a library, just add its Packagist identifier to the `require` list and set a target version string.
Then you should run `util/composer.phar update` to add it to your local `vendor` folder and update the `composer.lock` file that specifies the current versions of the dependencies. Then you should run `bin/composer.phar update` to add it to your local `vendor` folder and update the `composer.lock` file that specifies the current versions of the dependencies.
#### Updating an existing dependency #### Updating an existing dependency
If a package needs to be updated, whether to the next minor version or to the next major version provided you changed the adequate code in Friendica, simply edit `composer.json` to update the target version string of the relevant library. If a package needs to be updated, whether to the next minor version or to the next major version provided you changed the adequate code in Friendica, simply edit `composer.json` to update the target version string of the relevant library.
Then you should run `util/composer.phar update` to update it in your local `vendor` folder and update the `composer.lock` file that specifies the current versions of the dependencies. Then you should run `bin/composer.phar update` to update it in your local `vendor` folder and update the `composer.lock` file that specifies the current versions of the dependencies.
Please note that you should commit both `composer.json` and `composer.lock` with your work every time you make a change to the former. Please note that you should commit both `composer.json` and `composer.lock` with your work every time you make a change to the former.
@ -111,7 +111,7 @@ This is because `sudo` doesn't always change the `HOME` environment variable, wh
However, you can temporarily change environment variable for the execution of a single command. However, you can temporarily change environment variable for the execution of a single command.
For Composer, this would be: For Composer, this would be:
```` ````
$> COMPOSER_HOME=/var/tmp/composer sudo -u [web user] util/composer.phar [mode] $> COMPOSER_HOME=/var/tmp/composer sudo -u [web user] bin/composer.phar [mode]
```` ````
## Related ## Related

View file

@ -94,7 +94,7 @@ Please remove all the `require_once` mentions of the former file, as they will p
## Miscellaneous tips ## Miscellaneous tips
When you are done with moving the class, please run `php util/typo.php` from the Friendica base directory to check for obvious mistakes. When you are done with moving the class, please run `php bin/console.php typo` from the Friendica base directory to check for obvious mistakes.
Howevever, this tool isn't bullet-proof, and a staging install of Friendica is recommended to test your class move without impairing your production server if you host one. Howevever, this tool isn't bullet-proof, and a staging install of Friendica is recommended to test your class move without impairing your production server if you host one.
Most of Friendica processes are run in the background, so make sure to turn on your debug log to check for errors that wouldn't show up while simply browsing Friendica. Most of Friendica processes are run in the background, so make sure to turn on your debug log to check for errors that wouldn't show up while simply browsing Friendica.

View file

@ -16,7 +16,6 @@ Whether you feel like an expert or like a newbie - join us with your ideas!
The discussion of Friendica development takes place in the following Friendica forums: The discussion of Friendica development takes place in the following Friendica forums:
* The main [forum for Friendica development](https://forum.friendi.ca/profile/developers) * The main [forum for Friendica development](https://forum.friendi.ca/profile/developers)
* The [forum for Friendica theme development](https://friendica.eu/profile/ftdevs)
## Help other users ## Help other users
@ -61,7 +60,7 @@ If you want to have git automatically update the dependencies with composer, you
} }
# `composer install` if the `composer.lock` file gets changed # `composer install` if the `composer.lock` file gets changed
# to update all the php dependencies # to update all the php dependencies
check_run composer.lock "util/composer.phar install --no-dev" check_run composer.lock "bin/composer.phar install --no-dev"
just place it into `.git/hooks/post-merge` and make it executable. just place it into `.git/hooks/post-merge` and make it executable.
@ -141,7 +140,7 @@ If you want to get involved here:
* Look at the first steps that were made (e.g. the clean theme). * Look at the first steps that were made (e.g. the clean theme).
Ask us to find out whom to talk to about their experiences. Ask us to find out whom to talk to about their experiences.
* Talk to design people if you know any. * Talk to design people if you know any.
* Let us know about your plans [in the dev forum](https://forum.friendi.ca/profile/developers) or the [theme developer forum](https://friendica.eu/profile/ftdevs). * Let us know about your plans [in the dev forum](https://forum.friendi.ca/profile/developers)
Do not worry about cross-posting. Do not worry about cross-posting.
### Client software ### Client software

View file

@ -70,7 +70,8 @@ See Wikipedia for more of them ([video](http://en.wikipedia.org/wiki/HTML5_video
<a name="avatars"></a> <a name="avatars"></a>
### Is it possible to have different avatars per profile? ### Is it possible to have different avatars per profile?
Yes. On your Edit/Manage Profiles page, you will find a "change profile photo" link. Yes.
On your Edit/Manage Profiles page, you will find a "change profile photo" link.
Clicking this will take you to a page where you can upload a photograph and select which profile it will be associated with. Clicking this will take you to a page where you can upload a photograph and select which profile it will be associated with.
To avoid privacy leakage, we only display the photograph associated with your default profile as the avatar in your posts. To avoid privacy leakage, we only display the photograph associated with your default profile as the avatar in your posts.
@ -111,15 +112,9 @@ After that, your account is deleted.
<a name="hashtag"></a> <a name="hashtag"></a>
### Can I follow a hashtag? ### Can I follow a hashtag?
No. The act of 'following' a hashtags is an interesting technology, but presents a few issues. Yes. Simply add the hash tag to your saved searches.
The posts will appear on your network page.
1. Posts would have to be copied to all sites on the network that are "listening" to that hashtag. This would increase the storage demands to the detriment of small sites. It would make the use of shared hosting practically impossible. For technical reasons, your answers to such posts won't appear on the "personal" tab in the network page and the whole thread isn't accessible via the API.
2. Making spam easy (tag spam is a serious issue on Twitter for instance)
3. It creates a natural bias towards large sites which hold more tagged content - if your network uses tagging instead of other conversation federation mechanisms such as groups/forums.
Instead, we offer other mechanisms for wide-area conversations while retaining a 'level playing ground' for both large and small sites, such as forums and community pages and shared tags.
<a name="rss"></a> <a name="rss"></a>
### How to create a RSS feed of the stream? ### How to create a RSS feed of the stream?
@ -171,10 +166,15 @@ Depending on the features of the client you might encounter some glitches in usa
### Where I can find help? ### Where I can find help?
If you have problems with your Friendica page, you can ask the community at the [Friendica Support Group](https://forum.friendi.ca/profile/helpers). If you have problems with your Friendica page, you can ask the community at the [Friendica Support Group](https://forum.friendi.ca/profile/helpers).
If you can't use your default profile you can use an account at a public site [list](https://dir.friendica.social/servers) or you can use the Librelist mailing list. If you can't use your default profile you can use an account at a public site [list](https://dir.friendica.social/servers).
If you want to use the mailing list, please just send a mail to friendica AT librelist DOT com.
If you are a theme developer, you will find help at this forum: [Friendica Theme Developers](https://friendica.eu/profile/ftdevs). In case you do not want to set up another account on Friendica, you can also use one of the following channels to reach out for help:
* [Friendica Support Forum](https://forum.friendi.ca/~helpers)
* [Mailing List Archive](http://mailman.friendi.ca/mailman/listinfo/support-friendi.ca) you can subscribe to the list by sending an email to ``support-request(at)friendi.ca?subject=subscribe``
* XMPP/Jabber MUC: support(at)forum.friendi.ca
* IRC: #friendica at irc.freenode.net
* Matrix: #friendi.ca or #friendica at matrix.org
Admin Admin
-------- --------
@ -213,8 +213,8 @@ The listed emails need to be separated by a comma.
Please have a look at the Admin panel under [DB updates](/admin/dbsync/) and follow the link to *check database structure*. Please have a look at the Admin panel under [DB updates](/admin/dbsync/) and follow the link to *check database structure*.
This will start a background process to check if the structure is up to the current definition. This will start a background process to check if the structure is up to the current definition.
You can manually execute the structure update from the CLI in the base directory of your Friendica installation by running the following script: You can manually execute the structure update from the CLI in the base directory of your Friendica installation by running the following command:
scripts/dbstructure.php update bin/console dbstructure update
if there occur any errors, please contact the [support forum](https://forum.friendi.ca/profile/helpers). if there occur any errors, please contact the [support forum](https://forum.friendi.ca/profile/helpers).

View file

@ -13,7 +13,7 @@ Introduction to the workflow with our GitHub repository
3. Fork the Friendica repository from [https://github.com/friendica/friendica.git](https://github.com/friendica/friendica.git). 3. Fork the Friendica repository from [https://github.com/friendica/friendica.git](https://github.com/friendica/friendica.git).
4. Clone your fork from your GitHub account to your machine. 4. Clone your fork from your GitHub account to your machine.
Follow the instructions provided here: [http://help.github.com/fork-a-repo/](http://help.github.com/fork-a-repo/) to create and use your own tracking fork on GitHub Follow the instructions provided here: [http://help.github.com/fork-a-repo/](http://help.github.com/fork-a-repo/) to create and use your own tracking fork on GitHub
5. Run `util/composer.phar install` in Friendica's folder. 5. Run `bin/composer.phar install` in Friendica's folder.
6. Commit your changes to your fork. 6. Commit your changes to your fork.
Then go to your GitHub page and create a "Pull request" to notify us to merge your work. Then go to your GitHub page and create a "Pull request" to notify us to merge your work.
@ -68,7 +68,9 @@ If possible get an experienced Friendica developer to review the code.
Don't hesitate to ask us in case of doubt. Don't hesitate to ask us in case of doubt.
3. Check your code for typos. 3. Check your code for typos.
There is a PHP script in the *util* directory called *typos.php* for this. There is a console command called *typo* for this.
$> php bin/console.php typo
Check out how to work with [our Vagrant](help/Vagrant) to save a lot of setup time! Check out how to work with [our Vagrant](help/Vagrant) to save a lot of setup time!

View file

@ -28,7 +28,8 @@ 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 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)
* 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.)
@ -38,7 +39,7 @@ Requirements
Installation procedure Installation procedure
--- ---
###Get Friendica ### Get Friendica
Unpack the Friendica files into the root of your web server document area. Unpack the Friendica files into the root of your web server document area.
If you are able to do so, we recommend using git to clone the source repository rather than to use a packaged tar or zip file. If you are able to do so, we recommend using git to clone the source repository rather than to use a packaged tar or zip file.
@ -47,7 +48,7 @@ The Linux commands to clone the repository into a directory "mywebsite" would be
git clone https://github.com/friendica/friendica.git mywebsite git clone https://github.com/friendica/friendica.git mywebsite
cd mywebsite cd mywebsite
util/composer.phar install bin/composer.phar install
Make sure the folder *view/smarty3* exists and is writable by the webserver user Make sure the folder *view/smarty3* exists and is writable by the webserver user
@ -64,7 +65,7 @@ Clone the addon repository (separately):
If you copy the directory tree to your webserver, make sure that you also copy .htaccess - as "dot" files are often hidden and aren't normally copied. If you copy the directory tree to your webserver, make sure that you also copy .htaccess - as "dot" files are often hidden and aren't normally copied.
###Create a database ### Create a database
Create an empty database and note the access details (hostname, username, password, database name). Create an empty database and note the access details (hostname, username, password, database name).
@ -79,7 +80,7 @@ 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.
###Run the 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.
@ -96,19 +97,19 @@ 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.
###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.
Example: Example:
cd /base/directory; /path/to/php scripts/worker.php cd /base/directory; /path/to/php bin/worker.php
Change "/base/directory", and "/path/to/php" as appropriate for your situation. Change "/base/directory", and "/path/to/php" as appropriate for your situation.
If you are using a Linux server, run "crontab -e" and add a line like the If you are using a Linux server, run "crontab -e" and add a line like the
one shown, substituting for your unique paths and settings: one shown, substituting for your unique paths and settings:
*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php scripts/worker.php */10 * * * * cd /home/myname/mywebsite; /usr/bin/php bin/worker.php
You can generally find the location of PHP by executing "which php". You can generally find the location of PHP by executing "which php".
If you run into trouble with this section please contact your hosting provider for assistance. If you run into trouble with this section please contact your hosting provider for assistance.
@ -118,7 +119,8 @@ If it is not possible to set up a cron job then please activate the "frontend wo
Once you have installed Friendica and created an admin account as part of the process, you can access the admin panel of your installation and do most of the server wide configuration from there Once you have installed Friendica and created an admin account as part of the process, you can access the admin panel of your installation and do most of the server wide configuration from there
###Set up a backup plan ### Set up a backup plan
Bad things will happen. Bad things will happen.
Let there be a hardware failure, a corrupted database or whatever you can think of. Let there be a hardware failure, a corrupted database or whatever you can think of.
So once the installation of your Friendica node is done, you should make yourself a backup plan. So once the installation of your Friendica node is done, you should make yourself a backup plan.

View file

@ -3,21 +3,23 @@ Making Friends
* [Home](help) * [Home](help)
Friendship in Friendica can take on a great many different meanings. Friendship in Friendica can sometimes take on different meaning.
But let's keep it simple, you want to be friends with somebody. But let's keep it simple; you want to be friends with somebody.
How do you do it? How do you do it?
The Directories The Directories
--- ---
Friendica has two different kinds of "address book": Friendica has two different kinds of "address book".
The directory of the Friendica server you are registered on and the global directory that collects account information across all Friendica instances. The directory of the Friendica server you are registered on and a global directory to which your and other Friendica servers submit account information.
The first thing you can do is look at the **Directory**. The first thing you can do is look at the **Directory**.
The directory is split up into two parts. The directory is split up into two parts.
If you click the directory button, you will be presented with a list of all members (who chose to be listed) on your server. If you click the directory button, you will be presented with a list of all members (who chose to be listed) on your server.
You'll also see a link to the **Global Directory**. You'll also see a link to a **Global Directory**.
If you click through to the global directory, you will be presented with a list of everybody who chose to be listed across all instances of Friendica. There are several global directories across the globe that regularly exchange information with each other.
The specific global directory that you see usually depends on where your server is located.
If you click through to the global directory, you will be presented with a list of everybody who choses to be listed across all instances of Friendica.
You will also see a "Show Community Forums" link, which will direct you to Groups, Forums and Fanpages. You will also see a "Show Community Forums" link, which will direct you to Groups, Forums and Fanpages.
You connect to people, groups and forums in the same way, except groups and forums will automatically accept your introduction request, whereas a human will approve you manually. You connect to people, groups and forums in the same way, except groups and forums will automatically accept your introduction request, whereas a human will approve you manually.
@ -26,21 +28,18 @@ Connect to other Friendica users
Visit their profile. Visit their profile.
Just beneath their profile picture will be the word 'Connect' (we're assuming this is an English language profile). Just beneath their profile picture will be the word 'Connect' (we're assuming this is an English language profile).
Click that 'Connect' button. Click that 'Connect' button and it will take you to a 'Connect' form.
It will take you to a 'Connect' form.
The form is going to ask you for your Identity Address. The form is going to ask you for your Identity Address.
This is necessary so that this person's website can find yours. This is necessary so that this person's website can find yours.
What do you put in the box? If your Friendica site is called "demo.friendica.com" and your username/nickname on that site is "bob", you would enter "bob@demo.friendica.com" in this form.
If your Friendica site is called "demo.friendica.com" and your username/nickname on that site is "bob", you would put in "bob@demo.friendica.com".
Notice this looks just like an email address. Notice this looks just like an email address.
It was meant to be that way. It's meant to be that way.
It's easy for people to remember. It's easy for people to remember.
You *could* also put in the URL of your "home" page, such as "http://demo.friendica.com/profile/bob", but the email-style address is certainly easier. You *could* also put in the URL of your "home" page, such as "http://demo.friendica.com/profile/bob" instead of the email-style address.
When you've submitted the connection page, it will take you back to your own site where you must then login (if necessary) and verify the connection request on *your* site. When you've submitted the connection page, it will take you back to your own site where you must then login (if necessary) and verify the connection request on *your* site.
Once you've done this, the two websites can communicate with each other to complete the process (after your new friend has approved the request). Once you've done this, the two websites can communicate with each other to complete the process (after your new friend has approved the request).
@ -51,31 +50,40 @@ This will take you through a similar process.
Connect to users of alternate networks Connect to users of alternate networks
--- ---
###GNU Social, Twitter, Diaspora ###Across the Federation and Fedivese
You can also use your Identity Address or other people's Identity Addresses to become friends across networks. 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.
The list of possible networks is growing all the time. Currently, Friendica supports connections with people on diaspora*, Red, Hubzilla, GNU Social, StatusNet, Mastodon, Pleroma, socialhome, and ganggo platforms.
If you know (for instance) "bob" on gnusocial.de (a GNU Social site) you could put bob@gnusocial.de into your Contact page and become friends across networks.
(Or you can put in the URL to Bob's gnusocial.de page if you wish).
You can do the same for Twitter accounts and Diaspora accounts. If you know (for instance) "alice" on gnusocial.net (a GNU Social site) you could put alice@gnusocial.net into your Contact page and become friends across networks.
Likwise you can put in the URL to Alice's gnusocial.net page, if you wish.
Note: Some versions of GNU Social software may require the full URL to your profile and may not work with the identity address.
In fact, you can "follow" almost anybody or any website that produces a syndication feed (RSS/Atom,etc.). People on these networks can also initiate contact with you, if they know your contact details.
If we can find an information stream and a name to attach to the contact, we'll try to connect with them.
###Other social media
If you server provides this functionality, you can also connect with people one
Twitter or important feeds from Tumblr, Wordpress, and many more.
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.
People can also become friends with you from other networks. Create an email contact with for example Alice on Gmail, enter her email in following format "mailto:alice@gmail.no".
If a friend of yours has an GNU Social account, they can become friends with you by putting your Friendica Identity Address into their GNU Social subscription dialog box. In order to avoid abuse or spam, you must have an email from Alice with the correct email address in your email inbox.
A similar mechanism is available for Diaspora members, by putting your identity address into their search bar.
Note: Some versions of GNU Social software may require the full URL to your profile and may not work with the identity address. 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".
###Syndication feeds
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.
Notification Notification
--- ---
When somebody requests friendship you will receive a notification. When somebody requests friendship you will receive a notification.
You will need to approve this before the friendship is complete. You will usually need to approve this before the friendship is complete.
Approval Approval
--- ---
@ -84,16 +92,16 @@ Friendica does not allow this by default, as it would open a gateway for spam.
Unilateral or bilateral friendships Unilateral or bilateral friendships
--- ---
When you receive a friendship notification from another Friendica member, you will have the option of allowing them as a "fan" or as a "friend". When you receive a friendship notification from another Friendica member, you will have the option of allowing them as a "Follower" or as a "Friend".
If they are a fan, they can see what you have to say, including private communications that you send to them, but not vice versa. If they are a follower, they can see what you have to say, including private communications that you send to them, but not vice versa.
As a friend, you can both communicate with each other. As a friend, you can both communicate with each other.
Diaspora uses a different terminology, and you are given the option of allowing them to "share with you", or being full friends. diaspora* uses a different terminology, and you are given the option of allowing them to "share with you", or being full friends.
Ignoring, blocking and deleting contacts Ignoring, blocking and deleting contacts
--- ---
Once you have become friends, if you find the person constantly sends you spam or worthless information, you can "Ignore" them - without breaking off the friendship or even alerting them to the fact that you aren't interested in anything they are saying. Once you have become friends, if you find the person constantly sends you spam or worthless information, you can "Ignore" them - without breaking off the friendship or even alerting them to the fact that you aren't interested in anything they are saying.
In many ways they are like a "fan" - but they don't know this. In many ways they are like a "follower" - but they don't know this.
They think they are a friend. They think they are a friend.
You can also "block" a person. You can also "block" a person.

View file

@ -57,6 +57,21 @@ The `vier` theme for instance is mobile friendly.
### Registration ### Registration
#### Register policy
With this drop down selector you can set the nodes registration policy.
You can chose between the following modes:
* **open**: Everybody can register a new account and start using it right away.
* **requires approval**: Everybody can register a new account, but the admin has to approve it before it can be used.
* **closed**: No new registrations are possible.
##### Invitation based registry
Additionally to the setting in the admin panel, you can devide if registrations are only possible using an invitation code or not.
To enable invitation based registration, you have to set the `invitation_only` setting in the [.htconfig.php](/help/htconfig) file.
If you want to use this method, the registration policy has to be set to either *open* or *requires approval*.
#### Check Full Names #### Check Full Names
You may find a lot of spammers trying to register on your site. You may find a lot of spammers trying to register on your site.
@ -111,6 +126,14 @@ Unauthorised persons will also not be able to request friendship with site membe
Default is false. Default is false.
Available in version 2.2 or greater. Available in version 2.2 or greater.
#### Community pages for Visitors
The community pages show all public postings, separated by their origin being local or the entire network.
With this setting you can select which community pages will be shown to visitors of your Friendica node.
Your local users will always have access to both pages.
**Note**: Several settings, like users hiding their contacts from the public will prevent the postings to show up on the global community page.
#### Allowed Friend Domains #### Allowed Friend Domains
Comma separated list of domains which are allowed to establish friendships with this site. Comma separated list of domains which are allowed to establish friendships with this site.

View file

@ -21,7 +21,7 @@ You can get the latest changes at any time with
cd path/to/friendica cd path/to/friendica
git pull git pull
util/composer.phar install bin/composer.phar install
The addon tree has to be updated separately like so: The addon tree has to be updated separately like so:

View file

@ -294,6 +294,85 @@ Friendica doesn't allow showing the friends of other users.
--- ---
### lists/ownerships (*; AUTH)
#### Parameters
* list_id: ID of the list
* count: Items per page
* page: Page number
* since_id: Minimum ID
* max_id: Maximum ID
#### Unsupported parameters
* slug
* owner_screen_name
* owner_id
* include_entities
* include_rts
---
### lists/destroy (POST; AUTH)
#### Parameters
* list_id: ID of the list
#### Unsupported parameters
* owner_screen_name
* owner_id
* slug
---
### lists/create (POST; AUTH)
#### Parameters
* name: name of the list
#### Unsupported parameters
* mode
* description
---
### lists/update (POST; AUTH)
#### Parameters
* list_id: ID of the list
* name: name of the list
#### Unsupported parameters
* slug
* name
* mode
* description
* owner_screen_name
* owner_id
---
### lists/statuses (*; AUTH)
#### Parameters
* user_id: ID of the user for whom to return results.
#### Unsupported parameters
* screen_name
* count
* cursor
---
### media/upload (POST,PUT; AUTH) ### media/upload (POST,PUT; AUTH)
#### Parameters #### Parameters
@ -1237,7 +1316,6 @@ The following API calls from the Twitter API are not implemented in either Frien
* users/suggestions/:slug/members * users/suggestions/:slug/members
* favorites/list * favorites/list
* lists/list * lists/list
* lists/statuses
* lists/members/destroy * lists/members/destroy
* lists/memberships * lists/memberships
* lists/subscribers * lists/subscribers
@ -1248,13 +1326,9 @@ The following API calls from the Twitter API are not implemented in either Frien
* lists/members/show * lists/members/show
* lists/members * lists/members
* lists/members/create * lists/members/create
* lists/destroy
* lists/update
* lists/create
* lists/show * lists/show
* lists/subscriptions * lists/subscriptions
* lists/members/destroy_all * lists/members/destroy_all
* lists/ownerships
* saved_searches/show/:id * saved_searches/show/:id
* saved_searches/create * saved_searches/create
* saved_searches/destroy/:id * saved_searches/destroy/:id

View file

@ -189,178 +189,186 @@ Derzeitige Hooks
Komplette Liste der Hook-Callbacks Komplette Liste der Hook-Callbacks
--- ---
Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 14-Feb-2012 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.
boot.php: Addon::callHooks('login_hook',$o); index.php: Addon::callHooks('init_1');
index.php: Addon::callHooks('app_menu', $arr);
boot.php: Addon::callHooks('profile_sidebar_enter', $profile); index.php: Addon::callHooks('page_content_top', $a->page['content']);
index.php: Addon::callHooks($a->module.'_mod_init', $placeholder);
boot.php: Addon::callHooks('profile_sidebar', $arr); index.php: Addon::callHooks($a->module.'_mod_init', $placeholder);
index.php: Addon::callHooks($a->module.'_mod_post', $_POST);
boot.php: Addon::callHooks("proc_run", $arr); index.php: Addon::callHooks($a->module.'_mod_afterpost', $placeholder);
index.php: Addon::callHooks($a->module.'_mod_content', $arr);
include/contact_selectors.php: Addon::callHooks('network_to_name', $nets); 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); include/api.php: Addon::callHooks('logged_in', $a->user);
include/api.php: Addon::callHooks('authenticate', $addon_auth);
include/api.php: Addon::callHooks('logged_in', $a->user); include/api.php: Addon::callHooks('logged_in', $a->user);
include/queue.php: Addon::callHooks('queue_predeliver', $a, $r); include/enotify.php: Addon::callHooks('enotify', $h);
include/enotify.php: Addon::callHooks('enotify_store', $datarray);
include/enotify.php: Addon::callHooks('enotify_mail', $datarray);
include/enotify.php: Addon::callHooks('check_item_notification', $notification_data);
include/queue.php: Addon::callHooks('queue_deliver', $a, $params); include/conversation.php: Addon::callHooks('conversation_start', $cb);
include/conversation.php: Addon::callHooks('render_location', $locate);
include/text.php: Addon::callHooks('contact_block_end', $arr); include/conversation.php: Addon::callHooks('display_item', $arr);
include/conversation.php: Addon::callHooks('display_item', $arr);
include/text.php: Addon::callHooks('smilie', $s); include/conversation.php: Addon::callHooks('item_photo_menu', $args);
include/conversation.php: Addon::callHooks('jot_tool', $jotplugins);
include/text.php: Addon::callHooks('prepare_body_init', $item);
include/text.php: Addon::callHooks('prepare_body', $prep_arr);
include/text.php: Addon::callHooks('prepare_body_final', $prep_arr);
include/nav.php: Addon::callHooks('page_header', $a->page['nav']);
include/auth.php: Addon::callHooks('authenticate', $addon_auth);
include/bbcode.php: Addon::callHooks('bbcode',$Text);
include/oauth.php: Addon::callHooks('logged_in', $a->user);
include/acl_selectors.php: Addon::callHooks($a->module . '_pre_' . $selname, $arr);
include/acl_selectors.php: Addon::callHooks($a->module . '_post_' . $selname, $o);
include/acl_selectors.php: Addon::callHooks('contact_select_options', $x);
include/acl_selectors.php: Addon::callHooks($a->module . '_pre_' . $selname, $arr);
include/acl_selectors.php: Addon::callHooks($a->module . '_post_' . $selname, $o);
include/acl_selectors.php: Addon::callHooks($a->module . '_pre_' . $selname, $arr);
include/acl_selectors.php: Addon::callHooks($a->module . '_post_' . $selname, $o);
include/notifier.php: Addon::callHooks('notifier_normal',$target_item);
include/notifier.php: Addon::callHooks('notifier_end',$target_item);
include/items.php: Addon::callHooks('atom_feed', $atom);
include/items.php: Addon::callHooks('atom_feed_end', $atom);
include/items.php: Addon::callHooks('atom_feed_end', $atom);
include/items.php: Addon::callHooks('parse_atom', $arr);
include/items.php: Addon::callHooks('post_remote',$arr);
include/items.php: Addon::callHooks('atom_author', $o);
include/items.php: Addon::callHooks('atom_entry', $o);
include/bb2diaspora.php: Addon::callHooks('bb2diaspora',$Text);
include/cronhooks.php: Addon::callHooks('cron', $d);
include/security.php: Addon::callHooks('logged_in', $a->user); include/security.php: Addon::callHooks('logged_in', $a->user);
include/html2bbcode.php: Addon::callHooks('html2bbcode', $text); include/text.php: Addon::callHooks('contact_block_end', $arr);
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/Contact.php: Addon::callHooks('remove_user',$r[0]); include/items.php: Addon::callHooks('page_info_data', $data);
include/Contact.php: Addon::callHooks('contact_photo_menu', $args); mod/directory.php: Addon::callHooks('directory_item', $arr);
include/conversation.php: Addon::callHooks('conversation_start',$cb);
include/conversation.php: Addon::callHooks('render_location',$locate);
include/conversation.php: Addon::callHooks('display_item', $arr);
include/conversation.php: Addon::callHooks('render_location',$locate);
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/conversation.php: Addon::callHooks('jot_networks', $jotnets);
index.php: Addon::callHooks('init_1');
index.php: Addon::callHooks('app_menu', $arr);
index.php: Addon::callHooks('page_end', $a->page['content']);
mod/photos.php: Addon::callHooks('photo_post_init', $_POST);
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',intval($item_id));
mod/photos.php: Addon::callHooks('photo_upload_form',$ret);
mod/friendica.php: Addon::callHooks('about_hook', $o);
mod/editpost.php: Addon::callHooks('jot_tool', $jotplugins);
mod/editpost.php: Addon::callHooks('jot_networks', $jotnets);
mod/parse_url.php: Addon::callHooks('parse_link', $arr);
mod/home.php: Addon::callHooks('home_init',$ret);
mod/home.php: Addon::callHooks("home_content",$o);
mod/contacts.php: Addon::callHooks('contact_edit_post', $_POST);
mod/contacts.php: Addon::callHooks('contact_edit', $arr);
mod/settings.php: Addon::callHooks('addon_settings_post', $_POST);
mod/settings.php: Addon::callHooks('connector_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('settings_form',$o);
mod/register.php: Addon::callHooks('register_account', $newuid);
mod/like.php: Addon::callHooks('post_local_end', $arr);
mod/xrd.php: Addon::callHooks('personal_xrd', $arr); mod/xrd.php: Addon::callHooks('personal_xrd', $arr);
mod/item.php: Addon::callHooks('post_local_start', $_REQUEST); mod/ping.php: Addon::callHooks('network_ping', $arr);
mod/item.php: Addon::callHooks('post_local',$datarray); mod/parse_url.php: Addon::callHooks("parse_link", $arr);
mod/item.php: Addon::callHooks('post_local_end', $datarray); mod/manage.php: Addon::callHooks('home_init', $ret);
mod/profile.php: Addon::callHooks('profile_advanced',$o); mod/acl.php: Addon::callHooks('acl_lookup_end', $results);
mod/network.php: Addon::callHooks('network_content_init', $arr);
mod/network.php: Addon::callHooks('network_tabs', $arr);
mod/friendica.php: Addon::callHooks('about_hook', $o);
mod/subthread.php: Addon::callHooks('post_local_end', $arr);
mod/profiles.php: Addon::callHooks('profile_post', $_POST); mod/profiles.php: Addon::callHooks('profile_post', $_POST);
mod/profiles.php: Addon::callHooks('profile_edit', $arr); mod/profiles.php: Addon::callHooks('profile_edit', $arr);
mod/settings.php: Addon::callHooks('addon_settings_post', $_POST);
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/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/home.php: Addon::callHooks('home_init', $ret);
mod/home.php: Addon::callHooks("home_content", $content);
mod/poke.php: Addon::callHooks('post_local_end', $arr);
mod/contacts.php: Addon::callHooks('contact_edit_post', $_POST);
mod/contacts.php: Addon::callHooks('contact_edit', $arr);
mod/tagger.php: Addon::callHooks('post_local_end', $arr); mod/tagger.php: Addon::callHooks('post_local_end', $arr);
mod/cb.php: Addon::callHooks('cb_init'); mod/lockview.php: Addon::callHooks('lockview_content', $item);
mod/cb.php: Addon::callHooks('cb_post', $_POST); mod/uexport.php: Addon::callHooks('uexport_options', $options);
mod/cb.php: Addon::callHooks('cb_afterpost'); mod/register.php: Addon::callHooks('register_post', $arr);
mod/register.php: Addon::callHooks('register_form', $arr);
mod/cb.php: Addon::callHooks('cb_content', $o); mod/item.php: Addon::callHooks('post_local_start', $_REQUEST);
mod/item.php: Addon::callHooks('post_local', $datarray);
mod/item.php: Addon::callHooks('post_local_end', $datarray);
mod/directory.php: Addon::callHooks('directory_item', $arr); 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);
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);
src/Model/Contact.php: Addon::callHooks('follow', $arr);
src/Model/Profile.php: Addon::callHooks('profile_sidebar_enter', $profile);
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']);
src/Model/Event.php: Addon::callHooks("event_created", $event['id']);
src/Model/User.php: Addon::callHooks('register_account', $uid);
src/Model/User.php: Addon::callHooks('remove_user', $user);
src/Content/Text/BBCode.php: Addon::callHooks('bbcode', $text);
src/Content/Text/BBCode.php: 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);
src/Content/Feature.php: Addon::callHooks('get', $arr);
src/Content/ContactSelector.php: Addon::callHooks('network_to_name', $nets);
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);
src/Content/Nav.php: Addon::callHooks('page_header', $a->page['nav']);
src/Content/Nav.php: 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);
src/Worker/Queue.php: Addon::callHooks('queue_deliver', $params);
src/Module/Login.php: Addon::callHooks('authenticate', $addon_auth);
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);
src/Object/Post.php: Addon::callHooks('display_item', $arr);
src/Core/ACL.php: Addon::callHooks('contact_select_options', $x);
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);
src/Util/Emailer.php: Addon::callHooks('emailer_send_prepare', $params);
src/Util/Emailer.php: Addon::callHooks("emailer_send", $hookdata);
src/Util/Map.php: Addon::callHooks('generate_map', $arr);
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);
src/Util/ParseUrl.php: Addon::callHooks("getsiteinfo", $siteinfo);
src/Protocol/DFRN.php: Addon::callHooks('atom_feed_end', $atom);
src/Protocol/DFRN.php: Addon::callHooks('atom_feed_end', $atom);

View file

@ -10,7 +10,7 @@ Nutzer
* **[Ist es möglich, bei mehreren Profilen verschiedene Avatare (Nutzerbilder) zu haben?](help/FAQ#avatars)** * **[Ist es möglich, bei mehreren Profilen verschiedene Avatare (Nutzerbilder) zu haben?](help/FAQ#avatars)**
* **[Was ist der Unterschied zwischen blockierten|ignorierten|archivierten|versteckten Kontakten?](help/FAQ#contacts)** * **[Was ist der Unterschied zwischen blockierten|ignorierten|archivierten|versteckten Kontakten?](help/FAQ#contacts)**
* **[Was passiert, wenn ein Account gelöscht ist? Ist dieser richtig gelöscht?](help/FAQ#removed)** * **[Was passiert, wenn ein Account gelöscht ist? Ist dieser richtig gelöscht?](help/FAQ#removed)**
* **[Kann ich einem hashtag folgen?](help/FAQ#hashtag)** * **[Kann ich einem Hashtag folgen?](help/FAQ#hashtag)**
* **[Wie kann ich einen RSS-Feed meiner Netzwerkseite (Stream) erstellen?](help/FAQ#rss)** * **[Wie kann ich einen RSS-Feed meiner Netzwerkseite (Stream) erstellen?](help/FAQ#rss)**
* **[Gibt es Clients für Friendica?](help/FAQ#clients)** * **[Gibt es Clients für Friendica?](help/FAQ#clients)**
* **[Wo finde ich Hilfe?](help/FAQ#help)** * **[Wo finde ich Hilfe?](help/FAQ#help)**
@ -122,19 +122,11 @@ Dieses Vorgehen setzt voraus, dass Dein Profil für 24 Stunden weiterhin "teilwe
Wir können also Dein Profil blockieren und es so erscheinen lassen, als wären alle Daten sofort gelöscht, allerdings warten wir 24 Stunden (bzw. bis alle Deine Kontakte informiert wurden), bevor wir die Daten auch physikalisch löschen. Wir können also Dein Profil blockieren und es so erscheinen lassen, als wären alle Daten sofort gelöscht, allerdings warten wir 24 Stunden (bzw. bis alle Deine Kontakte informiert wurden), bevor wir die Daten auch physikalisch löschen.
<a name="hashtag"></a> <a name="hashtag"></a>
### Kann ich einem hashtag folgen? ### Kann ich einem Hashtag folgen?
Nein. Ja.
Die Möglichkeit, einem hashtag zu folgen, ist eine interessante Technik, führt aber zu einigen Schwierigkeiten. Füge die Tags zu Deinen gespeicherten Suchen hinzu, sie werden automatisch auf der Netzwerk-Seite auftauchen.
Bitte beachte, dass Deine Antworten auf solche Posts aus technischen Gründen nicht unter dem "Persönlich"-Reiter auf der Netzwerk-Seite und der gesamte Thread nicht per API zu sehen sind.
1.) Alle Beiträge, die diesen tag nutzen, müssten zu allen Seiten im Netzwerk kopiert werden. Das erhöht den Speicherbedarf und beeinträchtigt kleine Seiten. Die Nutzung von geteilten Hosting-Angeboten (Shared Hosting) wäre praktisch unmöglich.
2.) Die Verbreitung von Spam wäre vereinfacht (tag-Spam ist z.B. bei Twitter ein schwerwiegendes Problem)
3.) Der wichtigste Grund der gegen diese Technik spricht ist, dass sie eine natürliche Ausrichtung auf größere Seiten mit mehr getaggten Inhalten zur Folge hat. Dies kann z.B. aufkommen, wenn Dein Netzwerk tags anstelle von anderen Kommunikationsmitteln wie Gruppen oder Foren nutzt.
Stattdessen bieten wir andere Mechanismen, um globale Unterhaltungen zu erreichen, dabei aber eine angemesse Basis für kleine und große Seiten zu bieten.
Hierzu gehören Foren, Gruppen und geteilte tags.
<a name="rss"></a> <a name="rss"></a>
### Wie kann ich einen RSS-Feed meiner Netzwerkseite (Stream) erstellen? ### Wie kann ich einen RSS-Feed meiner Netzwerkseite (Stream) erstellen?
@ -189,10 +181,15 @@ Hier ist eine Liste von Clients bei denen dies möglich ist, bzw. die speziell f
### Wo finde ich Hilfe? ### Wo finde ich Hilfe?
Wenn Du Probleme mit Deiner Friendica-Seite hast, dann kannst Du die Community in der [Friendica-Support-Gruppe](https://forum.friendi.ca/profile/helpers) oder im [deutschen Friendica-Support-Forum](http://toktan.org/profile/wiki) fragen oder Dir das [deutsche Wiki](http://wiki.toktan.org/doku.php) anschauen. Wenn Du Probleme mit Deiner Friendica-Seite hast, dann kannst Du die Community in der [Friendica-Support-Gruppe](https://forum.friendi.ca/profile/helpers) oder im [deutschen Friendica-Support-Forum](http://toktan.org/profile/wiki) fragen oder Dir das [deutsche Wiki](http://wiki.toktan.org/doku.php) anschauen.
Wenn Du Deinen Account nicht nutzen kannst, kannst Du entweder einen [Testaccount](https://tryfriendica.de) bzw. einen Account auf einer öffentlichen Seite ([Liste](https://dir.friendica.social/servers)) nutzen, oder Du wählst die Librelist-mailing-Liste. Wenn Du Deinen Account nicht nutzen kannst, kannst Du entweder einen [Testaccount](https://tryfriendica.de) bzw. einen Account auf einer öffentlichen Seite ([Liste](https://dir.friendica.social/servers)) nutzen.
Wenn Du die Mailing-Liste nutzen willst, schicke eine Mail an friendica AT librelist PUNKT com.
Wenn Du ein Theme-Entwickler bist, wirst Du in diesem Forum Hilfe finden: [Friendica Theme Developers](https://friendica.eu/profile/ftdevs). Wenn du dir keinen weiteren Friendica Account einrichten willst, kannst du auch gerne über einen der folgenden alternativen Kanäle Hilfe suchen:
* [Friendica Support Forum](https://forum.friendi.ca/~helpers)
* [Mailing List Archive](http://mailman.friendi.ca/mailman/listinfo/support-friendi.ca) you can subscribe to the list by sending an email to ``support-request(at)friendi.ca?subject=subscribe``
* XMPP/Jabber MUC: support(at)forum.friendi.ca
* IRC: #friendica at irc.freenode.net
* Matrix: #friendi.ca or #friendica at matrix.org.
Admin Admin
-------- --------
@ -235,8 +232,8 @@ Rufe bitte im Admin Panel den Punkt [DB Updates](/admin/dbsync/) auf und folge d
Damit wird ein Hintergrundprozess gestartet der die Struktur deiner Datenbank überprüft und gegebenenfalls aktualisiert. Damit wird ein Hintergrundprozess gestartet der die Struktur deiner Datenbank überprüft und gegebenenfalls aktualisiert.
Du kannst das Struktur Updatee auch manuell auf der Kommandoeingabe ausführen. Du kannst das Struktur Updatee auch manuell auf der Kommandoeingabe ausführen.
Starte dazu bitte vom Grundverzeichnis deiner Friendica Instanz folgendes Skript: Starte dazu bitte vom Grundverzeichnis deiner Friendica Instanz folgendes Kommand:
scripts/dbstructure.php update bin/console dbstructure update
sollten bei der Ausführung Fehler auftreten, kontaktiere bitte das [Support Forum](https://forum.friendi.ca/profile/helpers). sollten bei der Ausführung Fehler auftreten, kontaktiere bitte das [Support Forum](https://forum.friendi.ca/profile/helpers).

View file

@ -24,8 +24,9 @@ Wir planen, diese Einschränkung in einer zukünftigen Version zu beheben.
- Apache mit einer aktiverten mod-rewrite-Funktion und dem Eintrag "Options All", so dass du die lokale .htaccess-Datei nutzen kannst - 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 5.6+. Je neuer, desto besser.
- PHP *Kommandozeilen*-Zugang mit register_argc_argv auf "true" gesetzt in der php.ini-Datei - PHP *Kommandozeilen*-Zugang mit register_argc_argv auf "true" gesetzt in der php.ini-Datei
- Curl, GD, PDO, MySQLi, xml und OpenSSL-Erweiterung - Curl, GD, PDO, MySQLi, xml, zip und OpenSSL-Erweiterung
- etwas in der Art eines Email-Servers oder eines Gateways wie PHP mail() - 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+ - 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] - 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. - 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.
@ -49,7 +50,7 @@ Wir planen, diese Einschränkung in einer zukünftigen Version zu beheben.
`cd meinewebseite` `cd meinewebseite`
`git pull` `git pull`
`util/composer.phar install` `bin/composer.phar install`
- Addons installieren - Addons installieren
- zunächst solltest du **in** deinem Webseitenordner sein - zunächst solltest du **in** deinem Webseitenordner sein
@ -86,13 +87,13 @@ Wenn du irgendwelche **kritischen** Fehler zu diesen Zeitpunkt erhalten solltest
7. Erstelle einen Cron job oder einen regelmäßigen Task, um den Poller alle 5-10 Minuten im Hintergrund ablaufen zu lassen. Beispiel: 7. 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 scripts/worker.php` `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.
Wenn du einen Linux-Server nutzt, benutze den Befehl "crontab -e" und ergänze eine Zeile wie die Folgende; angepasst an dein System Wenn du einen Linux-Server nutzt, benutze den Befehl "crontab -e" und ergänze eine Zeile wie die Folgende; angepasst an dein System
`*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php scripts/worker.php` `*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php bin/worker.php`
Du kannst den PHP-Pfad finden, indem du den Befehl „which php“ ausführst. Du kannst den PHP-Pfad finden, indem du den Befehl „which php“ ausführst.
Wenn du Schwierigkeiten mit diesem Schritt hast, kannst du deinen Hosting-Anbieter kontaktieren. Wenn du Schwierigkeiten mit diesem Schritt hast, kannst du deinen Hosting-Anbieter kontaktieren.

View file

@ -54,6 +54,20 @@ Das `vier` Theme z.B. unterstützt kleine Anzeigen und benötigt kein zusätzlic
### Registrierung ### Registrierung
#### Registrierungsmethode
Diese Einstellung regelt die Art der Registrierung.
Dabei kannst du zwischen den folgenden Optionen wählen:
* **Offen**: Jeder kann ein neues Nutzerkonto anlegen und es sofort benutzen.
* **Bedarf der Zustimmung**: Jeder kann ein Nutzerkonto anlegen. Dieses muss allerdings durch den Admin freigeschaltet werden, bevor es verwendet werden kann.
* **Geschlossen**: Es können keine weiteren Nutzerkonten angelegt werden.
##### Einladungen
Zusätzlich zu den oben genannten Möglichkeiten, kann die Registrierung eines neuen Nutzerkontos an eine Einladung durch einen bestehenden Nutzer gekoppelt werden.
Hierzu muss in der [.htconfig.php](/help/htconfig) Datei die Option `invitation_only` aktiviert und als Registrierungsmethode entweder *Offen* oder *Bedarf der Zustimmung* gewählt werden.
#### Namen auf Vollständigkeit überprüfen #### Namen auf Vollständigkeit überprüfen
Es kann vorkommen, dass viele Spammer versuchen, sich auf deiner Seite zu registrieren. Es kann vorkommen, dass viele Spammer versuchen, sich auf deiner Seite zu registrieren.
@ -108,6 +122,15 @@ Unautorisierte Personen haben ebenfalls nicht die Möglichkeit, Freundschaftsanf
Die Standardeinstellung ist deaktiviert. Die Standardeinstellung ist deaktiviert.
Verfügbar in Version 2.2 und höher. Verfügbar in Version 2.2 und höher.
#### Für Besucher verfügbare Gemeinschaftsseiten
Die Gemeinschaftsseiten zeigen all öffentlichen Beiträge.
Es gibt zwei Gemeinschaftsseiten, eine lokale auf der die Beiträge der Nutzer des Knotens gesammelt werden und eine globale auf der alle bekannten Beiträge aus dem gesamten Netzwerk erscheinen.
Mit dieser Einstellung kann geregelt werden, welche dieser beiden Seiten Besucher aufrufen können.
Angemeldete Nutzer des Knotens können grundsätzlich beide Seiten verwenden.
**Hinweis**: Einige Einstellungen, wie z.B. das Verbergen von Kontakten auf der Profilseite, können die Sichtbarkeit der Beiträge auf der Gemeinschaftsseiten beeinflussen.
#### Erlaubte Domains für Kontakte #### Erlaubte Domains für Kontakte
Kommagetrennte Liste von Domains, welche eine Freundschaft mit dieser Seite eingehen dürfen. Kommagetrennte Liste von Domains, welche eine Freundschaft mit dieser Seite eingehen dürfen.

View file

@ -25,8 +25,10 @@ Example: To set the automatic database cleanup process add this line to your .ht
* **allowed_link_protocols** (Array) - Allowed protocols in links URLs, add at your own risk. http is always allowed. * **allowed_link_protocols** (Array) - Allowed protocols in links URLs, add at your own risk. http is always allowed.
* **always_show_preview** (Boolean) - Only show small preview picures. Default value is false. * **always_show_preview** (Boolean) - Only show small preview picures. Default value is false.
* **block_local_dir** (Boolean) - Blocks the access to the directory of the local users. * **archival_days** (Integer) - Number of days that we try to deliver content before we archive a contact. Defaults to 32.
* **auth_cookie_lifetime** (Integer) - Number of days that should pass without any activity before a user who chose "Remember me" when logging in is considered logged out. Defaults to 7. * **auth_cookie_lifetime** (Integer) - Number of days that should pass without any activity before a user who chose "Remember me" when logging in is considered logged out. Defaults to 7.
* **block_local_dir** (Boolean) - Blocks the access to the directory of the local users.
* **config_adapter** (jit|preload) - Allow to switch the configuration adapter to improve performances at the cost of memory consumption. Default value is "jit"
* **curl_range_bytes** - Maximum number of bytes that should be fetched. Default is 0, which mean "no limit". * **curl_range_bytes** - Maximum number of bytes that should be fetched. Default is 0, which mean "no limit".
* **db_log** - Name of a logfile to log slow database queries * **db_log** - Name of a logfile to log slow database queries
* **db_loglimit** - If a database call lasts longer than this value it is logged * **db_loglimit** - If a database call lasts longer than this value it is logged
@ -40,6 +42,7 @@ Example: To set the automatic database cleanup process add this line to your .ht
* **diaspora_test** (Boolean) - For development only. Disables the message transfer. * **diaspora_test** (Boolean) - For development only. Disables the message transfer.
* **disable_email_validation** (Boolean) - Disables the check if a mail address is in a valid format and can be resolved via DNS. * **disable_email_validation** (Boolean) - Disables the check if a mail address is in a valid format and can be resolved via DNS.
* **disable_url_validation** (Boolean) - Disables the DNS lookup of an URL. * **disable_url_validation** (Boolean) - Disables the DNS lookup of an URL.
* **disable_password_exposed** (Boolean) - Disable the exposition check against the remote haveibeenpwned API on password change. Default value is false.
* **dlogfile - location of the developer log file * **dlogfile - location of the developer log file
* **dlogip - restricts develop log writes to requests originating from this IP address * **dlogip - restricts develop log writes to requests originating from this IP address
* **frontend_worker_timeout** - Value in minutes after we think that a frontend task was killed by the webserver. Default value is 10. * **frontend_worker_timeout** - Value in minutes after we think that a frontend task was killed by the webserver. Default value is 10.
@ -47,6 +50,7 @@ Example: To set the automatic database cleanup process add this line to your .ht
* **ignore_cache** (Boolean) - For development only. Disables the item cache. * **ignore_cache** (Boolean) - For development only. Disables the item cache.
* **instances_social_key** - Key to the API of https://instances.social which retrieves data about mastodon servers. See https://instances.social/api/token to get an API key. * **instances_social_key** - Key to the API of https://instances.social which retrieves data about mastodon servers. See https://instances.social/api/token to get an API key.
* **ipv4_resolve** (Boolean) - Resolve IPV4 addresses only. Don't resolve to IPV6. Default value is false. * **ipv4_resolve** (Boolean) - Resolve IPV4 addresses only. Don't resolve to IPV6. Default value is false.
* **invitation_only** (Boolean) - If set true registration is only possible after a current member of the node has send an invitation. Default is false.
* **like_no_comment** (Boolean) - Don't update the "commented" value of an item when it is liked. * **like_no_comment** (Boolean) - Don't update the "commented" value of an item when it is liked.
* **local_block** (Boolean) - Used in conjunction with "block_public". * **local_block** (Boolean) - Used in conjunction with "block_public".
* **local_search** (Boolean) - Blocks search for users who are not logged in to prevent crawlers from blocking your system. * **local_search** (Boolean) - Blocks search for users who are not logged in to prevent crawlers from blocking your system.
@ -82,11 +86,6 @@ Example: To set the automatic database cleanup process add this line to your .ht
* **proxy_cache_time** - Time after which the cache is cleared. Default value is one day. * **proxy_cache_time** - Time after which the cache is cleared. Default value is one day.
* **pushpoll_frequency** - * **pushpoll_frequency** -
* **qsearch_limit** - Default value is 100. * **qsearch_limit** - Default value is 100.
* **relay_server** - Experimental Diaspora feature. Address of the relay server where public posts should be send to. For example https://podrelay.net
* **relay_subscribe** (Boolean) - Enables the receiving of public posts from the relay. They will be included in the search and on the community page when it is set up to show all public items.
* **relay_scope** - Can be "all" or "tags". "all" means that every public post should be received. "tags" means that only posts with selected tags should be received.
* **relay_server_tags** - Comma separated list of tags for the "tags" subscription (see "relay_scrope")
* **relay_user_tags** (Boolean) - If enabled, the tags from the saved searches will used for the "tags" subscription in addition to the "relay_server_tags".
* **remove_multiplicated_lines** (Boolean) - If enabled, multiple linefeeds in items are stripped to a single one. * **remove_multiplicated_lines** (Boolean) - If enabled, multiple linefeeds in items are stripped to a single one.
* **show_unsupported_addons** (Boolean) - Show all addons including the unsupported ones. * **show_unsupported_addons** (Boolean) - Show all addons including the unsupported ones.
* **show_unsupported_themes** (Boolean) - Show all themes including the unsupported ones. * **show_unsupported_themes** (Boolean) - Show all themes including the unsupported ones.

View file

@ -11,16 +11,16 @@ Installation
- Change it's owner to whichever user is running the server, ie. ejabberd - Change it's owner to whichever user is running the server, ie. ejabberd
$ chown ejabberd:ejabberd /path/to/friendica/include/auth_ejabberd.php $ chown ejabberd:ejabberd /path/to/friendica/bin/auth_ejabberd.php
- Change the access mode so it is readable only to the user ejabberd and has exec - Change the access mode so it is readable only to the user ejabberd and has exec
$ chmod 700 /path/to/friendica/include/auth_ejabberd.php $ chmod 700 /path/to/friendica/bin/auth_ejabberd.php
- Edit your ejabberd.cfg file, comment out your auth_method and add: - Edit your ejabberd.cfg file, comment out your auth_method and add:
{auth_method, external}. {auth_method, external}.
{extauth_program, "/path/to/friendica/include/auth_ejabberd.php"}. {extauth_program, "/path/to/friendica/bin/auth_ejabberd.php"}.
- Disable the module "mod_register" and disable the registration: - Disable the module "mod_register" and disable the registration:

View file

@ -6,7 +6,6 @@ To change the look of friendica you have to touch the themes.
The current default theme is [Vier](https://github.com/friendica/friendica/tree/master/view/theme/vier) but there are numerous others. The current default theme is [Vier](https://github.com/friendica/friendica/tree/master/view/theme/vier) but there are numerous others.
Have a look at [friendica-themes.com](http://friendica-themes.com) for an overview of the existing themes. Have a look at [friendica-themes.com](http://friendica-themes.com) for an overview of the existing themes.
In case none of them suits your needs, there are several ways to change a theme. In case none of them suits your needs, there are several ways to change a theme.
If you need help theming, there is a forum @[ftdevs@friendica.eu](https://friendica.eu/profile/ftdevs) where you can ask theme specific questions and present your themes.
So, how to work on the UI of friendica. So, how to work on the UI of friendica.
@ -206,7 +205,7 @@ Basically what you have to do is identify which template you have to change so i
Adopt the CSS of the theme accordingly. Adopt the CSS of the theme accordingly.
And iterate the process until you have the theme the way you want it. And iterate the process until you have the theme the way you want it.
*Use the source Luke.* and don't hesitate to ask in @[ftdevs](https://friendica.eu/profile/ftdevs) or @[helpers](https://forum.friendi.ca/profile/helpers). *Use the source Luke.* and don't hesitate to ask in @[developers](https://forum.friendi.ca/profile/developers) or @[helpers](https://forum.friendi.ca/profile/helpers).
## Special Files ## Special Files

View file

@ -29,20 +29,21 @@ The location of the translated files in the source tree is
/view/lang/LNG-CODE/ /view/lang/LNG-CODE/
where LNG-CODE is the language code used, e.g. de for German or fr for French. where LNG-CODE is the language code used, e.g. de for German or fr for French.
The translated strings come as a "message.po" file from transifex which needs to be translated into the PHP file friendica uses. The translated strings come as a "message.po" file from transifex which needs to be translated into the PHP file friendica uses.
To do so, place the file in the directory mentioned above and use the "po2php" utility from the util directory of your friendica installation. To do so, place the file in the directory mentioned above and use the "po2php" command from the Friendica Console.
Assuming you want to convert the German localization which is placed in view/lang/de/message.po you would do the following. Assuming you want to convert the German localization which is placed in view/lang/de/message.po you would do the following.
1. Navigate at the command prompt to the base directory of your 1. Navigate at the command prompt to the base directory of your
friendica installation friendica installation
2. Execute the po2php script, which will place the translation 2. Execute the po2php command, which will place the translation
in the strings.php file that is used by friendica. in the strings.php file that is used by friendica.
$> php util/po2php.php view/lang/de/messages.po $> php bin/console.php po2php view/lang/de/messages.po
The output of the script will be placed at view/lang/de/strings.php where The output of the script will be placed at view/lang/de/strings.php where
friendica is expecting it, so you can test your translation immediately. friendica is expecting it, so you can test your translation immediately.
*Please note that the console tool has to be called from the base directory of your Friendica installation.*
3. Visit your friendica page to check if it still works in the language you 3. Visit your friendica page to check if it still works in the language you
just translated. If not try to find the error, most likely PHP will give just translated. If not try to find the error, most likely PHP will give
@ -64,7 +65,7 @@ Otherwise your work might get lost, when the translation from Transifex is inclu
Utilities Utilities
--------- ---------
Additional to the po2php script there are some more utilities for translation in the "util" directory of the friendica source tree. Additional to the po2php command there are some more utilities for translation in the console.
If you only want to translate friendica into another language you wont need any of these tools most likely but it gives you an idea how the translation process of friendica works. If you only want to translate friendica into another language you wont need any of these tools most likely but it gives you an idea how the translation process of friendica works.
For further information see the utils/README file. For further information see the utils/README file.
@ -92,9 +93,9 @@ To update the translation files after you have translated strings of e.g. Espera
$> tx pull -l eo $> tx pull -l eo
And then use the `po2php` utility described above to convert the `messages.po` file to the `strings.php` file Friendica is loading. And then use the `po2php` command described above to convert the `messages.po` file to the `strings.php` file Friendica is loading.
$> php util/po2php.php view/lang/eo/messages.po $> php bin/console.php po2php view/lang/eo/messages.po
Afterwards, just commit the two changed files to a feature branch of your Friendica repository, push the changes to github and open a pull request for your changes. Afterwards, just commit the two changed files to a feature branch of your Friendica repository, push the changes to github and open a pull request for your changes.

File diff suppressed because one or more lines are too long

View file

@ -2,6 +2,11 @@
// If automatic system installation fails: // If automatic system installation fails:
die('The configuration you did manually contains some mistakes. Please have a look at your .htconfig.php file.');
// If you are doing the configuration manually, please remove the line above
// Copy or rename this file to .htconfig.php // Copy or rename this file to .htconfig.php
// Why .htconfig.php? Because it contains sensitive information which could // Why .htconfig.php? Because it contains sensitive information which could

View file

@ -10,6 +10,7 @@ use Friendica\App;
use Friendica\Content\ContactSelector; use Friendica\Content\ContactSelector;
use Friendica\Content\Feature; use Friendica\Content\Feature;
use Friendica\Content\Text\BBCode; use Friendica\Content\Text\BBCode;
use Friendica\Content\Text\HTML;
use Friendica\Core\Addon; use Friendica\Core\Addon;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\L10n; use Friendica\Core\L10n;
@ -41,11 +42,9 @@ use Friendica\Util\Network;
use Friendica\Util\XML; use Friendica\Util\XML;
require_once 'include/conversation.php'; require_once 'include/conversation.php';
require_once 'include/html2plain.php';
require_once 'mod/share.php'; require_once 'mod/share.php';
require_once 'mod/item.php'; require_once 'mod/item.php';
require_once 'include/security.php'; require_once 'include/security.php';
require_once 'include/html2bbcode.php';
require_once 'mod/wall_upload.php'; require_once 'mod/wall_upload.php';
require_once 'mod/proxy.php'; require_once 'mod/proxy.php';
@ -224,7 +223,7 @@ function api_login(App $a)
$record = $addon_auth['user_record']; $record = $addon_auth['user_record'];
} else { } else {
$user_id = User::authenticate(trim($user), trim($password)); $user_id = User::authenticate(trim($user), trim($password));
if ($user_id) { if ($user_id !== false) {
$record = dba::selectFirst('user', [], ['uid' => $user_id]); $record = dba::selectFirst('user', [], ['uid' => $user_id]);
} }
} }
@ -268,7 +267,7 @@ function api_check_method($method)
* @brief Main API entry point * @brief Main API entry point
* *
* @param object $a App * @param object $a App
* @return string API call result * @return string|array API call result
*/ */
function api_call(App $a) function api_call(App $a)
{ {
@ -388,9 +387,7 @@ function api_call(App $a)
break; break;
case "json": case "json":
header("Content-Type: application/json"); header("Content-Type: application/json");
foreach ($return as $rr) { $json = json_encode(end($return));
$json = json_encode($rr);
}
if (x($_GET, 'callback')) { if (x($_GET, 'callback')) {
$json = $_GET['callback'] . "(" . $json . ")"; $json = $_GET['callback'] . "(" . $json . ")";
} }
@ -422,7 +419,7 @@ function api_call(App $a)
* *
* @param string $type Return type (xml, json, rss, as) * @param string $type Return type (xml, json, rss, as)
* @param object $e HTTPException Error object * @param object $e HTTPException Error object
* @return string error message formatted as $type * @return string|array error message formatted as $type
*/ */
function api_error($type, $e) function api_error($type, $e)
{ {
@ -532,7 +529,7 @@ function api_get_user(App $a, $contact_id = null)
// Searching for contact id with uid = 0 // Searching for contact id with uid = 0
if (!is_null($contact_id) && (intval($contact_id) != 0)) { if (!is_null($contact_id) && (intval($contact_id) != 0)) {
$user = dbesc(api_unique_id_to_nurl($contact_id)); $user = dbesc(api_unique_id_to_nurl(intval($contact_id)));
if ($user == "") { if ($user == "") {
throw new BadRequestException("User not found."); throw new BadRequestException("User not found.");
@ -578,17 +575,15 @@ function api_get_user(App $a, $contact_id = null)
$argid = count($called_api); $argid = count($called_api);
list($user, $null) = explode(".", $a->argv[$argid]); list($user, $null) = explode(".", $a->argv[$argid]);
if (is_numeric($user)) { if (is_numeric($user)) {
$user = dbesc(api_unique_id_to_nurl($user)); $user = dbesc(api_unique_id_to_nurl(intval($user)));
if ($user == "") {
return false;
}
if ($user != "") {
$url = $user; $url = $user;
$extra_query = "AND `contact`.`nurl` = '%s' "; $extra_query = "AND `contact`.`nurl` = '%s' ";
if (api_user() !== false) { if (api_user() !== false) {
$extra_query .= "AND `contact`.`uid`=" . intval(api_user()); $extra_query .= "AND `contact`.`uid`=" . intval(api_user());
} }
}
} else { } else {
$user = dbesc($user); $user = dbesc($user);
$extra_query = "AND `contact`.`nick` = '%s' "; $extra_query = "AND `contact`.`nick` = '%s' ";
@ -621,7 +616,9 @@ function api_get_user(App $a, $contact_id = null)
); );
// Selecting the id by priority, friendica first // Selecting the id by priority, friendica first
if (is_array($uinfo)) {
api_best_nickname($uinfo); api_best_nickname($uinfo);
}
// if the contact wasn't found, fetch it from the contacts with uid = 0 // if the contact wasn't found, fetch it from the contacts with uid = 0
if (!DBM::is_result($uinfo)) { if (!DBM::is_result($uinfo)) {
@ -648,6 +645,8 @@ function api_get_user(App $a, $contact_id = null)
'description' => $r[0]["about"], 'description' => $r[0]["about"],
'profile_image_url' => $r[0]["micro"], 'profile_image_url' => $r[0]["micro"],
'profile_image_url_https' => $r[0]["micro"], 'profile_image_url_https' => $r[0]["micro"],
'profile_image_url_profile_size' => $r[0]["thumb"],
'profile_image_url_large' => $r[0]["photo"],
'url' => $r[0]["url"], 'url' => $r[0]["url"],
'protected' => false, 'protected' => false,
'followers_count' => 0, 'followers_count' => 0,
@ -783,6 +782,8 @@ function api_get_user(App $a, $contact_id = null)
'description' => $description, 'description' => $description,
'profile_image_url' => $uinfo[0]['micro'], 'profile_image_url' => $uinfo[0]['micro'],
'profile_image_url_https' => $uinfo[0]['micro'], 'profile_image_url_https' => $uinfo[0]['micro'],
'profile_image_url_profile_size' => $uinfo[0]["thumb"],
'profile_image_url_large' => $uinfo[0]["photo"],
'url' => $uinfo[0]['url'], 'url' => $uinfo[0]['url'],
'protected' => false, 'protected' => false,
'followers_count' => intval($countfollowers), 'followers_count' => intval($countfollowers),
@ -978,7 +979,7 @@ function api_create_xml($data, $root_element)
* @param string $type Return type (atom, rss, xml, json) * @param string $type Return type (atom, rss, xml, json)
* @param array $data JSON style array * @param array $data JSON style array
* *
* @return (string|object|array) XML data or JSON data * @return (string|array) XML data or JSON data
*/ */
function api_format_data($root_element, $type, $data) function api_format_data($root_element, $type, $data)
{ {
@ -989,6 +990,7 @@ function api_format_data($root_element, $type, $data)
$ret = api_create_xml($data, $root_element); $ret = api_create_xml($data, $root_element);
break; break;
case "json": case "json":
default:
$ret = $data; $ret = $data;
break; break;
} }
@ -1096,7 +1098,7 @@ function api_statuses_mediap($type)
$purifier = new HTMLPurifier($config); $purifier = new HTMLPurifier($config);
$txt = $purifier->purify($txt); $txt = $purifier->purify($txt);
} }
$txt = html2bbcode($txt); $txt = HTML::toBBCode($txt);
$a->argv[1]=$user_info['screen_name']; //should be set to username? $a->argv[1]=$user_info['screen_name']; //should be set to username?
@ -1147,7 +1149,7 @@ function api_statuses_update($type)
$purifier = new HTMLPurifier($config); $purifier = new HTMLPurifier($config);
$txt = $purifier->purify($txt); $txt = $purifier->purify($txt);
$_REQUEST['body'] = html2bbcode($txt); $_REQUEST['body'] = HTML::toBBCode($txt);
} }
} else { } else {
$_REQUEST['body'] = requestdata('status'); $_REQUEST['body'] = requestdata('status');
@ -1426,7 +1428,7 @@ function api_status_show($type)
$status_info["entities"] = $converted["entities"]; $status_info["entities"] = $converted["entities"];
} }
if (($lastwall['item_network'] != "") && ($status["source"] == 'web')) { if (($lastwall['item_network'] != "") && ($status_info["source"] == 'web')) {
$status_info["source"] = ContactSelector::networkToName($lastwall['item_network'], $user_info['url']); $status_info["source"] = ContactSelector::networkToName($lastwall['item_network'], $user_info['url']);
} elseif (($lastwall['item_network'] != "") && (ContactSelector::networkToName($lastwall['item_network'], $user_info['url']) != $status_info["source"])) { } elseif (($lastwall['item_network'] != "") && (ContactSelector::networkToName($lastwall['item_network'], $user_info['url']) != $status_info["source"])) {
$status_info["source"] = trim($status_info["source"].' ('.ContactSelector::networkToName($lastwall['item_network'], $user_info['url']).')'); $status_info["source"] = trim($status_info["source"].' ('.ContactSelector::networkToName($lastwall['item_network'], $user_info['url']).')');
@ -1435,7 +1437,6 @@ function api_status_show($type)
// "uid" and "self" are only needed for some internal stuff, so remove it from here // "uid" and "self" are only needed for some internal stuff, so remove it from here
unset($status_info["user"]["uid"]); unset($status_info["user"]["uid"]);
unset($status_info["user"]["self"]); unset($status_info["user"]["self"]);
}
logger('status_info: '.print_r($status_info, true), LOGGER_DEBUG); logger('status_info: '.print_r($status_info, true), LOGGER_DEBUG);
@ -1444,6 +1445,7 @@ function api_status_show($type)
} }
return api_format_data("statuses", $type, ['status' => $status_info]); return api_format_data("statuses", $type, ['status' => $status_info]);
}
} }
/** /**
@ -1627,6 +1629,13 @@ api_register_func('api/users/lookup', 'api_users_lookup', true);
*/ */
function api_search($type) function api_search($type)
{ {
$a = get_app();
$user_info = api_get_user($a);
if (api_user() === false || $user_info === false) {
throw new ForbiddenException();
}
$data = []; $data = [];
$sql_extra = ''; $sql_extra = '';
@ -1665,7 +1674,7 @@ function api_search($type)
$since_id $since_id
); );
$data['status'] = api_format_items(dba::inArray($r), api_get_user(get_app())); $data['status'] = api_format_items(dba::inArray($r), $user_info);
return api_format_data("statuses", $type, $data); return api_format_data("statuses", $type, $data);
} }
@ -1687,8 +1696,9 @@ api_register_func('api/search', 'api_search', true);
function api_statuses_home_timeline($type) function api_statuses_home_timeline($type)
{ {
$a = get_app(); $a = get_app();
$user_info = api_get_user($a);
if (api_user() === false) { if (api_user() === false || $user_info === false) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
@ -1698,8 +1708,7 @@ function api_statuses_home_timeline($type)
unset($_REQUEST["screen_name"]); unset($_REQUEST["screen_name"]);
unset($_GET["screen_name"]); unset($_GET["screen_name"]);
$user_info = api_get_user($a); // get last network messages
// get last newtork messages
// params // params
$count = (x($_REQUEST, 'count') ? $_REQUEST['count'] : 20); $count = (x($_REQUEST, 'count') ? $_REQUEST['count'] : 20);
@ -1789,13 +1798,13 @@ api_register_func('api/statuses/friends_timeline', 'api_statuses_home_timeline',
function api_statuses_public_timeline($type) function api_statuses_public_timeline($type)
{ {
$a = get_app(); $a = get_app();
$user_info = api_get_user($a);
if (api_user() === false) { if (api_user() === false || $user_info === false) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
$user_info = api_get_user($a); // get last network messages
// get last newtork messages
// params // params
$count = (x($_REQUEST, 'count') ? $_REQUEST['count'] : 20); $count = (x($_REQUEST, 'count') ? $_REQUEST['count'] : 20);
@ -1898,13 +1907,12 @@ api_register_func('api/statuses/public_timeline', 'api_statuses_public_timeline'
function api_statuses_networkpublic_timeline($type) function api_statuses_networkpublic_timeline($type)
{ {
$a = get_app(); $a = get_app();
$user_info = api_get_user($a);
if (api_user() === false) { if (api_user() === false || $user_info === false) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
$user_info = api_get_user($a);
$since_id = x($_REQUEST, 'since_id') ? $_REQUEST['since_id'] : 0; $since_id = x($_REQUEST, 'since_id') ? $_REQUEST['since_id'] : 0;
$max_id = x($_REQUEST, 'max_id') ? $_REQUEST['max_id'] : 0; $max_id = x($_REQUEST, 'max_id') ? $_REQUEST['max_id'] : 0;
@ -1968,13 +1976,12 @@ api_register_func('api/statuses/networkpublic_timeline', 'api_statuses_networkpu
function api_statuses_show($type) function api_statuses_show($type)
{ {
$a = get_app(); $a = get_app();
$user_info = api_get_user($a);
if (api_user() === false) { if (api_user() === false || $user_info === false) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
$user_info = api_get_user($a);
// params // params
$id = intval($a->argv[3]); $id = intval($a->argv[3]);
@ -2042,13 +2049,12 @@ api_register_func('api/statuses/show', 'api_statuses_show', true);
function api_conversation_show($type) function api_conversation_show($type)
{ {
$a = get_app(); $a = get_app();
$user_info = api_get_user($a);
if (api_user() === false) { if (api_user() === false || $user_info === false) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
$user_info = api_get_user($a);
// params // params
$id = intval($a->argv[3]); $id = intval($a->argv[3]);
$count = (x($_REQUEST, 'count') ? $_REQUEST['count'] : 20); $count = (x($_REQUEST, 'count') ? $_REQUEST['count'] : 20);
@ -2255,8 +2261,9 @@ api_register_func('api/statuses/destroy', 'api_statuses_destroy', true, API_METH
function api_statuses_mentions($type) function api_statuses_mentions($type)
{ {
$a = get_app(); $a = get_app();
$user_info = api_get_user($a);
if (api_user() === false) { if (api_user() === false || $user_info === false) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
@ -2266,9 +2273,7 @@ function api_statuses_mentions($type)
unset($_REQUEST["screen_name"]); unset($_REQUEST["screen_name"]);
unset($_GET["screen_name"]); unset($_GET["screen_name"]);
$user_info = api_get_user($a); // get last network messages
// get last newtork messages
// params // params
$since_id = defaults($_REQUEST, 'since_id', 0); $since_id = defaults($_REQUEST, 'since_id', 0);
@ -2347,13 +2352,12 @@ api_register_func('api/statuses/replies', 'api_statuses_mentions', true);
function api_statuses_user_timeline($type) function api_statuses_user_timeline($type)
{ {
$a = get_app(); $a = get_app();
$user_info = api_get_user($a);
if (api_user() === false) { if (api_user() === false || $user_info === false) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
$user_info = api_get_user($a);
logger( logger(
"api_statuses_user_timeline: api_user: ". api_user() . "api_statuses_user_timeline: api_user: ". api_user() .
"\nuser_info: ".print_r($user_info, true) . "\nuser_info: ".print_r($user_info, true) .
@ -2517,15 +2521,14 @@ function api_favorites($type)
global $called_api; global $called_api;
$a = get_app(); $a = get_app();
$user_info = api_get_user($a);
if (api_user() === false) { if (api_user() === false || $user_info === false) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
$called_api = []; $called_api = [];
$user_info = api_get_user($a);
// in friendica starred item are private // in friendica starred item are private
// return favorites only for self // return favorites only for self
logger('api_favorites: self:' . $user_info['self']); logger('api_favorites: self:' . $user_info['self']);
@ -2624,10 +2627,10 @@ function api_format_messages($item, $recipient, $sender)
if ($_GET['getText'] == 'html') { if ($_GET['getText'] == 'html') {
$ret['text'] = BBCode::convert($item['body'], false); $ret['text'] = BBCode::convert($item['body'], false);
} elseif ($_GET['getText'] == 'plain') { } elseif ($_GET['getText'] == 'plain') {
$ret['text'] = trim(html2plain(BBCode::convert(api_clean_plain_items($item['body']), false, 2, true), 0)); $ret['text'] = trim(HTML::toPlaintext(BBCode::convert(api_clean_plain_items($item['body']), false, 2, true), 0));
} }
} else { } else {
$ret['text'] = $item['title'] . "\n" . html2plain(BBCode::convert(api_clean_plain_items($item['body']), false, 2, true), 0); $ret['text'] = $item['title'] . "\n" . HTML::toPlaintext(BBCode::convert(api_clean_plain_items($item['body']), false, 2, true), 0);
} }
if (x($_GET, 'getUserObjects') && $_GET['getUserObjects'] == 'false') { if (x($_GET, 'getUserObjects') && $_GET['getUserObjects'] == 'false') {
unset($ret['sender']); unset($ret['sender']);
@ -2650,7 +2653,7 @@ function api_convert_item($item)
// Workaround for ostatus messages where the title is identically to the body // Workaround for ostatus messages where the title is identically to the body
$html = BBCode::convert(api_clean_plain_items($body), false, 2, true); $html = BBCode::convert(api_clean_plain_items($body), false, 2, true);
$statusbody = trim(html2plain($html, 0)); $statusbody = trim(HTML::toPlaintext($html, 0));
// handle data: images // handle data: images
$statusbody = api_format_items_embeded_images($item, $statusbody); $statusbody = api_format_items_embeded_images($item, $statusbody);
@ -3265,22 +3268,6 @@ function api_help_test($type)
/// @TODO move to top of file or somewhere better /// @TODO move to top of file or somewhere better
api_register_func('api/help/test', 'api_help_test', false); api_register_func('api/help/test', 'api_help_test', false);
/**
*
* @param string $type Return type (atom, rss, xml, json)
*
* @return array|string
*/
function api_lists($type)
{
$ret = [];
/// @TODO $ret is not filled here?
return api_format_data('lists', $type, ["lists_list" => $ret]);
}
/// @TODO move to top of file or somewhere better
api_register_func('api/lists', 'api_lists', true);
/** /**
* Returns all lists the user subscribes to. * Returns all lists the user subscribes to.
* *
@ -3298,6 +3285,139 @@ function api_lists_list($type)
/// @TODO move to top of file or somewhere better /// @TODO move to top of file or somewhere better
api_register_func('api/lists/list', 'api_lists_list', true); api_register_func('api/lists/list', 'api_lists_list', true);
api_register_func('api/lists/subscriptions', 'api_lists_list', true);
/**
* Returns all groups the user owns.
*
* @param string $type Return type (atom, rss, xml, json)
*
* @return array|string
* @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-ownerships
*/
function api_lists_ownerships($type)
{
$a = get_app();
if (api_user() === false) {
throw new ForbiddenException();
}
// params
$user_info = api_get_user($a);
$uid = $user_info['uid'];
$groups = dba::select('group', [], ['deleted' => 0, 'uid' => $uid]);
// loop through all groups
$lists = [];
foreach ($groups as $group) {
if ($group['visible']) {
$mode = 'public';
} else {
$mode = 'private';
}
$lists[] = [
'name' => $group['name'],
'id' => intval($group['id']),
'id_str' => (string) $group['id'],
'user' => $user_info,
'mode' => $mode
];
}
return api_format_data("lists", $type, ['lists' => ['lists' => $lists]]);
}
/// @TODO move to top of file or somewhere better
api_register_func('api/lists/ownerships', 'api_lists_ownerships', true);
/**
* Returns recent statuses from users in the specified group.
*
* @param string $type Return type (atom, rss, xml, json)
*
* @return array|string
* @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-ownerships
*/
function api_lists_statuses($type)
{
$a = get_app();
$user_info = api_get_user($a);
if (api_user() === false || $user_info === false) {
throw new ForbiddenException();
}
unset($_REQUEST["user_id"]);
unset($_GET["user_id"]);
unset($_REQUEST["screen_name"]);
unset($_GET["screen_name"]);
if (empty($_REQUEST['list_id'])) {
throw new BadRequestException('list_id not specified');
}
// params
$count = (x($_REQUEST, 'count') ? $_REQUEST['count'] : 20);
$page = (x($_REQUEST, 'page') ? $_REQUEST['page'] - 1 : 0);
if ($page < 0) {
$page = 0;
}
$since_id = (x($_REQUEST, 'since_id') ? $_REQUEST['since_id'] : 0);
$max_id = (x($_REQUEST, 'max_id') ? $_REQUEST['max_id'] : 0);
$exclude_replies = (x($_REQUEST, 'exclude_replies') ? 1 : 0);
$conversation_id = (x($_REQUEST, 'conversation_id') ? $_REQUEST['conversation_id'] : 0);
$start = $page * $count;
$sql_extra = '';
if ($max_id > 0) {
$sql_extra .= ' AND `item`.`id` <= ' . intval($max_id);
}
if ($exclude_replies > 0) {
$sql_extra .= ' AND `item`.`parent` = `item`.`id`';
}
if ($conversation_id > 0) {
$sql_extra .= ' AND `item`.`parent` = ' . intval($conversation_id);
}
$statuses = dba::p(
"SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
`contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
`contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
`contact`.`id` AS `cid`, `group_member`.`gid`
FROM `item`
STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid`
AND (NOT `contact`.`blocked` OR `contact`.`pending`)
STRAIGHT_JOIN `group_member` ON `group_member`.`contact-id` = `item`.`contact-id`
WHERE `item`.`uid` = ? AND `verb` = ?
AND `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted`
$sql_extra
AND `item`.`id`>?
AND `group_member`.`gid` = ?
ORDER BY `item`.`id` DESC LIMIT ".intval($start)." ,".intval($count),
api_user(),
ACTIVITY_POST,
$since_id,
$_REQUEST['list_id']
);
$items = api_format_items(dba::inArray($statuses), $user_info, false, $type);
$data = ['status' => $items];
switch ($type) {
case "atom":
case "rss":
$data = api_rss_extra($a, $data, $user_info);
break;
}
return api_format_data("statuses", $type, $data);
}
/// @TODO move to top of file or somewhere better
api_register_func('api/lists/statuses', 'api_lists_statuses', true);
/** /**
* Considers friends and followers lists to be private and won't return * Considers friends and followers lists to be private and won't return
@ -3697,7 +3817,7 @@ api_register_func('api/direct_messages/new', 'api_direct_messages_new', true, AP
* @brief delete a direct_message from mail table through api * @brief delete a direct_message from mail table through api
* *
* @param string $type Known types are 'atom', 'rss', 'xml' and 'json' * @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
* @return string * @return string|array
* @see https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/delete-message * @see https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/delete-message
*/ */
function api_direct_messages_destroy($type) function api_direct_messages_destroy($type)
@ -3783,8 +3903,9 @@ api_register_func('api/direct_messages/destroy', 'api_direct_messages_destroy',
function api_direct_messages_box($type, $box, $verbose) function api_direct_messages_box($type, $box, $verbose)
{ {
$a = get_app(); $a = get_app();
$user_info = api_get_user($a);
if (api_user() === false) { if (api_user() === false || $user_info === false) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
@ -3808,7 +3929,6 @@ function api_direct_messages_box($type, $box, $verbose)
unset($_REQUEST["screen_name"]); unset($_REQUEST["screen_name"]);
unset($_GET["screen_name"]); unset($_GET["screen_name"]);
$user_info = api_get_user($a);
$profile_url = $user_info["url"]; $profile_url = $user_info["url"];
// pagination // pagination
@ -3859,8 +3979,10 @@ function api_direct_messages_box($type, $box, $verbose)
$sender = $user_info; $sender = $user_info;
} }
if (isset($recipient) && isset($sender)) {
$ret[] = api_format_messages($item, $recipient, $sender); $ret[] = api_format_messages($item, $recipient, $sender);
} }
}
$data = ['direct_message' => $ret]; $data = ['direct_message' => $ret];
@ -3977,7 +4099,7 @@ api_register_func('api/oauth/access_token', 'api_oauth_access_token', false);
* @brief delete a complete photoalbum with all containing photos from database through api * @brief delete a complete photoalbum with all containing photos from database through api
* *
* @param string $type Known types are 'atom', 'rss', 'xml' and 'json' * @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
* @return string * @return string|array
*/ */
function api_fr_photoalbum_delete($type) function api_fr_photoalbum_delete($type)
{ {
@ -4032,7 +4154,7 @@ function api_fr_photoalbum_delete($type)
* @brief update the name of the album for all photos of an album * @brief update the name of the album for all photos of an album
* *
* @param string $type Known types are 'atom', 'rss', 'xml' and 'json' * @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
* @return string * @return string|array
*/ */
function api_fr_photoalbum_update($type) function api_fr_photoalbum_update($type)
{ {
@ -4081,7 +4203,7 @@ function api_fr_photoalbum_update($type)
* @brief list all photos of the authenticated user * @brief list all photos of the authenticated user
* *
* @param string $type Known types are 'atom', 'rss', 'xml' and 'json' * @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
* @return string * @return string|array
*/ */
function api_fr_photos_list($type) function api_fr_photos_list($type)
{ {
@ -4127,7 +4249,7 @@ function api_fr_photos_list($type)
* @brief upload a new photo or change an existing photo * @brief upload a new photo or change an existing photo
* *
* @param string $type Known types are 'atom', 'rss', 'xml' and 'json' * @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
* @return string * @return string|array
*/ */
function api_fr_photo_create_update($type) function api_fr_photo_create_update($type)
{ {
@ -4275,7 +4397,7 @@ function api_fr_photo_create_update($type)
* @brief delete a single photo from the database through api * @brief delete a single photo from the database through api
* *
* @param string $type Known types are 'atom', 'rss', 'xml' and 'json' * @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
* @return string * @return string|array
*/ */
function api_fr_photo_delete($type) function api_fr_photo_delete($type)
{ {
@ -4358,7 +4480,7 @@ function api_fr_photo_detail($type)
* *
* @param string $type Known types are 'atom', 'rss', 'xml' and 'json' * @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
* *
* @return string * @return string|array
* @see https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_image * @see https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_image
*/ */
function api_account_update_profile_image($type) function api_account_update_profile_image($type)
@ -4410,6 +4532,8 @@ function api_account_update_profile_image($type)
$fileext = "jpg"; $fileext = "jpg";
} elseif ($filetype == "image/png") { } elseif ($filetype == "image/png") {
$fileext = "png"; $fileext = "png";
} else {
throw new InternalServerErrorException('Unsupported filetype');
} }
// change specified profile or all profiles to the new resource-id // change specified profile or all profiles to the new resource-id
if ($is_default_profile) { if ($is_default_profile) {
@ -4690,7 +4814,7 @@ function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $
logger("photo upload: new profile image upload ended", LOGGER_DEBUG); logger("photo upload: new profile image upload ended", LOGGER_DEBUG);
} }
if ($r) { if (isset($r) && $r) {
// create entry in 'item'-table on new uploads to enable users to comment/like/dislike the photo // create entry in 'item'-table on new uploads to enable users to comment/like/dislike the photo
if ($photo_id == null && $mediatype == "photo") { if ($photo_id == null && $mediatype == "photo") {
post_photo_item($hash, $allow_cid, $deny_cid, $allow_gid, $deny_gid, $filetype, $visibility); post_photo_item($hash, $allow_cid, $deny_cid, $allow_gid, $deny_gid, $filetype, $visibility);
@ -4766,6 +4890,13 @@ function post_photo_item($hash, $allow_cid, $deny_cid, $allow_gid, $deny_gid, $f
*/ */
function prepare_photo_data($type, $scale, $photo_id) function prepare_photo_data($type, $scale, $photo_id)
{ {
$a = get_app();
$user_info = api_get_user($a);
if ($user_info === false) {
throw new ForbiddenException();
}
$scale_sql = ($scale === false ? "" : sprintf("AND scale=%d", intval($scale))); $scale_sql = ($scale === false ? "" : sprintf("AND scale=%d", intval($scale)));
$data_sql = ($scale === false ? "" : "data, "); $data_sql = ($scale === false ? "" : "data, ");
@ -4846,7 +4977,7 @@ function prepare_photo_data($type, $scale, $photo_id)
); );
// prepare output of comments // prepare output of comments
$commentData = api_format_items($r, api_get_user(get_app()), false, $type); $commentData = api_format_items($r, $user_info, false, $type);
$comments = []; $comments = [];
if ($type == "xml") { if ($type == "xml") {
$k = 0; $k = 0;
@ -5221,7 +5352,7 @@ function api_clean_attachments($body)
{ {
$data = BBCode::getAttachmentData($body); $data = BBCode::getAttachmentData($body);
if (!$data) { if (empty($data)) {
return $body; return $body;
} }
$body = ""; $body = "";
@ -5347,6 +5478,7 @@ function api_friendica_group_show($type)
} }
// loop through all groups and retrieve all members for adding data in the user array // loop through all groups and retrieve all members for adding data in the user array
$grps = [];
foreach ($r as $rr) { foreach ($r as $rr) {
$members = Contact::getByGroupId($rr['id']); $members = Contact::getByGroupId($rr['id']);
$users = []; $users = [];
@ -5433,15 +5565,15 @@ function api_friendica_group_delete($type)
} }
api_register_func('api/friendica/group_delete', 'api_friendica_group_delete', true, API_METHOD_DELETE); api_register_func('api/friendica/group_delete', 'api_friendica_group_delete', true, API_METHOD_DELETE);
/** /**
* Create the specified group with the posted array of contacts. * Delete a group.
* *
* @param string $type Return type (atom, rss, xml, json) * @param string $type Return type (atom, rss, xml, json)
* *
* @return array|string * @return array|string
* @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-destroy
*/ */
function api_friendica_group_create($type) function api_lists_destroy($type)
{ {
$a = get_app(); $a = get_app();
@ -5451,11 +5583,45 @@ function api_friendica_group_create($type)
// params // params
$user_info = api_get_user($a); $user_info = api_get_user($a);
$name = (x($_REQUEST, 'name') ? $_REQUEST['name'] : ""); $gid = (x($_REQUEST, 'list_id') ? $_REQUEST['list_id'] : 0);
$uid = $user_info['uid']; $uid = $user_info['uid'];
$json = json_decode($_POST['json'], true);
$users = $json['user'];
// error if no gid specified
if ($gid == 0) {
throw new BadRequestException('gid not specified');
}
// get data of the specified group id
$group = dba::selectFirst('group', [], ['uid' => $uid, 'id' => $gid]);
// error message if specified gid is not in database
if (!$group) {
throw new BadRequestException('gid not available');
}
if (Group::remove($gid)) {
$list = [
'name' => $group['name'],
'id' => intval($gid),
'id_str' => (string) $gid,
'user' => $user_info
];
return api_format_data("lists", $type, ['lists' => $list]);
}
}
api_register_func('api/lists/destroy', 'api_lists_destroy', true, API_METHOD_DELETE);
/**
* Add a new group to the database.
*
* @param string $name Group name
* @param int $uid User ID
* @param array $users List of users to add to the group
*
* @return array
*/
function group_create($name, $uid, $users = [])
{
// error if no name specified // error if no name specified
if ($name == "") { if ($name == "") {
throw new BadRequestException('group name not specified'); throw new BadRequestException('group name not specified');
@ -5511,12 +5677,73 @@ function api_friendica_group_create($type)
} }
// return success message incl. missing users in array // return success message incl. missing users in array
$status = ($erroraddinguser ? "missing user" : ($reactivate_group ? "reactivated" : "ok")); $status = ($erroraddinguser ? "missing user" : ((isset($reactivate_group) && $reactivate_group) ? "reactivated" : "ok"));
$success = ['success' => true, 'gid' => $gid, 'name' => $name, 'status' => $status, 'wrong users' => $errorusers];
return ['success' => true, 'gid' => $gid, 'name' => $name, 'status' => $status, 'wrong users' => $errorusers];
}
/**
* Create the specified group with the posted array of contacts.
*
* @param string $type Return type (atom, rss, xml, json)
*
* @return array|string
*/
function api_friendica_group_create($type)
{
$a = get_app();
if (api_user() === false) {
throw new ForbiddenException();
}
// params
$user_info = api_get_user($a);
$name = (x($_REQUEST, 'name') ? $_REQUEST['name'] : "");
$uid = $user_info['uid'];
$json = json_decode($_POST['json'], true);
$users = $json['user'];
$success = group_create($name, $uid, $users);
return api_format_data("group_create", $type, ['result' => $success]); return api_format_data("group_create", $type, ['result' => $success]);
} }
api_register_func('api/friendica/group_create', 'api_friendica_group_create', true, API_METHOD_POST); api_register_func('api/friendica/group_create', 'api_friendica_group_create', true, API_METHOD_POST);
/**
* Create a new group.
*
* @param string $type Return type (atom, rss, xml, json)
*
* @return array|string
* @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-create
*/
function api_lists_create($type)
{
$a = get_app();
if (api_user() === false) {
throw new ForbiddenException();
}
// params
$user_info = api_get_user($a);
$name = (x($_REQUEST, 'name') ? $_REQUEST['name'] : "");
$uid = $user_info['uid'];
$success = group_create($name, $uid);
if ($success['success']) {
$grp = [
'name' => $success['name'],
'id' => intval($success['gid']),
'id_str' => (string) $success['gid'],
'user' => $user_info
];
return api_format_data("lists", $type, ['lists'=>$grp]);
}
}
api_register_func('api/lists/create', 'api_lists_create', true, API_METHOD_POST);
/** /**
* Update the specified group with the posted array of contacts. * Update the specified group with the posted array of contacts.
@ -5558,7 +5785,7 @@ function api_friendica_group_update($type)
foreach ($users as $user) { foreach ($users as $user) {
$found = ($user['cid'] == $cid ? true : false); $found = ($user['cid'] == $cid ? true : false);
} }
if (!$found) { if (!isset($found) || !$found) {
Group::removeMemberByName($uid, $name, $cid); Group::removeMemberByName($uid, $name, $cid);
} }
} }
@ -5591,6 +5818,54 @@ function api_friendica_group_update($type)
api_register_func('api/friendica/group_update', 'api_friendica_group_update', true, API_METHOD_POST); api_register_func('api/friendica/group_update', 'api_friendica_group_update', true, API_METHOD_POST);
/**
* Update information about a group.
*
* @param string $type Return type (atom, rss, xml, json)
*
* @return array|string
* @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-update
*/
function api_lists_update($type)
{
$a = get_app();
if (api_user() === false) {
throw new ForbiddenException();
}
// params
$user_info = api_get_user($a);
$gid = (x($_REQUEST, 'list_id') ? $_REQUEST['list_id'] : 0);
$name = (x($_REQUEST, 'name') ? $_REQUEST['name'] : "");
$uid = $user_info['uid'];
// error if no gid specified
if ($gid == 0) {
throw new BadRequestException('gid not specified');
}
// get data of the specified group id
$group = dba::selectFirst('group', [], ['uid' => $uid, 'id' => $gid]);
// error message if specified gid is not in database
if (!$group) {
throw new BadRequestException('gid not available');
}
if (Group::update($gid, $name)) {
$list = [
'name' => $name,
'id' => intval($gid),
'id_str' => (string) $gid,
'user' => $user_info
];
return api_format_data("lists", $type, ['lists' => $list]);
}
}
api_register_func('api/lists/update', 'api_lists_update', true, API_METHOD_POST);
/** /**
* *
* @param string $type Return type (atom, rss, xml, json) * @param string $type Return type (atom, rss, xml, json)
@ -5639,7 +5914,7 @@ api_register_func('api/friendica/activity/unattendmaybe', 'api_friendica_activit
* @brief Returns notifications * @brief Returns notifications
* *
* @param string $type Known types are 'atom', 'rss', 'xml' and 'json' * @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
* @return string * @return string|array
*/ */
function api_friendica_notification($type) function api_friendica_notification($type)
{ {
@ -5673,13 +5948,14 @@ function api_friendica_notification($type)
* @brief Set notification as seen and returns associated item (if possible) * @brief Set notification as seen and returns associated item (if possible)
* *
* @param string $type Known types are 'atom', 'rss', 'xml' and 'json' * @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
* @return string * @return string|array
*/ */
function api_friendica_notification_seen($type) function api_friendica_notification_seen($type)
{ {
$a = get_app(); $a = get_app();
$user_info = api_get_user($a);
if (api_user() === false) { if (api_user() === false || $user_info === false) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
if ($a->argc!==4) { if ($a->argc!==4) {
@ -5704,7 +5980,6 @@ function api_friendica_notification_seen($type)
); );
if ($r!==false) { if ($r!==false) {
// we found the item, return it to the user // we found the item, return it to the user
$user_info = api_get_user($a);
$ret = api_format_items($r, $user_info, false, $type); $ret = api_format_items($r, $user_info, false, $type);
$data = ['status' => $ret]; $data = ['status' => $ret];
return api_format_data("status", $type, $data); return api_format_data("status", $type, $data);
@ -5722,7 +5997,7 @@ api_register_func('api/friendica/notification', 'api_friendica_notification', tr
* @brief update a direct_message to seen state * @brief update a direct_message to seen state
* *
* @param string $type Known types are 'atom', 'rss', 'xml' and 'json' * @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
* @return string (success result=ok, error result=error with error message) * @return string|array (success result=ok, error result=error with error message)
*/ */
function api_friendica_direct_messages_setseen($type) function api_friendica_direct_messages_setseen($type)
{ {
@ -5780,7 +6055,7 @@ api_register_func('api/friendica/direct_messages_setseen', 'api_friendica_direct
* *
* @param string $type Known types are 'atom', 'rss', 'xml' and 'json' * @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
* @param string $box * @param string $box
* @return string (success: success=true if found and search_result contains found messages, * @return string|array (success: success=true if found and search_result contains found messages,
* success=false if nothing was found, search_result='nothing found', * success=false if nothing was found, search_result='nothing found',
* error: result=error with error message) * error: result=error with error message)
*/ */
@ -5828,8 +6103,10 @@ function api_friendica_direct_messages_search($type, $box = "")
$sender = $user_info; $sender = $user_info;
} }
if (isset($recipient) && isset($sender)) {
$ret[] = api_format_messages($item, $recipient, $sender); $ret[] = api_format_messages($item, $recipient, $sender);
} }
}
$success = ['success' => true, 'search_results' => $ret]; $success = ['success' => true, 'search_results' => $ret];
} }
@ -5843,7 +6120,7 @@ api_register_func('api/friendica/direct_messages_search', 'api_friendica_direct_
* @brief return data of all the profiles a user has to the client * @brief return data of all the profiles a user has to the client
* *
* @param string $type Known types are 'atom', 'rss', 'xml' and 'json' * @param string $type Known types are 'atom', 'rss', 'xml' and 'json'
* @return string * @return string|array
*/ */
function api_friendica_profile_show($type) function api_friendica_profile_show($type)
{ {
@ -5880,19 +6157,20 @@ function api_friendica_profile_show($type)
} }
// loop through all returned profiles and retrieve data and users // loop through all returned profiles and retrieve data and users
$k = 0; $k = 0;
$profiles = [];
foreach ($r as $rr) { foreach ($r as $rr) {
$profile = api_format_items_profiles($rr); $profile = api_format_items_profiles($rr);
// select all users from contact table, loop and prepare standard return for user data // select all users from contact table, loop and prepare standard return for user data
$users = []; $users = [];
$r = q( $nurls = q(
"SELECT `id`, `nurl` FROM `contact` WHERE `uid`= %d AND `profile-id` = %d", "SELECT `id`, `nurl` FROM `contact` WHERE `uid`= %d AND `profile-id` = %d",
intval(api_user()), intval(api_user()),
intval($rr['profile_id']) intval($rr['profile_id'])
); );
foreach ($r as $rr) { foreach ($nurls as $nurl) {
$user = api_get_user($a, $rr['nurl']); $user = api_get_user($a, $nurl['nurl']);
($type == "xml") ? $users[$k++ . ":user"] = $user : $users[] = $user; ($type == "xml") ? $users[$k++ . ":user"] = $user : $users[] = $user;
} }
$profile['users'] = $users; $profile['users'] = $users;
@ -5932,10 +6210,12 @@ function api_saved_searches_list($type)
$result = []; $result = [];
while ($term = $terms->fetch()) { while ($term = $terms->fetch()) {
$result[] = [ $result[] = [
'name' => $term['term'], 'created_at' => api_date(time()),
'query' => $term['term'], 'id' => intval($term['id']),
'id_str' => $term['id'], 'id_str' => $term['id'],
'id' => intval($term['id']) 'name' => $term['term'],
'position' => null,
'query' => $term['term']
]; ];
} }

View file

@ -443,7 +443,7 @@ These Fields are not added below (yet). They are here to for bug search.
return "`item`.`author-id`, `item`.`author-link`, `item`.`author-name`, `item`.`author-avatar`, return "`item`.`author-id`, `item`.`author-link`, `item`.`author-name`, `item`.`author-avatar`,
`item`.`owner-id`, `item`.`owner-link`, `item`.`owner-name`, `item`.`owner-avatar`, `item`.`owner-id`, `item`.`owner-link`, `item`.`owner-name`, `item`.`owner-avatar`,
`item`.`contact-id`, `item`.`uid`, `item`.`id`, `item`.`parent`, `item`.`contact-id`, `item`.`uid`, `item`.`id`, `item`.`parent`,
`item`.`uri`, `item`.`thr-parent`, `item`.`parent-uri`, `item`.`uri`, `item`.`thr-parent`, `item`.`parent-uri`, `item`.`content-warning`,
`item`.`commented`, `item`.`created`, `item`.`edited`, `item`.`received`, `item`.`commented`, `item`.`created`, `item`.`edited`, `item`.`received`,
`item`.`verb`, `item`.`object-type`, `item`.`postopts`, `item`.`plink`, `item`.`verb`, `item`.`object-type`, `item`.`postopts`, `item`.`plink`,
`item`.`guid`, `item`.`wall`, `item`.`private`, `item`.`starred`, `item`.`guid`, `item`.`wall`, `item`.`private`, `item`.`starred`,
@ -756,7 +756,13 @@ function conversation(App $a, $items, $mode, $update, $preview = false, $order =
list($categories, $folders) = get_cats_and_terms($item); list($categories, $folders) = get_cats_and_terms($item);
$profile_name_e = $profile_name; $profile_name_e = $profile_name;
$item['title_e'] = $item['title'];
if (!empty($item['content-warning']) && PConfig::get(local_user(), 'system', 'disable_cw', false)) {
$title_e = ucfirst($item['content-warning']);
} else {
$title_e = $item['title'];
}
$body_e = $body; $body_e = $body;
$tags_e = $tags; $tags_e = $tags;
$hashtags_e = $hashtags; $hashtags_e = $hashtags;
@ -781,7 +787,7 @@ function conversation(App $a, $items, $mode, $update, $preview = false, $order =
'sparkle' => $sparkle, 'sparkle' => $sparkle,
'lock' => $lock, 'lock' => $lock,
'thumb' => System::removedBaseUrl(proxy_url($item['author-thumb'], false, PROXY_SIZE_THUMB)), 'thumb' => System::removedBaseUrl(proxy_url($item['author-thumb'], false, PROXY_SIZE_THUMB)),
'title' => $item['title_e'], 'title' => $title_e,
'body' => $body_e, 'body' => $body_e,
'tags' => $tags_e, 'tags' => $tags_e,
'hashtags' => $hashtags_e, 'hashtags' => $hashtags_e,
@ -1245,7 +1251,7 @@ function format_like($cnt, array $arr, $type, $id) {
break; break;
case 'attendmaybe': case 'attendmaybe':
$phrase = L10n::t('<span %1$s>%2$d people</span> attend maybe', $spanatts, $cnt); $phrase = L10n::t('<span %1$s>%2$d people</span> attend maybe', $spanatts, $cnt);
$explikers = L10n::t('%s anttend maybe.', $likers); $explikers = L10n::t('%s attend maybe.', $likers);
break; break;
} }
@ -1329,6 +1335,7 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false)
$tpl = get_markup_template("jot.tpl"); $tpl = get_markup_template("jot.tpl");
$o .= replace_macros($tpl,[ $o .= replace_macros($tpl,[
'$new_post' => L10n::t('New Post'),
'$return_path' => $query_str, '$return_path' => $query_str,
'$action' => 'item', '$action' => 'item',
'$share' => defaults($x, 'button', L10n::t('Share')), '$share' => defaults($x, 'button', L10n::t('Share')),
@ -1643,7 +1650,7 @@ function get_responses($conv_responses, $response_verbs, $ob, $item) {
foreach ($response_verbs as $v) { foreach ($response_verbs as $v) {
$ret[$v] = []; $ret[$v] = [];
$ret[$v]['count'] = defaults($conv_responses[$v], $item['uri'], ''); $ret[$v]['count'] = defaults($conv_responses[$v], $item['uri'], '');
$ret[$v]['list'] = defaults($conv_responses[$v], $item['uri'] . '-l', ''); $ret[$v]['list'] = defaults($conv_responses[$v], $item['uri'] . '-l', []);
$ret[$v]['self'] = defaults($conv_responses[$v], $item['uri'] . '-self', '0'); $ret[$v]['self'] = defaults($conv_responses[$v], $item['uri'] . '-self', '0');
if (count($ret[$v]['list']) > MAX_LIKERS) { if (count($ret[$v]['list']) > MAX_LIKERS) {
$ret[$v]['list_part'] = array_slice($ret[$v]['list'], 0, MAX_LIKERS); $ret[$v]['list_part'] = array_slice($ret[$v]['list'], 0, MAX_LIKERS);

View file

@ -13,7 +13,7 @@ use Friendica\Util\DateTimeFormat;
*/ */
class dba { class dba {
public static $connected = true; public static $connected = false;
private static $_server_info = ''; private static $_server_info = '';
private static $db; private static $db;
@ -48,17 +48,14 @@ class dba {
$db = trim($db); $db = trim($db);
if (!(strlen($server) && strlen($user))) { if (!(strlen($server) && strlen($user))) {
self::$connected = false;
self::$db = null;
return false; return false;
} }
if ($install) { if ($install) {
if (strlen($server) && ($server !== 'localhost') && ($server !== '127.0.0.1')) { // server has to be a non-empty string that is not 'localhost' and not an IP
if (! dns_get_record($server, DNS_A + DNS_CNAME + DNS_PTR)) { if (strlen($server) && ($server !== 'localhost') && filter_var($server, FILTER_VALIDATE_IP) === false) {
if (! dns_get_record($server, DNS_A + DNS_CNAME)) {
self::$error = L10n::t('Cannot locate DNS info for database server \'%s\'', $server); self::$error = L10n::t('Cannot locate DNS info for database server \'%s\'', $server);
self::$connected = false;
self::$db = null;
return false; return false;
} }
} }
@ -79,7 +76,6 @@ class dba {
self::$db = @new PDO($connect, $user, $pass); self::$db = @new PDO($connect, $user, $pass);
self::$connected = true; self::$connected = true;
} catch (PDOException $e) { } catch (PDOException $e) {
self::$connected = false;
} }
} }
@ -98,13 +94,10 @@ class dba {
// No suitable SQL driver was found. // No suitable SQL driver was found.
if (!self::$connected) { if (!self::$connected) {
self::$db = null; self::$db = null;
if (!$install) {
System::unavailable();
}
} }
$a->save_timestamp($stamp1, "network"); $a->save_timestamp($stamp1, "network");
return true; return self::$connected;
} }
/** /**

View file

@ -12,16 +12,14 @@ use Friendica\Database\DBM;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\Emailer; use Friendica\Util\Emailer;
require_once 'include/html2bbcode.php';
/** /**
* @brief Creates a notification entry and possibly sends a mail * @brief Creates a notification entry and possibly sends a mail
* *
* @param array $params Array with the elements: * @param array $params Array with the elements:
uid, item, parent, type, otype, verb, event, * uid, item, parent, type, otype, verb, event,
link, subject, body, to_name, to_email, source_name, * link, subject, body, to_name, to_email, source_name,
source_link, activity, preamble, notify_flags, * source_link, activity, preamble, notify_flags,
language, show_in_notification_page * language, show_in_notification_page
*/ */
function notification($params) function notification($params)
{ {
@ -47,10 +45,7 @@ function notification($params)
$hostname = substr($hostname, 0, strpos($hostname, ':')); $hostname = substr($hostname, 0, strpos($hostname, ':'));
} }
$sender_email = $a->config['sender_email']; $sender_email = $a->getSenderEmailAddress();
if (empty($sender_email)) {
$sender_email = L10n::t('noreply').'@'.$hostname;
}
if ($params['type'] != SYSTEM_EMAIL) { if ($params['type'] != SYSTEM_EMAIL) {
$user = dba::selectFirst('user', ['nickname', 'page-flags'], $user = dba::selectFirst('user', ['nickname', 'page-flags'],
@ -362,7 +357,7 @@ function notification($params)
if ($params['type'] == NOTIFY_SYSTEM) { if ($params['type'] == NOTIFY_SYSTEM) {
switch($params['event']) { switch($params['event']) {
case "SYSTEM_REGISTER_REQUEST": case "SYSTEM_REGISTER_REQUEST":
$subject = L10n::t('[Friendica System:Notify] registration request'); $subject = L10n::t('[Friendica System Notify]') . ' ' . L10n::t('registration request');
$preamble = L10n::t('You\'ve received a registration request from \'%1$s\' at %2$s', $params['source_name'], $sitename); $preamble = L10n::t('You\'ve received a registration request from \'%1$s\' at %2$s', $params['source_name'], $sitename);
$epreamble = L10n::t('You\'ve received a [url=%1$s]registration request[/url] from %2$s.', $epreamble = L10n::t('You\'ve received a [url=%1$s]registration request[/url] from %2$s.',
@ -370,7 +365,7 @@ function notification($params)
'[url='.$params['source_link'].']'.$params['source_name'].'[/url]' '[url='.$params['source_link'].']'.$params['source_name'].'[/url]'
); );
$body = L10n::t('Full Name: %1$s\nSite Location: %2$s\nLogin Name: %3$s ' . "\x28" . '%4$s' . "\x28", $body = L10n::t('Full Name: %1$s\nSite Location: %2$s\nLogin Name: %3$s ' . "\x28" . '%4$s' . "\x29",
$params['source_name'], $params['source_name'],
$siteurl, $params['source_mail'], $siteurl, $params['source_mail'],
$params['source_nick'] $params['source_nick']

File diff suppressed because it is too large Load diff

View file

@ -1,403 +0,0 @@
<?php
/**
* @file include/html2bbcode.php
* @brief Converter for HTML to BBCode
*
* Made by: ike@piratenpartei.de
* Originally made for the syncom project: http://wiki.piratenpartei.de/Syncom
* https://github.com/annando/Syncom
*/
use Friendica\Core\Addon;
use Friendica\Util\Network;
use Friendica\Util\XML;
function node2bbcode(&$doc, $oldnode, $attributes, $startbb, $endbb)
{
do {
$done = node2bbcodesub($doc, $oldnode, $attributes, $startbb, $endbb);
} while ($done);
}
function node2bbcodesub(&$doc, $oldnode, $attributes, $startbb, $endbb)
{
$savestart = str_replace('$', '\x01', $startbb);
$replace = false;
$xpath = new DomXPath($doc);
$list = $xpath->query("//".$oldnode);
foreach ($list as $oldNode) {
$attr = [];
if ($oldNode->attributes->length) {
foreach ($oldNode->attributes as $attribute) {
$attr[$attribute->name] = $attribute->value;
}
}
$replace = true;
$startbb = $savestart;
$i = 0;
foreach ($attributes as $attribute => $value) {
$startbb = str_replace('\x01'.++$i, '$1', $startbb);
if (strpos('*'.$startbb, '$1') > 0) {
if ($replace && (@$attr[$attribute] != '')) {
$startbb = preg_replace($value, $startbb, $attr[$attribute], -1, $count);
// If nothing could be changed
if ($count == 0) {
$replace = false;
}
} else {
$replace = false;
}
} else {
if (@$attr[$attribute] != $value) {
$replace = false;
}
}
}
if ($replace) {
$StartCode = $oldNode->ownerDocument->createTextNode($startbb);
$EndCode = $oldNode->ownerDocument->createTextNode($endbb);
$oldNode->parentNode->insertBefore($StartCode, $oldNode);
if ($oldNode->hasChildNodes()) {
foreach ($oldNode->childNodes as $child) {
$newNode = $child->cloneNode(true);
$oldNode->parentNode->insertBefore($newNode, $oldNode);
}
}
$oldNode->parentNode->insertBefore($EndCode, $oldNode);
$oldNode->parentNode->removeChild($oldNode);
}
}
return($replace);
}
function html2bbcode($message, $basepath = '')
{
$message = str_replace("\r", "", $message);
// Removing code blocks before the whitespace removal processing below
$codeblocks = [];
$message = preg_replace_callback(
'#<pre><code(?: class="([^"]*)")?>(.*)</code></pre>#iUs',
function ($matches) use (&$codeblocks) {
$return = '[codeblock-' . count($codeblocks) . ']';
$prefix = '[code]';
if ($matches[1] != '') {
$prefix = '[code=' . $matches[1] . ']';
}
$codeblocks[] = $prefix . trim($matches[2]) . '[/code]';
return $return;
},
$message
);
$message = str_replace(
[
"<li><p>",
"</p></li>",
],
[
"<li>",
"</li>",
],
$message
);
// remove namespaces
$message = preg_replace('=<(\w+):(.+?)>=', '<removeme>', $message);
$message = preg_replace('=</(\w+):(.+?)>=', '</removeme>', $message);
$doc = new DOMDocument();
$doc->preserveWhiteSpace = false;
$message = mb_convert_encoding($message, 'HTML-ENTITIES', "UTF-8");
@$doc->loadHTML($message);
XML::deleteNode($doc, 'style');
XML::deleteNode($doc, 'head');
XML::deleteNode($doc, 'title');
XML::deleteNode($doc, 'meta');
XML::deleteNode($doc, 'xml');
XML::deleteNode($doc, 'removeme');
$xpath = new DomXPath($doc);
$list = $xpath->query("//pre");
foreach ($list as $node) {
$node->nodeValue = str_replace("\n", "\r", $node->nodeValue);
}
$message = $doc->saveHTML();
$message = str_replace(["\n<", ">\n", "\r", "\n", "\xC3\x82\xC2\xA0"], ["<", ">", "<br />", " ", ""], $message);
$message = preg_replace('= [\s]*=i', " ", $message);
@$doc->loadHTML($message);
node2bbcode($doc, 'html', [], "", "");
node2bbcode($doc, 'body', [], "", "");
// Outlook-Quote - Variant 1
node2bbcode($doc, 'p', ['class'=>'MsoNormal', 'style'=>'margin-left:35.4pt'], '[quote]', '[/quote]');
// Outlook-Quote - Variant 2
node2bbcode($doc, 'div', ['style'=>'border:none;border-left:solid blue 1.5pt;padding:0cm 0cm 0cm 4.0pt'], '[quote]', '[/quote]');
// MyBB-Stuff
node2bbcode($doc, 'span', ['style'=>'text-decoration: underline;'], '[u]', '[/u]');
node2bbcode($doc, 'span', ['style'=>'font-style: italic;'], '[i]', '[/i]');
node2bbcode($doc, 'span', ['style'=>'font-weight: bold;'], '[b]', '[/b]');
/*node2bbcode($doc, 'font', array('face'=>'/([\w ]+)/', 'size'=>'/(\d+)/', 'color'=>'/(.+)/'), '[font=$1][size=$2][color=$3]', '[/color][/size][/font]');
node2bbcode($doc, 'font', array('size'=>'/(\d+)/', 'color'=>'/(.+)/'), '[size=$1][color=$2]', '[/color][/size]');
node2bbcode($doc, 'font', array('face'=>'/([\w ]+)/', 'size'=>'/(.+)/'), '[font=$1][size=$2]', '[/size][/font]');
node2bbcode($doc, 'font', array('face'=>'/([\w ]+)/', 'color'=>'/(.+)/'), '[font=$1][color=$3]', '[/color][/font]');
node2bbcode($doc, 'font', array('face'=>'/([\w ]+)/'), '[font=$1]', '[/font]');
node2bbcode($doc, 'font', array('size'=>'/(\d+)/'), '[size=$1]', '[/size]');
node2bbcode($doc, 'font', array('color'=>'/(.+)/'), '[color=$1]', '[/color]');
*/
// Untested
//node2bbcode($doc, 'span', array('style'=>'/.*font-size:\s*(.+?)[,;].*font-family:\s*(.+?)[,;].*color:\s*(.+?)[,;].*/'), '[size=$1][font=$2][color=$3]', '[/color][/font][/size]');
//node2bbcode($doc, 'span', array('style'=>'/.*font-size:\s*(\d+)[,;].*/'), '[size=$1]', '[/size]');
//node2bbcode($doc, 'span', array('style'=>'/.*font-size:\s*(.+?)[,;].*/'), '[size=$1]', '[/size]');
node2bbcode($doc, 'span', ['style'=>'/.*color:\s*(.+?)[,;].*/'], '[color="$1"]', '[/color]');
//node2bbcode($doc, 'span', array('style'=>'/.*font-family:\s*(.+?)[,;].*/'), '[font=$1]', '[/font]');
//node2bbcode($doc, 'div', array('style'=>'/.*font-family:\s*(.+?)[,;].*font-size:\s*(\d+?)pt.*/'), '[font=$1][size=$2]', '[/size][/font]');
//node2bbcode($doc, 'div', array('style'=>'/.*font-family:\s*(.+?)[,;].*font-size:\s*(\d+?)px.*/'), '[font=$1][size=$2]', '[/size][/font]');
//node2bbcode($doc, 'div', array('style'=>'/.*font-family:\s*(.+?)[,;].*/'), '[font=$1]', '[/font]');
// Importing the classes - interesting for importing of posts from third party networks that were exported from friendica
// Test
//node2bbcode($doc, 'span', array('class'=>'/([\w ]+)/'), '[class=$1]', '[/class]');
node2bbcode($doc, 'span', ['class'=>'type-link'], '[class=type-link]', '[/class]');
node2bbcode($doc, 'span', ['class'=>'type-video'], '[class=type-video]', '[/class]');
node2bbcode($doc, 'strong', [], '[b]', '[/b]');
node2bbcode($doc, 'em', [], '[i]', '[/i]');
node2bbcode($doc, 'b', [], '[b]', '[/b]');
node2bbcode($doc, 'i', [], '[i]', '[/i]');
node2bbcode($doc, 'u', [], '[u]', '[/u]');
node2bbcode($doc, 'big', [], "[size=large]", "[/size]");
node2bbcode($doc, 'small', [], "[size=small]", "[/size]");
node2bbcode($doc, 'blockquote', [], '[quote]', '[/quote]');
node2bbcode($doc, 'br', [], "\n", '');
node2bbcode($doc, 'p', ['class'=>'MsoNormal'], "\n", "");
node2bbcode($doc, 'div', ['class'=>'MsoNormal'], "\r", "");
node2bbcode($doc, 'span', [], "", "");
node2bbcode($doc, 'span', [], "", "");
node2bbcode($doc, 'pre', [], "", "");
node2bbcode($doc, 'div', [], "\r", "\r");
node2bbcode($doc, 'p', [], "\n", "\n");
node2bbcode($doc, 'ul', [], "[list]", "[/list]");
node2bbcode($doc, 'ol', [], "[list=1]", "[/list]");
node2bbcode($doc, 'li', [], "[*]", "");
node2bbcode($doc, 'hr', [], "[hr]", "");
node2bbcode($doc, 'table', [], "", "");
node2bbcode($doc, 'tr', [], "\n", "");
node2bbcode($doc, 'td', [], "\t", "");
//node2bbcode($doc, 'table', array(), "[table]", "[/table]");
//node2bbcode($doc, 'th', array(), "[th]", "[/th]");
//node2bbcode($doc, 'tr', array(), "[tr]", "[/tr]");
//node2bbcode($doc, 'td', array(), "[td]", "[/td]");
//node2bbcode($doc, 'h1', array(), "\n\n[size=xx-large][b]", "[/b][/size]\n");
//node2bbcode($doc, 'h2', array(), "\n\n[size=x-large][b]", "[/b][/size]\n");
//node2bbcode($doc, 'h3', array(), "\n\n[size=large][b]", "[/b][/size]\n");
//node2bbcode($doc, 'h4', array(), "\n\n[size=medium][b]", "[/b][/size]\n");
//node2bbcode($doc, 'h5', array(), "\n\n[size=small][b]", "[/b][/size]\n");
//node2bbcode($doc, 'h6', array(), "\n\n[size=x-small][b]", "[/b][/size]\n");
node2bbcode($doc, 'h1', [], "\n\n[h1]", "[/h1]\n");
node2bbcode($doc, 'h2', [], "\n\n[h2]", "[/h2]\n");
node2bbcode($doc, 'h3', [], "\n\n[h3]", "[/h3]\n");
node2bbcode($doc, 'h4', [], "\n\n[h4]", "[/h4]\n");
node2bbcode($doc, 'h5', [], "\n\n[h5]", "[/h5]\n");
node2bbcode($doc, 'h6', [], "\n\n[h6]", "[/h6]\n");
node2bbcode($doc, 'a', ['href'=>'/mailto:(.+)/'], '[mail=$1]', '[/mail]');
node2bbcode($doc, 'a', ['href'=>'/(.+)/'], '[url=$1]', '[/url]');
node2bbcode($doc, 'img', ['src'=>'/(.+)/', 'width'=>'/(\d+)/', 'height'=>'/(\d+)/'], '[img=$2x$3]$1', '[/img]');
node2bbcode($doc, 'img', ['src'=>'/(.+)/'], '[img]$1', '[/img]');
node2bbcode($doc, 'video', ['src'=>'/(.+)/'], '[video]$1', '[/video]');
node2bbcode($doc, 'audio', ['src'=>'/(.+)/'], '[audio]$1', '[/audio]');
node2bbcode($doc, 'iframe', ['src'=>'/(.+)/'], '[iframe]$1', '[/iframe]');
node2bbcode($doc, 'key', [], '[code]', '[/code]');
node2bbcode($doc, 'code', [], '[code]', '[/code]');
$message = $doc->saveHTML();
// I'm removing something really disturbing
// Don't know exactly what it is
$message = str_replace(chr(194).chr(160), ' ', $message);
$message = str_replace("&nbsp;", " ", $message);
// removing multiple DIVs
$message = preg_replace('=\r *\r=i', "\n", $message);
$message = str_replace("\r", "\n", $message);
Addon::callHooks('html2bbcode', $message);
$message = strip_tags($message);
$message = html_entity_decode($message, ENT_QUOTES, 'UTF-8');
$message = str_replace(["<"], ["&lt;"], $message);
// remove quotes if they don't make sense
$message = preg_replace('=\[/quote\][\s]*\[quote\]=i', "\n", $message);
$message = preg_replace('=\[quote\]\s*=i', "[quote]", $message);
$message = preg_replace('=\s*\[/quote\]=i', "[/quote]", $message);
do {
$oldmessage = $message;
$message = str_replace("\n \n", "\n\n", $message);
} while ($oldmessage != $message);
do {
$oldmessage = $message;
$message = str_replace("\n\n\n", "\n\n", $message);
} while ($oldmessage != $message);
do {
$oldmessage = $message;
$message = str_replace(
[
"[/size]\n\n",
"\n[hr]",
"[hr]\n",
"\n[list",
"[/list]\n",
"\n[/",
"[list]\n",
"[list=1]\n",
"\n[*]"],
[
"[/size]\n",
"[hr]",
"[hr]",
"[list",
"[/list]",
"[/",
"[list]",
"[list=1]",
"[*]"],
$message
);
} while ($message != $oldmessage);
$message = str_replace(
['[b][b]', '[/b][/b]', '[i][i]', '[/i][/i]'],
['[b]', '[/b]', '[i]', '[/i]'],
$message
);
// Handling Yahoo style of mails
$message = str_replace('[hr][b]From:[/b]', '[quote][b]From:[/b]', $message);
// Restore code blocks
$message = preg_replace_callback(
'#\[codeblock-([0-9]+)\]#iU',
function ($matches) use ($codeblocks) {
$return = '';
if (isset($codeblocks[intval($matches[1])])) {
$return = $codeblocks[$matches[1]];
}
return $return;
},
$message
);
$message = trim($message);
if ($basepath != '') {
$message = addHostname($message, $basepath);
}
return $message;
}
/**
* @brief Sub function to complete incomplete URL
*
* @param array $matches Result of preg_replace_callback
* @param string $basepath Basepath that is used to complete the URL
*
* @return string The expanded URL
*/
function addHostnameSub($matches, $basepath)
{
$base = parse_url($basepath);
unset($base['query']);
unset($base['fragment']);
$link = $matches[0];
$url = $matches[1];
$parts = array_merge($base, parse_url($url));
$url2 = Network::unparseURL($parts);
return str_replace($url, $url2, $link);
}
/**
* @brief Complete incomplete URLs in BBCode
*
* @param string $body Body with URLs
* @param string $basepath Basepath that is used to complete the URL
*
* @return string Body with expanded URLs
*/
function addHostname($body, $basepath)
{
$URLSearchString = "^\[\]";
$matches = ["/\[url\=([$URLSearchString]*)\].*?\[\/url\]/ism",
"/\[url\]([$URLSearchString]*)\[\/url\]/ism",
"/\[img\=[0-9]*x[0-9]*\](.*?)\[\/img\]/ism",
"/\[img\](.*?)\[\/img\]/ism",
"/\[zmg\=[0-9]*x[0-9]*\](.*?)\[\/img\]/ism",
"/\[zmg\](.*?)\[\/zmg\]/ism",
"/\[video\](.*?)\[\/video\]/ism",
"/\[audio\](.*?)\[\/audio\]/ism",
];
foreach ($matches as $match) {
$body = preg_replace_callback(
$match,
function ($match) use ($basepath) {
return addHostnameSub($match, $basepath);
},
$body
);
}
return $body;
}

View file

@ -1,246 +0,0 @@
<?php
require_once 'include/html2bbcode.php';
function breaklines($line, $level, $wraplength = 75)
{
if ($wraplength == 0) {
$wraplength = 2000000;
}
$wraplen = $wraplength - $level;
$newlines = [];
do {
$oldline = $line;
$subline = substr($line, 0, $wraplen);
$pos = strrpos($subline, ' ');
if ($pos == 0) {
$pos = strpos($line, ' ');
}
if (($pos > 0) && strlen($line) > $wraplen) {
$newline = trim(substr($line, 0, $pos));
if ($level > 0) {
$newline = str_repeat(">", $level) . ' ' . $newline;
}
$newlines[] = $newline . " ";
$line = substr($line, $pos + 1);
}
} while ((strlen($line) > $wraplen) && !($oldline == $line));
if ($level > 0) {
$line = str_repeat(">", $level) . ' ' . $line;
}
$newlines[] = $line;
return implode($newlines, "\n");
}
function quotelevel($message, $wraplength = 75)
{
$lines = explode("\n", $message);
$newlines = [];
$level = 0;
foreach ($lines as $line) {
$line = trim($line);
$startquote = false;
while (strpos("*" . $line, '[quote]') > 0) {
$level++;
$pos = strpos($line, '[quote]');
$line = substr($line, 0, $pos) . substr($line, $pos + 7);
$startquote = true;
}
$currlevel = $level;
while (strpos("*" . $line, '[/quote]') > 0) {
$level--;
if ($level < 0) {
$level = 0;
}
$pos = strpos($line, '[/quote]');
$line = substr($line, 0, $pos) . substr($line, $pos + 8);
}
if (!$startquote || ($line != '')) {
$newlines[] = breaklines($line, $currlevel, $wraplength);
}
}
return implode($newlines, "\n");
}
function collecturls($message)
{
$pattern = '/<a.*?href="(.*?)".*?>(.*?)<\/a>/is';
preg_match_all($pattern, $message, $result, PREG_SET_ORDER);
$urls = [];
foreach ($result as $treffer) {
$ignore = false;
// A list of some links that should be ignored
$list = ["/user/", "/tag/", "/group/", "/profile/", "/search?search=", "/search?tag=", "mailto:", "/u/", "/node/",
"//facebook.com/profile.php?id=", "//plus.google.com/", "//twitter.com/"];
foreach ($list as $listitem) {
if (strpos($treffer[1], $listitem) !== false) {
$ignore = true;
}
}
if ((strpos($treffer[1], "//twitter.com/") !== false) && (strpos($treffer[1], "/status/") !== false)) {
$ignore = false;
}
if ((strpos($treffer[1], "//plus.google.com/") !== false) && (strpos($treffer[1], "/posts") !== false)) {
$ignore = false;
}
if ((strpos($treffer[1], "//plus.google.com/") !== false) && (strpos($treffer[1], "/photos") !== false)) {
$ignore = false;
}
if (!$ignore) {
$urls[$treffer[1]] = $treffer[1];
}
}
return $urls;
}
function html2plain($html, $wraplength = 75, $compact = false)
{
global $lang;
$message = str_replace("\r", "", $html);
$doc = new DOMDocument();
$doc->preserveWhiteSpace = false;
$message = mb_convert_encoding($message, 'HTML-ENTITIES', "UTF-8");
@$doc->loadHTML($message);
$xpath = new DomXPath($doc);
$list = $xpath->query("//pre");
foreach ($list as $node) {
$node->nodeValue = str_replace("\n", "\r", $node->nodeValue);
}
$message = $doc->saveHTML();
$message = str_replace(["\n<", ">\n", "\r", "\n", "\xC3\x82\xC2\xA0"], ["<", ">", "<br>", " ", ""], $message);
$message = preg_replace('= [\s]*=i', " ", $message);
// Collecting all links
$urls = collecturls($message);
@$doc->loadHTML($message);
node2bbcode($doc, 'html', [], '', '');
node2bbcode($doc, 'body', [], '', '');
// MyBB-Auszeichnungen
/*
node2bbcode($doc, 'span', array('style'=>'text-decoration: underline;'), '_', '_');
node2bbcode($doc, 'span', array('style'=>'font-style: italic;'), '/', '/');
node2bbcode($doc, 'span', array('style'=>'font-weight: bold;'), '*', '*');
node2bbcode($doc, 'strong', array(), '*', '*');
node2bbcode($doc, 'b', array(), '*', '*');
node2bbcode($doc, 'i', array(), '/', '/');
node2bbcode($doc, 'u', array(), '_', '_');
*/
if ($compact) {
node2bbcode($doc, 'blockquote', [], "»", "«");
} else {
node2bbcode($doc, 'blockquote', [], '[quote]', "[/quote]\n");
}
node2bbcode($doc, 'br', [], "\n", '');
node2bbcode($doc, 'span', [], "", "");
node2bbcode($doc, 'pre', [], "", "");
node2bbcode($doc, 'div', [], "\r", "\r");
node2bbcode($doc, 'p', [], "\n", "\n");
//node2bbcode($doc, 'ul', array(), "\n[list]", "[/list]\n");
//node2bbcode($doc, 'ol', array(), "\n[list=1]", "[/list]\n");
node2bbcode($doc, 'li', [], "\n* ", "\n");
node2bbcode($doc, 'hr', [], "\n" . str_repeat("-", 70) . "\n", "");
node2bbcode($doc, 'tr', [], "\n", "");
node2bbcode($doc, 'td', [], "\t", "");
node2bbcode($doc, 'h1', [], "\n\n*", "*\n");
node2bbcode($doc, 'h2', [], "\n\n*", "*\n");
node2bbcode($doc, 'h3', [], "\n\n*", "*\n");
node2bbcode($doc, 'h4', [], "\n\n*", "*\n");
node2bbcode($doc, 'h5', [], "\n\n*", "*\n");
node2bbcode($doc, 'h6', [], "\n\n*", "*\n");
// Problem: there is no reliable way to detect if it is a link to a tag or profile
//node2bbcode($doc, 'a', array('href'=>'/(.+)/'), ' $1 ', ' ', true);
//node2bbcode($doc, 'a', array('href'=>'/(.+)/', 'rel'=>'oembed'), ' $1 ', '', true);
//node2bbcode($doc, 'img', array('alt'=>'/(.+)/'), '$1', '');
//node2bbcode($doc, 'img', array('title'=>'/(.+)/'), '$1', '');
//node2bbcode($doc, 'img', array(), '', '');
if (!$compact) {
node2bbcode($doc, 'img', ['src' => '/(.+)/'], ' [img]$1', '[/img] ');
} else {
node2bbcode($doc, 'img', ['src' => '/(.+)/'], ' ', ' ');
}
node2bbcode($doc, 'iframe', ['src' => '/(.+)/'], ' $1 ', '');
$message = $doc->saveHTML();
if (!$compact) {
$message = str_replace("[img]", "", $message);
$message = str_replace("[/img]", "", $message);
}
// was ersetze ich da?
// Irgendein stoerrisches UTF-Zeug
$message = str_replace(chr(194) . chr(160), ' ', $message);
$message = str_replace("&nbsp;", " ", $message);
// Aufeinanderfolgende DIVs
$message = preg_replace('=\r *\r=i', "\n", $message);
$message = str_replace("\r", "\n", $message);
$message = strip_tags($message);
$message = html_entity_decode($message, ENT_QUOTES, 'UTF-8');
if (!$compact && ($message != '')) {
foreach ($urls as $id => $url) {
if ($url != '' && strpos($message, $url) === false) {
$message .= "\n" . $url . ' ';
}
}
}
$message = str_replace("\n«", "«\n", $message);
$message = str_replace("»\n", "\n»", $message);
do {
$oldmessage = $message;
$message = str_replace("\n\n\n", "\n\n", $message);
} while ($oldmessage != $message);
$message = quotelevel(trim($message), $wraplength);
return trim($message);
}

View file

@ -228,7 +228,7 @@ function add_page_info_to_body($body, $texturl = false, $no_photos = false) {
* *
* @TODO find proper type-hints * @TODO find proper type-hints
*/ */
function consume_feed($xml, $importer, &$contact, &$hub, $datedir = 0, $pass = 0) { function consume_feed($xml, $importer, $contact, &$hub, $datedir = 0, $pass = 0) {
if ($contact['network'] === NETWORK_OSTATUS) { if ($contact['network'] === NETWORK_OSTATUS) {
if ($pass < 2) { if ($pass < 2) {
// Test - remove before flight // Test - remove before flight
@ -290,7 +290,7 @@ function subscribe_to_hub($url, $importer, $contact, $hubmode = 'subscribe') {
return; return;
} }
$push_url = Config::get('system','url') . '/pubsub/' . $r[0]['nickname'] . '/' . $contact['id']; $push_url = System::baseUrl() . '/pubsub/' . $r[0]['nickname'] . '/' . $contact['id'];
// Use a single verify token, even if multiple hubs // Use a single verify token, even if multiple hubs
$verify_token = ((strlen($contact['hub-verify'])) ? $contact['hub-verify'] : random_string()); $verify_token = ((strlen($contact['hub-verify'])) ? $contact['hub-verify'] : random_string());

View file

@ -14,6 +14,7 @@ use Friendica\Core\L10n;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Model\Event;
use Friendica\Model\Item; use Friendica\Model\Item;
use Friendica\Model\Profile; use Friendica\Model\Profile;
use Friendica\Render\FriendicaSmarty; use Friendica\Render\FriendicaSmarty;
@ -21,7 +22,6 @@ use Friendica\Util\DateTimeFormat;
use Friendica\Util\Map; use Friendica\Util\Map;
require_once "mod/proxy.php"; require_once "mod/proxy.php";
require_once "include/event.php";
require_once "include/conversation.php"; require_once "include/conversation.php";
/** /**
@ -1062,7 +1062,7 @@ function linkify($s) {
* Load poke verbs * Load poke verbs
* *
* @return array index is present tense verb * @return array index is present tense verb
value is array containing past tense verb, translation of present, translation of past * value is array containing past tense verb, translation of present, translation of past
* @hook poke_verbs pokes array * @hook poke_verbs pokes array
*/ */
function get_poke_verbs() { function get_poke_verbs() {
@ -1169,31 +1169,51 @@ function redir_private_images($a, &$item)
} }
} }
/**
* Sets the "rendered-html" field of the provided item
*
* Body is preserved to avoid side-effects as we modify it just-in-time for spoilers and private image links
*
* @param array $item
* @param bool $update
*
* @todo Remove reference, simply return "rendered-html" and "rendered-hash"
*/
function put_item_in_cache(&$item, $update = false) function put_item_in_cache(&$item, $update = false)
{ {
$body = $item["body"];
$rendered_hash = defaults($item, 'rendered-hash', ''); $rendered_hash = defaults($item, 'rendered-hash', '');
$rendered_html = defaults($item, 'rendered-html', '');
if ($rendered_hash == '' if ($rendered_hash == ''
|| $item["rendered-html"] == "" || $item["rendered-html"] == ""
|| $rendered_hash != hash("md5", $item["body"]) || $rendered_hash != hash("md5", $item["body"])
|| Config::get("system", "ignore_cache") || Config::get("system", "ignore_cache")
) { ) {
// The function "redir_private_images" changes the body.
// I'm not sure if we should store it permanently, so we save the old value.
$body = $item["body"];
$a = get_app(); $a = get_app();
redir_private_images($a, $item); redir_private_images($a, $item);
$item["rendered-html"] = prepare_text($item["body"]); $item["rendered-html"] = prepare_text($item["body"]);
$item["rendered-hash"] = hash("md5", $item["body"]); $item["rendered-hash"] = hash("md5", $item["body"]);
$item["body"] = $body;
// Force an update if the generated values differ from the existing ones
if ($rendered_hash != $item["rendered-hash"]) {
$update = true;
}
// Only compare the HTML when we forcefully ignore the cache
if (Config::get("system", "ignore_cache") && ($rendered_html != $item["rendered-html"])) {
$update = true;
}
if ($update && ($item["id"] > 0)) { if ($update && ($item["id"] > 0)) {
dba::update('item', ['rendered-html' => $item["rendered-html"], 'rendered-hash' => $item["rendered-hash"]], dba::update('item', ['rendered-html' => $item["rendered-html"], 'rendered-hash' => $item["rendered-hash"]],
['id' => $item["id"]], false); ['id' => $item["id"]], false);
} }
} }
$item["body"] = $body;
} }
/** /**
@ -1202,13 +1222,15 @@ function put_item_in_cache(&$item, $update = false)
* *
* @param array $item * @param array $item
* @param boolean $attach * @param boolean $attach
* @param boolean $is_preview
* @return string item body html * @return string item body html
* @hook prepare_body_init item array before any work * @hook prepare_body_init item array before any work
* @hook prepare_body ('item'=>item array, 'html'=>body string) after first bbcode to html * @hook prepare_body_content_filter ('item'=>item array, 'filter_reasons'=>string array) before first bbcode to html
* @hook prepare_body ('item'=>item array, 'html'=>body string, 'is_preview'=>boolean, 'filter_reasons'=>string array) after first bbcode to html
* @hook prepare_body_final ('item'=>item array, 'html'=>body string) after attach icons and blockquote special case handling (spoiler, author) * @hook prepare_body_final ('item'=>item array, 'html'=>body string) after attach icons and blockquote special case handling (spoiler, author)
*/ */
function prepare_body(&$item, $attach = false, $preview = false) { function prepare_body(array &$item, $attach = false, $is_preview = false)
{
$a = get_app(); $a = get_app();
Addon::callHooks('prepare_body_init', $item); Addon::callHooks('prepare_body_init', $item);
@ -1221,17 +1243,16 @@ function prepare_body(&$item, $attach = false, $preview = false) {
// In order to provide theme developers more possibilities, event items // In order to provide theme developers more possibilities, event items
// are treated differently. // are treated differently.
if ($item['object-type'] === ACTIVITY_OBJ_EVENT && isset($item['event-id'])) { if ($item['object-type'] === ACTIVITY_OBJ_EVENT && isset($item['event-id'])) {
$ev = format_event_item($item); $ev = Event::getItemHTML($item);
return $ev; return $ev;
} }
if (!Config::get('system','suppress_tags')) {
$taglist = dba::p("SELECT `type`, `term`, `url` FROM `term` WHERE `otype` = ? AND `oid` = ? AND `type` IN (?, ?) ORDER BY `tid`", $taglist = dba::p("SELECT `type`, `term`, `url` FROM `term` WHERE `otype` = ? AND `oid` = ? AND `type` IN (?, ?) ORDER BY `tid`",
intval(TERM_OBJ_POST), intval($item['id']), intval(TERM_HASHTAG), intval(TERM_MENTION)); intval(TERM_OBJ_POST), intval($item['id']), intval(TERM_HASHTAG), intval(TERM_MENTION));
while ($tag = dba::fetch($taglist)) { while ($tag = dba::fetch($taglist)) {
if ($tag["url"] == "") { if ($tag["url"] == "") {
$tag["url"] = $searchpath.strtolower($tag["term"]); $tag["url"] = $searchpath . strtolower($tag["term"]);
} }
$orig_tag = $tag["url"]; $orig_tag = $tag["url"];
@ -1242,21 +1263,38 @@ function prepare_body(&$item, $attach = false, $preview = false) {
if ($orig_tag != $tag["url"]) { if ($orig_tag != $tag["url"]) {
$item['body'] = str_replace($orig_tag, $tag["url"], $item['body']); $item['body'] = str_replace($orig_tag, $tag["url"], $item['body']);
} }
$hashtags[] = "#<a href=\"".$tag["url"]."\" target=\"_blank\">".$tag["term"]."</a>";
$hashtags[] = "#<a href=\"" . $tag["url"] . "\" target=\"_blank\">" . $tag["term"] . "</a>";
$prefix = "#"; $prefix = "#";
} elseif ($tag["type"] == TERM_MENTION) { } elseif ($tag["type"] == TERM_MENTION) {
$mentions[] = "@<a href=\"".$tag["url"]."\" target=\"_blank\">".$tag["term"]."</a>"; $mentions[] = "@<a href=\"" . $tag["url"] . "\" target=\"_blank\">" . $tag["term"] . "</a>";
$prefix = "@"; $prefix = "@";
} }
$tags[] = $prefix."<a href=\"".$tag["url"]."\" target=\"_blank\">".$tag["term"]."</a>";
$tags[] = $prefix . "<a href=\"" . $tag["url"] . "\" target=\"_blank\">" . $tag["term"] . "</a>";
} }
dba::close($taglist); dba::close($taglist);
}
$item['tags'] = $tags; $item['tags'] = $tags;
$item['hashtags'] = $hashtags; $item['hashtags'] = $hashtags;
$item['mentions'] = $mentions; $item['mentions'] = $mentions;
// Compile eventual content filter reasons
$filter_reasons = [];
if (!$is_preview && !($item['self'] && local_user() == $item['uid'])) {
if (!empty($item['content-warning']) && (!local_user() || !PConfig::get(local_user(), 'system', 'disable_cw', false))) {
$filter_reasons[] = L10n::t('Content warning: %s', $item['content-warning']);
}
$hook_data = [
'item' => $item,
'filter_reasons' => $filter_reasons
];
Addon::callHooks('prepare_body_content_filter', $hook_data);
$filter_reasons = $hook_data['filter_reasons'];
unset($hook_data);
}
// Update the cached values if there is no "zrl=..." on the links. // Update the cached values if there is no "zrl=..." on the links.
$update = (!local_user() && !remote_user() && ($item["uid"] == 0)); $update = (!local_user() && !remote_user() && ($item["uid"] == 0));
@ -1268,9 +1306,17 @@ function prepare_body(&$item, $attach = false, $preview = false) {
put_item_in_cache($item, $update); put_item_in_cache($item, $update);
$s = $item["rendered-html"]; $s = $item["rendered-html"];
$prep_arr = ['item' => $item, 'html' => $s, 'preview' => $preview]; $hook_data = [
Addon::callHooks('prepare_body', $prep_arr); 'item' => $item,
$s = $prep_arr['html']; 'html' => $s,
'preview' => $is_preview,
'filter_reasons' => $filter_reasons
];
Addon::callHooks('prepare_body', $hook_data);
$s = $hook_data['html'];
unset($hook_data);
$s = apply_content_filter($s, $filter_reasons);
if (! $attach) { if (! $attach) {
// Replace the blockquotes with quotes that are used in mails. // Replace the blockquotes with quotes that are used in mails.
@ -1281,13 +1327,8 @@ function prepare_body(&$item, $attach = false, $preview = false) {
$as = ''; $as = '';
$vhead = false; $vhead = false;
$arr = explode('[/attach],', $item['attach']); $matches = [];
if (count($arr)) { preg_match_all('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\"(?: title=\"(.*?)\")?|', $item['attach'], $matches, PREG_SET_ORDER);
foreach ($arr as $r) {
$matches = false;
$icon = '';
$cnt = preg_match_all('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\" title=\"(.*?)\"|',$r ,$matches, PREG_SET_ORDER);
if ($cnt) {
foreach ($matches as $mtch) { foreach ($matches as $mtch) {
$mime = $mtch[3]; $mime = $mtch[3];
@ -1328,15 +1369,13 @@ function prepare_body(&$item, $attach = false, $preview = false) {
$filesubtype = 'unkn'; $filesubtype = 'unkn';
} }
$title = ((strlen(trim($mtch[4]))) ? escape_tags(trim($mtch[4])) : escape_tags($mtch[1])); $title = escape_tags(trim(!empty($mtch[4]) ? $mtch[4] : $mtch[1]));
$title .= ' ' . $mtch[2] . ' ' . L10n::t('bytes'); $title .= ' ' . $mtch[2] . ' ' . L10n::t('bytes');
$icon = '<div class="attachtype icon s22 type-' . $filetype . ' subtype-' . $filesubtype . '"></div>'; $icon = '<div class="attachtype icon s22 type-' . $filetype . ' subtype-' . $filesubtype . '"></div>';
$as .= '<a href="' . strip_tags($the_url) . '" title="' . $title . '" class="attachlink" target="_blank" >' . $icon . '</a>'; $as .= '<a href="' . strip_tags($the_url) . '" title="' . $title . '" class="attachlink" target="_blank" >' . $icon . '</a>';
} }
}
}
}
if ($as != '') { if ($as != '') {
$s .= '<div class="body-attach">'.$as.'<div class="clear"></div></div>'; $s .= '<div class="body-attach">'.$as.'<div class="clear"></div></div>';
} }
@ -1386,10 +1425,39 @@ function prepare_body(&$item, $attach = false, $preview = false) {
$s = preg_replace('|(<img[^>]+src="[^"]+/photo/[0-9a-f]+)-[0-9]|', "$1-" . $ps, $s); $s = preg_replace('|(<img[^>]+src="[^"]+/photo/[0-9a-f]+)-[0-9]|', "$1-" . $ps, $s);
} }
$prep_arr = ['item' => $item, 'html' => $s]; $hook_data = ['item' => $item, 'html' => $s];
Addon::callHooks('prepare_body_final', $prep_arr); Addon::callHooks('prepare_body_final', $hook_data);
return $prep_arr['html']; return $hook_data['html'];
}
/**
* Given a HTML text and a set of filtering reasons, adds a content hiding header with the provided reasons
*
* Reasons are expected to have been translated already.
*
* @param string $html
* @param array $reasons
* @return string
*/
function apply_content_filter($html, array $reasons)
{
if (count($reasons)) {
$rnd = random_string(8);
$content_filter_html = '<ul class="content-filter-reasons">';
foreach ($reasons as $reason) {
$content_filter_html .= '<li>' . htmlspecialchars($reason) . '</li>' . PHP_EOL;
}
$content_filter_html .= '</ul>
<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;
} }
/** /**
@ -2023,6 +2091,10 @@ function text_highlight($s, $lang) {
$lang = 'javascript'; $lang = 'javascript';
} }
if ($lang === 'bash') {
$lang = 'sh';
}
// @TODO: Replace Text_Highlighter_Renderer_Html by scrivo/highlight.php // @TODO: Replace Text_Highlighter_Renderer_Html by scrivo/highlight.php
// Autoload the library to make constants available // Autoload the library to make constants available

View file

@ -24,9 +24,7 @@ use Friendica\Module\Login;
require_once 'boot.php'; require_once 'boot.php';
if (empty($a)) { $a = new App(__DIR__);
$a = new App(__DIR__);
}
BaseObject::setApp($a); BaseObject::setApp($a);
// We assume that the index.php is called by a frontend process // We assume that the index.php is called by a frontend process
@ -53,9 +51,13 @@ if (!$install) {
require_once "include/dba.php"; require_once "include/dba.php";
if (!$install) { if (!$install) {
dba::connect($db_host, $db_user, $db_pass, $db_data, $install); $result = dba::connect($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data); unset($db_host, $db_user, $db_pass, $db_data);
if (!$result) {
System::unavailable();
}
/** /**
* Load configs from db. Overwrite configs from .htconfig.php * Load configs from db. Overwrite configs from .htconfig.php
*/ */
@ -72,12 +74,13 @@ if (!$install) {
if (Config::get('system', 'force_ssl') && ($a->get_scheme() == "http") if (Config::get('system', 'force_ssl') && ($a->get_scheme() == "http")
&& (intval(Config::get('system', 'ssl_policy')) == SSL_POLICY_FULL) && (intval(Config::get('system', 'ssl_policy')) == SSL_POLICY_FULL)
&& (substr(System::baseUrl(), 0, 8) == "https://") && (substr(System::baseUrl(), 0, 8) == "https://")
) { && ($_SERVER['REQUEST_METHOD'] == 'GET')) {
header("HTTP/1.1 302 Moved Temporarily"); header("HTTP/1.1 302 Moved Temporarily");
header("Location: " . System::baseUrl() . "/" . $a->query_string); header("Location: " . System::baseUrl() . "/" . $a->query_string);
exit(); exit();
} }
Config::init();
Session::init(); Session::init();
Addon::loadHooks(); Addon::loadHooks();
Addon::callHooks('init_1'); Addon::callHooks('init_1');
@ -225,8 +228,36 @@ if (strlen($a->module)) {
*/ */
// Compatibility with the Android Diaspora client // Compatibility with the Android Diaspora client
if ($a->module == "stream") { if ($a->module == 'stream') {
$a->module = "network"; goaway('network?f=&order=post');
}
if ($a->module == 'conversations') {
goaway('message');
}
if ($a->module == 'commented') {
goaway('network?f=&order=comment');
}
if ($a->module == 'liked') {
goaway('network?f=&order=comment');
}
if ($a->module == 'activity') {
goaway('network/?f=&conv=1');
}
if (($a->module == 'status_messages') && ($a->cmd == 'status_messages/new')) {
goaway('bookmarklet');
}
if (($a->module == 'user') && ($a->cmd == 'user/edit')) {
goaway('settings');
}
if (($a->module == 'tag_followings') && ($a->cmd == 'tag_followings/manage')) {
goaway('search');
} }
// Compatibility with the Firefox App // Compatibility with the Firefox App

View file

@ -46,8 +46,10 @@ function wk_social_relay()
$server_tags = Config::get('system', 'relay_server_tags'); $server_tags = Config::get('system', 'relay_server_tags');
$tagitems = explode(",", $server_tags); $tagitems = explode(",", $server_tags);
/// @todo Check if it was better to use "strtolower" on the tags
foreach ($tagitems AS $tag) { foreach ($tagitems AS $tag) {
$tags[trim($tag, "# ")] = trim($tag, "# "); $tag = trim($tag, "# ");
$tags[$tag] = $tag;
} }
if (Config::get('system', 'relay_user_tags')) { if (Config::get('system', 'relay_user_tags')) {
@ -62,8 +64,10 @@ function wk_social_relay()
$taglist = []; $taglist = [];
foreach ($tags AS $tag) { foreach ($tags AS $tag) {
if (!empty($tag)) {
$taglist[] = $tag; $taglist[] = $tag;
} }
}
$relay = [ $relay = [
"subscribe" => $subscribe, "subscribe" => $subscribe,

View file

@ -32,7 +32,7 @@ function acl_content(App $a)
$search = $_REQUEST['query']; $search = $_REQUEST['query'];
} }
logger('Searching for ' . $search . ' - type ' . $type, LOGGER_DEBUG); logger("Searching for ".$search." - type ".$type." conversation ".$conv_id, LOGGER_DEBUG);
if ($search != '') { if ($search != '') {
$sql_extra = "AND `name` LIKE '%%" . dbesc($search) . "%%'"; $sql_extra = "AND `name` LIKE '%%" . dbesc($search) . "%%'";
@ -239,6 +239,12 @@ function acl_content(App $a)
$items = array_merge($groups, $contacts); $items = array_merge($groups, $contacts);
if ($conv_id) { if ($conv_id) {
// In multi threaded posts the conv_id is not the parent of the whole thread
$parent_item = dba::selectFirst('item', ['parent'], ['id' => $conv_id]);
if (DBM::is_result($parent_item)) {
$conv_id = $parent_item['parent'];
}
/* /*
* if $conv_id is set, get unknown contacts in thread * if $conv_id is set, get unknown contacts in thread
* but first get known contacts url to filter them out * but first get known contacts url to filter them out

View file

@ -109,6 +109,9 @@ function admin_post(App $a)
} }
$return_path = 'admin/themes/' . $theme; $return_path = 'admin/themes/' . $theme;
break; break;
case 'tos':
admin_page_tos_post($a);
break;
case 'features': case 'features':
admin_page_features_post($a); admin_page_features_post($a);
break; break;
@ -181,7 +184,8 @@ function admin_content(App $a)
'users' => ["admin/users/" , L10n::t("Users") , "users"], 'users' => ["admin/users/" , L10n::t("Users") , "users"],
'addons' => ["admin/addons/" , L10n::t("Addons") , "addons"], 'addons' => ["admin/addons/" , L10n::t("Addons") , "addons"],
'themes' => ["admin/themes/" , L10n::t("Themes") , "themes"], 'themes' => ["admin/themes/" , L10n::t("Themes") , "themes"],
'features' => ["admin/features/" , L10n::t("Additional features") , "features"] ]], 'features' => ["admin/features/" , L10n::t("Additional features") , "features"],
'tos' => ["admin/tos/" , L10n::t("Terms of Service") , "tos"] ]],
'database' => [ L10n::t('Database'), [ 'database' => [ L10n::t('Database'), [
'dbsync' => ["admin/dbsync/" , L10n::t('DB updates') , "dbsync"], 'dbsync' => ["admin/dbsync/" , L10n::t('DB updates') , "dbsync"],
'queue' => ["admin/queue/" , L10n::t('Inspect Queue') , "queue"], ]], 'queue' => ["admin/queue/" , L10n::t('Inspect Queue') , "queue"], ]],
@ -265,6 +269,9 @@ function admin_content(App $a)
case 'deleteitem': case 'deleteitem':
$o = admin_page_deleteitem($a); $o = admin_page_deleteitem($a);
break; break;
case 'tos':
$o = admin_page_tos($a);
break;
default: default:
notice(L10n::t("Item not found.")); notice(L10n::t("Item not found."));
} }
@ -281,6 +288,50 @@ function admin_content(App $a)
} }
} }
/**
* @brief Subpage to define the display of a Terms of Usage page.
*
* @param App $a
* @return string
*/
function admin_page_tos(App $a)
{
$t = get_markup_template('admin/tos.tpl');
return replace_macros($t, [
'$title' => L10n::t('Administration'),
'$page' => L10n::t('Terms of Service'),
'$displaytos' => ['displaytos', L10n::t('Display Terms of Service'), Config::get('system', 'tosdisplay'), L10n::t('Enable the Terms of Service page. If this is enabled a link to the terms will be added to the registration form and the general information page.')],
'$displayprivstatement' => ['displayprivstatement', L10n::t('Display Privacy Statement'), Config::get('system','tosprivstatement'), L10n::t('Show some informations regarding the needed information to operate the node according e.g. to <a href="%s" target="_blank">EU-GDPR</a>.','https://en.wikipedia.org/wiki/General_Data_Protection_Regulation')],
'$tostext' => ['tostext', L10n::t('The Terms of Service'), Config::get('system', 'tostext'), L10n::t('Enter the Terms of Service for your node here. You can use BBCode. Headers of sections should be [h2] and below.')],
'$form_security_token' => get_form_security_token("admin_tos"),
'$submit' => L10n::t('Save Settings'),
]);
}
/**
* @brief Process send data from Admin TOS Page
*
* @param App $a
*/
function admin_page_tos_post(App $a)
{
check_form_security_token_redirectOnErr('/admin/tos', 'admin_tos');
if (!x($_POST, "page_tos")) {
return;
}
$displaytos = ((x($_POST, 'displaytos')) ? True : False);
$displayprivstatement = ((x($_POST, 'displayprivstatement')) ? True : False);
$tostext = ((x($_POST, 'tostext')) ? strip_tags(trim($_POST['tostext'])) : '');
Config::set('system', 'tosdisplay', $displaytos);
Config::set('system', 'tosprivstatement', $displayprivstatement);
Config::set('system', 'tostext', $tostext);
goaway('admin/tos');
return; // NOTREACHED
}
/** /**
* @brief Subpage to modify the server wide block list via the admin panel. * @brief Subpage to modify the server wide block list via the admin panel.
* *
@ -635,8 +686,21 @@ function admin_page_federation(App $a)
$v = $newVv; $v = $newVv;
} }
foreach ($v as $key => $vv) // Assure that the versions are sorted correctly
$v[$key]["version"] = trim(strip_tags($vv["version"])); $v2 = [];
$versions = [];
foreach ($v as $vv) {
$version = trim(strip_tags($vv["version"]));
$v2[$version] = $vv;
$versions[] = $version;
}
usort($versions, 'version_compare');
$v = [];
foreach ($versions as $version) {
$v[] = $v2[$version];
}
// the 3rd array item is needed for the JavaScript graphs as JS does // the 3rd array item is needed for the JavaScript graphs as JS does
// not like some characters in the names of variables... // not like some characters in the names of variables...
@ -718,7 +782,7 @@ function admin_page_summary(App $a)
$warningtext = []; $warningtext = [];
if (DBM::is_result($r)) { if (DBM::is_result($r)) {
$showwarning = true; $showwarning = true;
$warningtext[] = L10n::t('Your DB still runs with MyISAM tables. You should change the engine type to InnoDB. As Friendica will use InnoDB only features in the future, you should change this! See <a href="%s">here</a> for a guide that may be helpful converting the table engines. You may also use the command <tt>php scripts/dbstructure.php toinnodb</tt> of your Friendica installation for an automatic conversion.<br />', 'https://dev.mysql.com/doc/refman/5.7/en/converting-tables-to-innodb.html'); $warningtext[] = L10n::t('Your DB still runs with MyISAM tables. You should change the engine type to InnoDB. As Friendica will use InnoDB only features in the future, you should change this! See <a href="%s">here</a> for a guide that may be helpful converting the table engines. You may also use the command <tt>php bin/console.php dbstructure toinnodb</tt> of your Friendica installation for an automatic conversion.<br />', 'https://dev.mysql.com/doc/refman/5.7/en/converting-tables-to-innodb.html');
} }
// Check if github.com/friendica/master/VERSION is higher then // Check if github.com/friendica/master/VERSION is higher then
// the local version of Friendica. Check is opt-in, source may be master or devel branch // the local version of Friendica. Check is opt-in, source may be master or devel branch
@ -735,7 +799,7 @@ function admin_page_summary(App $a)
} }
if (Config::get('system', 'dbupdate') == DB_UPDATE_FAILED) { if (Config::get('system', 'dbupdate') == DB_UPDATE_FAILED) {
$showwarning = true; $showwarning = true;
$warningtext[] = L10n::t('The database update failed. Please run "php scripts/dbstructure.php update" from the command line and have a look at the errors that might appear.'); $warningtext[] = L10n::t('The database update failed. Please run "php bin/console.php dbstructure update" from the command line and have a look at the errors that might appear.');
} }
$last_worker_call = Config::get('system', 'last_poller_execution', false); $last_worker_call = Config::get('system', 'last_poller_execution', false);
@ -871,8 +935,9 @@ function admin_page_site_post(App $a)
update_table("gcontact", ['connect', 'addr'], $old_host, $new_host); update_table("gcontact", ['connect', 'addr'], $old_host, $new_host);
// update config // update config
$a->set_baseurl($new_url); Config::set('system', 'hostname', parse_url($new_url, PHP_URL_HOST));
Config::set('system', 'url', $new_url); Config::set('system', 'url', $new_url);
$a->set_baseurl($new_url);
// send relocate // send relocate
$users = q("SELECT `uid` FROM `user` WHERE `account_removed` = 0 AND `account_expired` = 0"); $users = q("SELECT `uid` FROM `user` WHERE `account_removed` = 0 AND `account_expired` = 0");
@ -906,7 +971,7 @@ function admin_page_site_post(App $a)
$daily_registrations = ((x($_POST,'max_daily_registrations')) ? intval(trim($_POST['max_daily_registrations'])) :0); $daily_registrations = ((x($_POST,'max_daily_registrations')) ? intval(trim($_POST['max_daily_registrations'])) :0);
$abandon_days = ((x($_POST,'abandon_days')) ? intval(trim($_POST['abandon_days'])) : 0); $abandon_days = ((x($_POST,'abandon_days')) ? intval(trim($_POST['abandon_days'])) : 0);
$register_text = ((x($_POST,'register_text')) ? notags(trim($_POST['register_text'])) : ''); $register_text = ((x($_POST,'register_text')) ? strip_tags(trim($_POST['register_text'])) : '');
$allowed_sites = ((x($_POST,'allowed_sites')) ? notags(trim($_POST['allowed_sites'])) : ''); $allowed_sites = ((x($_POST,'allowed_sites')) ? notags(trim($_POST['allowed_sites'])) : '');
$allowed_email = ((x($_POST,'allowed_email')) ? notags(trim($_POST['allowed_email'])) : ''); $allowed_email = ((x($_POST,'allowed_email')) ? notags(trim($_POST['allowed_email'])) : '');
@ -960,11 +1025,19 @@ function admin_page_site_post(App $a)
$only_tag_search = ((x($_POST,'only_tag_search')) ? True : False); $only_tag_search = ((x($_POST,'only_tag_search')) ? True : False);
$rino = ((x($_POST,'rino')) ? intval($_POST['rino']) : 0); $rino = ((x($_POST,'rino')) ? intval($_POST['rino']) : 0);
$check_new_version_url = ((x($_POST, 'check_new_version_url')) ? notags(trim($_POST['check_new_version_url'])) : 'none'); $check_new_version_url = ((x($_POST, 'check_new_version_url')) ? notags(trim($_POST['check_new_version_url'])) : 'none');
$worker_queues = ((x($_POST,'worker_queues')) ? intval($_POST['worker_queues']) : 4); $worker_queues = ((x($_POST,'worker_queues')) ? intval($_POST['worker_queues']) : 4);
$worker_dont_fork = ((x($_POST,'worker_dont_fork')) ? True : False); $worker_dont_fork = ((x($_POST,'worker_dont_fork')) ? True : False);
$worker_fastlane = ((x($_POST,'worker_fastlane')) ? True : False); $worker_fastlane = ((x($_POST,'worker_fastlane')) ? True : False);
$worker_frontend = ((x($_POST,'worker_frontend')) ? True : False); $worker_frontend = ((x($_POST,'worker_frontend')) ? True : False);
$relay_directly = ((x($_POST,'relay_directly')) ? True : False);
$relay_server = ((x($_POST,'relay_server')) ? notags(trim($_POST['relay_server'])) : '');
$relay_subscribe = ((x($_POST,'relay_subscribe')) ? True : False);
$relay_scope = ((x($_POST,'relay_scope')) ? notags(trim($_POST['relay_scope'])) : '');
$relay_server_tags = ((x($_POST,'relay_server_tags')) ? notags(trim($_POST['relay_server_tags'])) : '');
$relay_user_tags = ((x($_POST,'relay_user_tags')) ? True : False);
// Has the directory url changed? If yes, then resubmit the existing profiles there // Has the directory url changed? If yes, then resubmit the existing profiles there
if ($global_directory != Config::get('system', 'directory') && ($global_directory != '')) { if ($global_directory != Config::get('system', 'directory') && ($global_directory != '')) {
Config::set('system', 'directory', $global_directory); Config::set('system', 'directory', $global_directory);
@ -1118,10 +1191,19 @@ function admin_page_site_post(App $a)
Config::set('system', 'basepath', $basepath); Config::set('system', 'basepath', $basepath);
Config::set('system', 'proxy_disabled', $proxy_disabled); Config::set('system', 'proxy_disabled', $proxy_disabled);
Config::set('system', 'only_tag_search', $only_tag_search); Config::set('system', 'only_tag_search', $only_tag_search);
Config::set('system', 'worker_queues', $worker_queues); Config::set('system', 'worker_queues', $worker_queues);
Config::set('system', 'worker_dont_fork', $worker_dont_fork); Config::set('system', 'worker_dont_fork', $worker_dont_fork);
Config::set('system', 'worker_fastlane', $worker_fastlane); Config::set('system', 'worker_fastlane', $worker_fastlane);
Config::set('system', 'frontend_worker', $worker_frontend); Config::set('system', 'frontend_worker', $worker_frontend);
Config::set('system', 'relay_directly', $relay_directly);
Config::set('system', 'relay_server', $relay_server);
Config::set('system', 'relay_subscribe', $relay_subscribe);
Config::set('system', 'relay_scope', $relay_scope);
Config::set('system', 'relay_server_tags', $relay_server_tags);
Config::set('system', 'relay_user_tags', $relay_user_tags);
Config::set('system', 'rino_encrypt', $rino); Config::set('system', 'rino_encrypt', $rino);
info(L10n::t('Site settings updated.') . EOL); info(L10n::t('Site settings updated.') . EOL);
@ -1270,6 +1352,7 @@ function admin_page_site(App $a)
'$portable_contacts' => L10n::t('Auto Discovered Contact Directory'), '$portable_contacts' => L10n::t('Auto Discovered Contact Directory'),
'$performance' => L10n::t('Performance'), '$performance' => L10n::t('Performance'),
'$worker_title' => L10n::t('Worker'), '$worker_title' => L10n::t('Worker'),
'$relay_title' => L10n::t('Message Relay'),
'$relocate' => L10n::t('Relocate - WARNING: advanced function. Could make this server unreachable.'), '$relocate' => L10n::t('Relocate - WARNING: advanced function. Could make this server unreachable.'),
'$baseurl' => System::baseUrl(true), '$baseurl' => System::baseUrl(true),
// name, label, value, help string, extra data... // name, label, value, help string, extra data...
@ -1293,7 +1376,7 @@ function admin_page_site(App $a)
'$register_policy' => ['register_policy', L10n::t("Register policy"), $a->config['register_policy'], "", $register_choices], '$register_policy' => ['register_policy', L10n::t("Register policy"), $a->config['register_policy'], "", $register_choices],
'$daily_registrations' => ['max_daily_registrations', L10n::t("Maximum Daily Registrations"), Config::get('system', 'max_daily_registrations'), L10n::t("If registration is permitted above, this sets the maximum number of new user registrations to accept per day. If register is set to closed, this setting has no effect.")], '$daily_registrations' => ['max_daily_registrations', L10n::t("Maximum Daily Registrations"), Config::get('system', 'max_daily_registrations'), L10n::t("If registration is permitted above, this sets the maximum number of new user registrations to accept per day. If register is set to closed, this setting has no effect.")],
'$register_text' => ['register_text', L10n::t("Register text"), $a->config['register_text'], L10n::t("Will be displayed prominently on the registration page.")], '$register_text' => ['register_text', L10n::t("Register text"), $a->config['register_text'], L10n::t("Will be displayed prominently on the registration page. You can use BBCode here.")],
'$abandon_days' => ['abandon_days', L10n::t('Accounts abandoned after x days'), Config::get('system','account_abandon_days'), L10n::t('Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.')], '$abandon_days' => ['abandon_days', L10n::t('Accounts abandoned after x days'), Config::get('system','account_abandon_days'), L10n::t('Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.')],
'$allowed_sites' => ['allowed_sites', L10n::t("Allowed friend domains"), Config::get('system','allowed_sites'), L10n::t("Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains")], '$allowed_sites' => ['allowed_sites', L10n::t("Allowed friend domains"), Config::get('system','allowed_sites'), L10n::t("Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains")],
'$allowed_email' => ['allowed_email', L10n::t("Allowed email domains"), Config::get('system','allowed_email'), L10n::t("Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains")], '$allowed_email' => ['allowed_email', L10n::t("Allowed email domains"), Config::get('system','allowed_email'), L10n::t("Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains")],
@ -1301,7 +1384,7 @@ function admin_page_site(App $a)
'$allowed_oembed' => ['allowed_oembed', L10n::t("Allowed OEmbed domains"), Config::get('system','allowed_oembed'), L10n::t("Comma separated list of domains which oembed content is allowed to be displayed. Wildcards are accepted.")], '$allowed_oembed' => ['allowed_oembed', L10n::t("Allowed OEmbed domains"), Config::get('system','allowed_oembed'), L10n::t("Comma separated list of domains which oembed content is allowed to be displayed. Wildcards are accepted.")],
'$block_public' => ['block_public', L10n::t("Block public"), Config::get('system','block_public'), L10n::t("Check to block public access to all otherwise public personal pages on this site unless you are currently logged in.")], '$block_public' => ['block_public', L10n::t("Block public"), Config::get('system','block_public'), L10n::t("Check to block public access to all otherwise public personal pages on this site unless you are currently logged in.")],
'$force_publish' => ['publish_all', L10n::t("Force publish"), Config::get('system','publish_all'), L10n::t("Check to force all profiles on this site to be listed in the site directory.")], '$force_publish' => ['publish_all', L10n::t("Force publish"), Config::get('system','publish_all'), L10n::t("Check to force all profiles on this site to be listed in the site directory.")],
'$global_directory' => ['directory', L10n::t("Global directory URL"), Config::get('system','directory'), L10n::t("URL to the global directory. If this is not set, the global directory is completely unavailable to the application.")], '$global_directory' => ['directory', L10n::t("Global directory URL"), Config::get('system', 'directory', 'https://dir.friendica.social'), L10n::t("URL to the global directory. If this is not set, the global directory is completely unavailable to the application.")],
'$newuser_private' => ['newuser_private', L10n::t("Private posts by default for new users"), Config::get('system','newuser_private'), L10n::t("Set default post permissions for all new members to the default privacy group rather than public.")], '$newuser_private' => ['newuser_private', L10n::t("Private posts by default for new users"), Config::get('system','newuser_private'), L10n::t("Set default post permissions for all new members to the default privacy group rather than public.")],
'$enotify_no_content' => ['enotify_no_content', L10n::t("Don't include post content in email notifications"), Config::get('system','enotify_no_content'), L10n::t("Don't include the content of a post/comment/private message/etc. in the email notifications that are sent out from this site, as a privacy measure.")], '$enotify_no_content' => ['enotify_no_content', L10n::t("Don't include post content in email notifications"), Config::get('system','enotify_no_content'), L10n::t("Don't include the content of a post/comment/private message/etc. in the email notifications that are sent out from this site, as a privacy measure.")],
'$private_addons' => ['private_addons', L10n::t("Disallow public access to addons listed in the apps menu."), Config::get('config','private_addons'), L10n::t("Checking this box will restrict addons listed in the apps menu to members only.")], '$private_addons' => ['private_addons', L10n::t("Disallow public access to addons listed in the apps menu."), Config::get('config','private_addons'), L10n::t("Checking this box will restrict addons listed in the apps menu to members only.")],
@ -1317,17 +1400,17 @@ function admin_page_site(App $a)
'$ostatus_not_able' => L10n::t("OStatus support can only be enabled if threading is enabled."), '$ostatus_not_able' => L10n::t("OStatus support can only be enabled if threading is enabled."),
'$diaspora_able' => $diaspora_able, '$diaspora_able' => $diaspora_able,
'$diaspora_not_able' => L10n::t("Diaspora support can't be enabled because Friendica was installed into a sub directory."), '$diaspora_not_able' => L10n::t("Diaspora support can't be enabled because Friendica was installed into a sub directory."),
'$diaspora_enabled' => ['diaspora_enabled', L10n::t("Enable Diaspora support"), Config::get('system','diaspora_enabled'), L10n::t("Provide built-in Diaspora network compatibility.")], '$diaspora_enabled' => ['diaspora_enabled', L10n::t("Enable Diaspora support"), Config::get('system', 'diaspora_enabled', $diaspora_able), L10n::t("Provide built-in Diaspora network compatibility.")],
'$dfrn_only' => ['dfrn_only', L10n::t('Only allow Friendica contacts'), Config::get('system','dfrn_only'), L10n::t("All contacts must use Friendica protocols. All other built-in communication protocols disabled.")], '$dfrn_only' => ['dfrn_only', L10n::t('Only allow Friendica contacts'), Config::get('system','dfrn_only'), L10n::t("All contacts must use Friendica protocols. All other built-in communication protocols disabled.")],
'$verifyssl' => ['verifyssl', L10n::t("Verify SSL"), Config::get('system','verifyssl'), L10n::t("If you wish, you can turn on strict certificate checking. This will mean you cannot connect \x28at all\x29 to self-signed SSL sites.")], '$verifyssl' => ['verifyssl', L10n::t("Verify SSL"), Config::get('system','verifyssl'), L10n::t("If you wish, you can turn on strict certificate checking. This will mean you cannot connect \x28at all\x29 to self-signed SSL sites.")],
'$proxyuser' => ['proxyuser', L10n::t("Proxy user"), Config::get('system','proxyuser'), ""], '$proxyuser' => ['proxyuser', L10n::t("Proxy user"), Config::get('system','proxyuser'), ""],
'$proxy' => ['proxy', L10n::t("Proxy URL"), Config::get('system','proxy'), ""], '$proxy' => ['proxy', L10n::t("Proxy URL"), Config::get('system','proxy'), ""],
'$timeout' => ['timeout', L10n::t("Network timeout"), (x(Config::get('system','curl_timeout'))?Config::get('system','curl_timeout'):60), L10n::t("Value is in seconds. Set to 0 for unlimited \x28not recommended\x29.")], '$timeout' => ['timeout', L10n::t("Network timeout"), Config::get('system', 'curl_timeout', 60), L10n::t("Value is in seconds. Set to 0 for unlimited \x28not recommended\x29.")],
'$maxloadavg' => ['maxloadavg', L10n::t("Maximum Load Average"), ((intval(Config::get('system','maxloadavg')) > 0)?Config::get('system','maxloadavg'):50), L10n::t("Maximum system load before delivery and poll processes are deferred - default 50.")], '$maxloadavg' => ['maxloadavg', L10n::t("Maximum Load Average"), Config::get('system', 'maxloadavg', 50), L10n::t("Maximum system load before delivery and poll processes are deferred - default 50.")],
'$maxloadavg_frontend' => ['maxloadavg_frontend', L10n::t("Maximum Load Average \x28Frontend\x29"), ((intval(Config::get('system','maxloadavg_frontend')) > 0)?Config::get('system','maxloadavg_frontend'):50), L10n::t("Maximum system load before the frontend quits service - default 50.")], '$maxloadavg_frontend' => ['maxloadavg_frontend', L10n::t("Maximum Load Average \x28Frontend\x29"), Config::get('system', 'maxloadavg_frontend', 50), L10n::t("Maximum system load before the frontend quits service - default 50.")],
'$min_memory' => ['min_memory', L10n::t("Minimal Memory"), ((intval(Config::get('system','min_memory')) > 0)?Config::get('system','min_memory'):0), L10n::t("Minimal free memory in MB for the worker. Needs access to /proc/meminfo - default 0 \x28deactivated\x29.")], '$min_memory' => ['min_memory', L10n::t("Minimal Memory"), Config::get('system', 'min_memory', 0), L10n::t("Minimal free memory in MB for the worker. Needs access to /proc/meminfo - default 0 \x28deactivated\x29.")],
'$optimize_max_tablesize'=> ['optimize_max_tablesize', L10n::t("Maximum table size for optimization"), $optimize_max_tablesize, L10n::t("Maximum table size \x28in MB\x29 for the automatic optimization - default 100 MB. Enter -1 to disable it.")], '$optimize_max_tablesize'=> ['optimize_max_tablesize', L10n::t("Maximum table size for optimization"), $optimize_max_tablesize, L10n::t("Maximum table size \x28in MB\x29 for the automatic optimization - default 100 MB. Enter -1 to disable it.")],
'$optimize_fragmentation'=> ['optimize_fragmentation', L10n::t("Minimum level of fragmentation"), ((intval(Config::get('system','optimize_fragmentation')) > 0)?Config::get('system','optimize_fragmentation'):30), L10n::t("Minimum fragmenation level to start the automatic optimization - default value is 30%.")], '$optimize_fragmentation'=> ['optimize_fragmentation', L10n::t("Minimum level of fragmentation"), Config::get('system', 'optimize_fragmentation', 30), L10n::t("Minimum fragmenation level to start the automatic optimization - default value is 30%.")],
'$poco_completion' => ['poco_completion', L10n::t("Periodical check of global contacts"), Config::get('system','poco_completion'), L10n::t("If enabled, the global contacts are checked periodically for missing or outdated data and the vitality of the contacts and servers.")], '$poco_completion' => ['poco_completion', L10n::t("Periodical check of global contacts"), Config::get('system','poco_completion'), L10n::t("If enabled, the global contacts are checked periodically for missing or outdated data and the vitality of the contacts and servers.")],
'$poco_requery_days' => ['poco_requery_days', L10n::t("Days between requery"), Config::get('system','poco_requery_days'), L10n::t("Number of days after which a server is requeried for his contacts.")], '$poco_requery_days' => ['poco_requery_days', L10n::t("Days between requery"), Config::get('system','poco_requery_days'), L10n::t("Number of days after which a server is requeried for his contacts.")],
@ -1349,13 +1432,20 @@ function admin_page_site(App $a)
'$relocate_url' => ['relocate_url', L10n::t("New base url"), System::baseUrl(), L10n::t("Change base url for this server. Sends relocate message to all Friendica and Diaspora* contacts of all users.")], '$relocate_url' => ['relocate_url', L10n::t("New base url"), System::baseUrl(), L10n::t("Change base url for this server. Sends relocate message to all Friendica and Diaspora* contacts of all users.")],
'$rino' => ['rino', L10n::t("RINO Encryption"), intval(Config::get('system','rino_encrypt')), L10n::t("Encryption layer between nodes."), [0 => "Disabled", 1 => "Enabled"]], '$rino' => ['rino', L10n::t("RINO Encryption"), intval(Config::get('system','rino_encrypt')), L10n::t("Encryption layer between nodes."), [0 => L10n::t("Disabled"), 1 => L10n::t("Enabled")]],
'$worker_queues' => ['worker_queues', L10n::t("Maximum number of parallel workers"), Config::get('system','worker_queues'), L10n::t("On shared hosters set this to 2. On larger systems, values of 10 are great. Default value is 4.")], '$worker_queues' => ['worker_queues', L10n::t("Maximum number of parallel workers"), Config::get('system','worker_queues'), L10n::t("On shared hosters set this to 2. On larger systems, values of 10 are great. Default value is 4.")],
'$worker_dont_fork' => ['worker_dont_fork', L10n::t("Don't use 'proc_open' with the worker"), Config::get('system','worker_dont_fork'), L10n::t("Enable this if your system doesn't allow the use of 'proc_open'. This can happen on shared hosters. If this is enabled you should increase the frequency of worker calls in your crontab.")], '$worker_dont_fork' => ['worker_dont_fork', L10n::t("Don't use 'proc_open' with the worker"), Config::get('system','worker_dont_fork'), L10n::t("Enable this if your system doesn't allow the use of 'proc_open'. This can happen on shared hosters. If this is enabled you should increase the frequency of worker calls in your crontab.")],
'$worker_fastlane' => ['worker_fastlane', L10n::t("Enable fastlane"), Config::get('system','worker_fastlane'), L10n::t("When enabed, the fastlane mechanism starts an additional worker if processes with higher priority are blocked by processes of lower priority.")], '$worker_fastlane' => ['worker_fastlane', L10n::t("Enable fastlane"), Config::get('system','worker_fastlane'), L10n::t("When enabed, the fastlane mechanism starts an additional worker if processes with higher priority are blocked by processes of lower priority.")],
'$worker_frontend' => ['worker_frontend', L10n::t('Enable frontend worker'), Config::get('system','frontend_worker'), L10n::t('When enabled the Worker process is triggered when backend access is performed \x28e.g. messages being delivered\x29. On smaller sites you might want to call %s/worker on a regular basis via an external cron job. You should only enable this option if you cannot utilize cron/scheduled jobs on your server.', System::baseUrl())], '$worker_frontend' => ['worker_frontend', L10n::t('Enable frontend worker'), Config::get('system','frontend_worker'), L10n::t('When enabled the Worker process is triggered when backend access is performed \x28e.g. messages being delivered\x29. On smaller sites you might want to call %s/worker on a regular basis via an external cron job. You should only enable this option if you cannot utilize cron/scheduled jobs on your server.', System::baseUrl())],
'$relay_subscribe' => ['relay_subscribe', L10n::t("Subscribe to relay"), Config::get('system','relay_subscribe'), L10n::t("Enables the receiving of public posts from the relay. They will be included in the search, subscribed tags and on the global community page.")],
'$relay_server' => ['relay_server', L10n::t("Relay server"), Config::get('system', 'relay_server', 'https://relay.diasp.org'), L10n::t("Address of the relay server where public posts should be send to. For example https://relay.diasp.org")],
'$relay_directly' => ['relay_directly', L10n::t("Direct relay transfer"), Config::get('system','relay_directly'), L10n::t("Enables the direct transfer to other servers without using the relay servers")],
'$relay_scope' => ['relay_scope', L10n::t("Relay scope"), Config::get('system','relay_scope'), L10n::t("Can be 'all' or 'tags'. 'all' means that every public post should be received. 'tags' means that only posts with selected tags should be received."), ['' => L10n::t('Disabled'), 'all' => L10n::t('all'), 'tags' => L10n::t('tags')]],
'$relay_server_tags' => ['relay_server_tags', L10n::t("Server tags"), Config::get('system','relay_server_tags'), L10n::t("Comma separated list of tags for the 'tags' subscription.")],
'$relay_user_tags' => ['relay_user_tags', L10n::t("Allow user tags"), Config::get('system', 'relay_user_tags', true), L10n::t("If enabled, the tags from the saved searches will used for the 'tags' subscription in addition to the 'relay_server_tags'.")],
'$form_security_token' => get_form_security_token("admin_site") '$form_security_token' => get_form_security_token("admin_site")
]); ]);
} }
@ -1508,6 +1598,8 @@ function admin_page_users_post(App $a)
If you are new and do not know anybody here, they may help If you are new and do not know anybody here, they may help
you to make some new and interesting friends. you to make some new and interesting friends.
If you ever want to delete your account, you can do so at %1$s/removeme
Thank you and welcome to %4$s.')); Thank you and welcome to %4$s.'));
$preamble = sprintf($preamble, $user['username'], $a->config['sitename']); $preamble = sprintf($preamble, $user['username'], $a->config['sitename']);
@ -1568,7 +1660,7 @@ function admin_page_users(App $a)
if ($a->argc > 2) { if ($a->argc > 2) {
$uid = $a->argv[3]; $uid = $a->argv[3];
$user = dba::selectFirst('user', ['username', 'blocked'], ['uid' => $uid]); $user = dba::selectFirst('user', ['username', 'blocked'], ['uid' => $uid]);
if (DBM::is_result($user)) { if (!DBM::is_result($user)) {
notice('User not found' . EOL); notice('User not found' . EOL);
goaway('admin/users'); goaway('admin/users');
return ''; // NOTREACHED return ''; // NOTREACHED

View file

@ -3,12 +3,9 @@
* @file mod/babel.php * @file mod/babel.php
*/ */
use Friendica\Content\Text\BBCode; use Friendica\Content\Text;
use Friendica\Content\Text\Markdown;
use Friendica\Core\L10n; use Friendica\Core\L10n;
require_once 'include/html2bbcode.php';
function visible_lf($s) function visible_lf($s)
{ {
return str_replace("\n", '<br />', $s); return str_replace("\n", '<br />', $s);
@ -16,64 +13,104 @@ function visible_lf($s)
function babel_content() function babel_content()
{ {
$o = '<h1>Babel Diagnostic</h1>'; $results = [];
if (!empty($_REQUEST['text'])) {
switch (defaults($_REQUEST, 'type', 'bbcode')) {
case 'bbcode':
$bbcode = trim($_REQUEST['text']);
$results[] = [
'title' => L10n::t('Source input'),
'content' => visible_lf($bbcode)
];
$o .= '<form action="babel" method="post">'; $html = Text\BBCode::convert($bbcode);
$o .= L10n::t("Source \x28bbcode\x29 text:") . EOL; $results[] = [
$o .= '<textarea name="text" cols="80" rows="10">' . htmlspecialchars($_REQUEST['text']) . '</textarea>' . EOL; 'title' => L10n::t("BBCode::convert \x28raw HTML\x29"),
$o .= '<input type="submit" name="submit" value="Submit" /></form>'; 'content' => htmlspecialchars($html)
];
$o .= '<br /><br />'; $results[] = [
'title' => L10n::t('BBCode::convert'),
'content' => $html
];
$o .= '<form action="babel" method="post">'; $bbcode2 = Text\HTML::toBBCode($html);
$o .= L10n::t("Source \x28Diaspora\x29 text to convert to BBcode:") . EOL; $results[] = [
$o .= '<textarea name="d2bbtext" cols="80" rows="10">' . htmlspecialchars($_REQUEST['d2bbtext']) . '</textarea>' . EOL; 'title' => L10n::t('BBCode::convert => HTML::toBBCode'),
$o .= '<input type="submit" name="submit" value="Submit" /></form>'; 'content' => visible_lf($bbcode2)
];
$o .= '<br /><br />'; $markdown = Text\BBCode::toMarkdown($bbcode);
$results[] = [
'title' => L10n::t('BBCode::toMarkdown'),
'content' => visible_lf($markdown)
];
if (x($_REQUEST, 'text')) { $html2 = Text\Markdown::convert($markdown);
$text = trim($_REQUEST['text']); $results[] = [
$o .= '<h2>' . L10n::t('Source input: ') . '</h2>' . EOL . EOL; 'title' => L10n::t('BBCode::toMarkdown => Markdown::convert'),
$o .= visible_lf($text) . EOL . EOL; 'content' => $html2
];
$html = BBCode::convert($text); $bbcode3 = Text\Markdown::toBBCode($markdown);
$o .= '<h2>' . L10n::t("bbcode \x28raw HTML\x28: ") . '</h2>' . EOL . EOL; $results[] = [
$o .= htmlspecialchars($html) . EOL . EOL; 'title' => L10n::t('BBCode::toMarkdown => Markdown::toBBCode'),
'content' => visible_lf($bbcode3)
];
$o .= '<h2>' . L10n::t('bbcode: ') . '</h2>' . EOL . EOL; $bbcode4 = Text\HTML::toBBCode($html2);
$o .= $html . EOL . EOL; $results[] = [
'title' => L10n::t('BBCode::toMarkdown => Markdown::convert => HTML::toBBCode'),
'content' => visible_lf($bbcode4)
];
break;
case 'markdown':
$markdown = trim($_REQUEST['text']);
$results[] = [
'title' => L10n::t('Source input \x28Diaspora format\x29'),
'content' => '<pre>' . $markdown . '</pre>'
];
$bbcode = html2bbcode($html); $bbcode = Text\Markdown::toBBCode($markdown);
$o .= '<h2>' . L10n::t('bbcode => html2bbcode: ') . '</h2>' . EOL . EOL; $results[] = [
$o .= visible_lf($bbcode) . EOL . EOL; 'title' => L10n::t('Markdown::toBBCode'),
'content' => '<pre>' . $bbcode . '</pre>'
];
break;
case 'html' :
$html = trim($_REQUEST['text']);
$results[] = [
'title' => L10n::t("Raw HTML input"),
'content' => htmlspecialchars($html)
];
$diaspora = BBCode::toMarkdown($text); $results[] = [
$o .= '<h2>' . L10n::t('BBCode::toMarkdown: ') . '</h2>' . EOL . EOL; 'title' => L10n::t('HTML Input'),
$o .= visible_lf($diaspora) . EOL . EOL; 'content' => $html
];
$html = Markdown::convert($diaspora); $bbcode = Text\HTML::toBBCode($html);
$o .= '<h2>' . L10n::t('BBCode::toMarkdown => Markdown::convert: ') . '</h2>' . EOL . EOL; $results[] = [
$o .= $html . EOL . EOL; 'title' => L10n::t('HTML::toBBCode'),
'content' => visible_lf($bbcode)
];
$bbcode = Markdown::toBBCode($diaspora); $text = Text\HTML::toPlaintext($html);
$o .= '<h2>' . L10n::t('BBCode::toMarkdown => Markdown::toBBCode: ') . '</h2>' . EOL . EOL; $results[] = [
$o .= visible_lf($bbcode) . EOL . EOL; 'title' => L10n::t('HTML::toPlaintext'),
'content' => '<pre>' . $text . '</pre>'
$bbcode = html2bbcode($html); ];
$o .= '<h2>' . L10n::t('bbcode => html2bbcode: ') . '</h2>' . EOL . EOL; }
$o .= visible_lf($bbcode) . EOL . EOL;
} }
if (x($_REQUEST, 'd2bbtext')) { $tpl = get_markup_template('babel.tpl');
$d2bbtext = trim($_REQUEST['d2bbtext']); $o = replace_macros($tpl, [
$o .= '<h2>' . L10n::t("Source input \x28Diaspora format\x29: ") . '</h2>' . EOL . EOL; '$text' => ['text', L10n::t('Source text'), defaults($_REQUEST, 'text', ''), ''],
$o .= '<pre>' . $d2bbtext . '</pre>' . EOL . EOL; '$type_bbcode' => ['type', L10n::t('BBCode'), 'bbcode', '', defaults($_REQUEST, 'type', 'bbcode') == 'bbcode'],
'$type_markdown' => ['type', L10n::t('Markdown'), 'markdown', '', defaults($_REQUEST, 'type', 'bbcode') == 'markdown'],
$bb = Markdown::toBBCode($d2bbtext); '$type_html' => ['type', L10n::t('HTML'), 'html', '', defaults($_REQUEST, 'type', 'bbcode') == 'html'],
$o .= '<h2>' . L10n::t('diaspora2bb: ') . '</h2>' . EOL . EOL; '$results' => $results
$o .= '<pre>' . $bb . '</pre>' . EOL . EOL; ]);
}
return $o; return $o;
} }

View file

@ -9,19 +9,19 @@
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature; use Friendica\Content\Feature;
use Friendica\Content\Nav; use Friendica\Content\Nav;
use Friendica\Content\Widget;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Event;
use Friendica\Model\Group; use Friendica\Model\Group;
use Friendica\Model\Profile; use Friendica\Model\Profile;
use Friendica\Protocol\DFRN; use Friendica\Protocol\DFRN;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\Temporal; use Friendica\Util\Temporal;
require_once 'include/event.php';
function cal_init(App $a) function cal_init(App $a)
{ {
if ($a->argc > 1) { if ($a->argc > 1) {
@ -64,7 +64,7 @@ function cal_init(App $a)
'$pdesc' => (($profile['pdesc'] != "") ? $profile['pdesc'] : ""), '$pdesc' => (($profile['pdesc'] != "") ? $profile['pdesc'] : ""),
]); ]);
$cal_widget = widget_events(); $cal_widget = Widget\CalendarExport::getHTML();
if (!x($a->page, 'aside')) { if (!x($a->page, 'aside')) {
$a->page['aside'] = ''; $a->page['aside'] = '';
@ -82,7 +82,7 @@ function cal_content(App $a)
Nav::setSelected('events'); Nav::setSelected('events');
// get the translation strings for the callendar // get the translation strings for the callendar
$i18n = get_event_strings(); $i18n = Event::getStrings();
$htpl = get_markup_template('event_head.tpl'); $htpl = get_markup_template('event_head.tpl');
$a->page['htmlhead'] .= replace_macros($htpl, [ $a->page['htmlhead'] .= replace_macros($htpl, [
@ -212,25 +212,25 @@ function cal_content(App $a)
// put the event parametes in an array so we can better transmit them // put the event parametes in an array so we can better transmit them
$event_params = [ $event_params = [
'event_id' => (x($_GET, 'id') ? $_GET["id"] : 0), 'event_id' => intval(defaults($_GET, 'id', 0)),
'start' => $start, 'start' => $start,
'finish' => $finish, 'finish' => $finish,
'adjust_start' => $adjust_start, 'adjust_start' => $adjust_start,
'adjust_finish' => $adjust_finish, 'adjust_finish' => $adjust_finish,
'ignored' => $ignored, 'ignore' => $ignored,
]; ];
// get events by id or by date // get events by id or by date
if (x($_GET, 'id')) { if ($event_params['event_id']) {
$r = event_by_id($owner_uid, $event_params, $sql_extra); $r = Event::getListById($owner_uid, $event_params['event-id'], $sql_extra);
} else { } else {
$r = events_by_date($owner_uid, $event_params, $sql_extra); $r = Event::getListByDate($owner_uid, $event_params, $sql_extra);
} }
$links = []; $links = [];
if (DBM::is_result($r)) { if (DBM::is_result($r)) {
$r = sort_by_date($r); $r = Event::sortByDate($r);
foreach ($r as $rr) { foreach ($r as $rr) {
$j = $rr['adjust'] ? DateTimeFormat::local($rr['start'], 'j') : DateTimeFormat::utc($rr['start'], 'j'); $j = $rr['adjust'] ? DateTimeFormat::local($rr['start'], 'j') : DateTimeFormat::utc($rr['start'], 'j');
if (!x($links, $j)) { if (!x($links, $j)) {
@ -240,7 +240,7 @@ function cal_content(App $a)
} }
// transform the event in a usable array // transform the event in a usable array
$events = process_events($r); $events = Event::prepareListForTemplate($r);
if ($a->argv[2] === 'json') { if ($a->argv[2] === 'json') {
echo json_encode($events); echo json_encode($events);
@ -306,7 +306,7 @@ function cal_content(App $a)
} }
// Get the export data by uid // Get the export data by uid
$evexport = event_export($owner_uid, $format); $evexport = Event::exportListByUserId($owner_uid, $format);
if (!$evexport["success"]) { if (!$evexport["success"]) {
if ($evexport["content"]) { if ($evexport["content"]) {

View file

@ -45,6 +45,14 @@ function contacts_init(App $a)
} }
if (DBM::is_result($contact)) { if (DBM::is_result($contact)) {
if ($contact['self']) {
if (($a->argc == 3) && intval($a->argv[1]) && ($a->argv[2] == "posts")) {
goaway('profile/' . $contact['nick']);
} else {
goaway('profile/' . $contact['nick'] . '?tab=profile');
}
}
$a->data['contact'] = $contact; $a->data['contact'] = $contact;
if (($a->data['contact']['network'] != "") && ($a->data['contact']['network'] != NETWORK_DFRN)) { if (($a->data['contact']['network'] != "") && ($a->data['contact']['network'] != NETWORK_DFRN)) {
@ -579,9 +587,10 @@ function contacts_content(App $a)
$profile_select = ContactSelector::profileAssign($contact['profile-id'], (($contact['network'] !== NETWORK_DFRN) ? true : false)); $profile_select = ContactSelector::profileAssign($contact['profile-id'], (($contact['network'] !== NETWORK_DFRN) ? true : false));
} }
/// @todo Only show the following link with DFRN when the remote version supports it
$follow = ''; $follow = '';
$follow_text = ''; $follow_text = '';
if (in_array($contact['network'], [NETWORK_DIASPORA, NETWORK_OSTATUS])) { if (in_array($contact['network'], [NETWORK_DIASPORA, NETWORK_OSTATUS, NETWORK_DFRN])) {
if ($contact['rel'] == CONTACT_IS_FOLLOWER) { if ($contact['rel'] == CONTACT_IS_FOLLOWER) {
$follow = System::baseUrl(true) . "/follow?url=" . urlencode($contact["url"]); $follow = System::baseUrl(true) . "/follow?url=" . urlencode($contact["url"]);
$follow_text = L10n::t("Connect/Follow"); $follow_text = L10n::t("Connect/Follow");
@ -939,6 +948,13 @@ function _contact_detail_for_template($rr)
$sparkle = ''; $sparkle = '';
} }
if ($rr['self']) {
$dir_icon = 'images/larrow.gif';
$alt_text = L10n::t('This is you');
$url = $rr['url'];
$sparkle = '';
}
return [ return [
'img_hover' => L10n::t('Visit %s\'s profile [%s]', $rr['name'], $rr['url']), 'img_hover' => L10n::t('Visit %s\'s profile [%s]', $rr['name'], $rr['url']),
'edit_hover' => L10n::t('Edit contact'), 'edit_hover' => L10n::t('Edit contact'),

View file

@ -6,6 +6,7 @@ use Friendica\App;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Model\User;
require_once 'mod/settings.php'; require_once 'mod/settings.php';
@ -28,6 +29,21 @@ function delegate_post(App $a)
check_form_security_token_redirectOnErr('/delegate', 'delegate'); check_form_security_token_redirectOnErr('/delegate', 'delegate');
$parent_uid = defaults($_POST, 'parent_user', 0); $parent_uid = defaults($_POST, 'parent_user', 0);
$parent_password = defaults($_POST, 'parent_password', '');
if ($parent_uid != 0) {
$user = dba::selectFirst('user', ['nickname'], ['uid' => $parent_uid]);
if (!DBM::is_result($user)) {
notice(L10n::t('Parent user not found.') . EOL);
return;
}
$success = User::authenticate($user['nickname'], trim($parent_password));
if (!$success) {
notice(L10n::t('Permission denied.') . EOL);
return;
}
}
dba::update('user', ['parent-uid' => $parent_uid], ['uid' => local_user()]); dba::update('user', ['parent-uid' => $parent_uid], ['uid' => local_user()]);
} }
@ -70,16 +86,6 @@ function delegate_content(App $a)
goaway(System::baseUrl() . '/delegate'); goaway(System::baseUrl() . '/delegate');
} }
// These people can manage this account/page with full privilege
$full_managers = [];
$r = q("SELECT * FROM `user` WHERE `email` = '%s' AND `password` = '%s' ",
dbesc($a->user['email']),
dbesc($a->user['password'])
);
if (DBM::is_result($r)) {
$full_managers = $r;
}
// find everybody that currently has delegated management to this account/page // find everybody that currently has delegated management to this account/page
$delegates = []; $delegates = [];
$r = q("SELECT * FROM `user` WHERE `uid` IN (SELECT `uid` FROM `manage` WHERE `mid` = %d)", $r = q("SELECT * FROM `user` WHERE `uid` IN (SELECT `uid` FROM `manage` WHERE `mid` = %d)",
@ -90,10 +96,6 @@ function delegate_content(App $a)
} }
$uids = []; $uids = [];
foreach ($full_managers as $rr) {
$uids[] = $rr['uid'];
}
foreach ($delegates as $rr) { foreach ($delegates as $rr) {
$uids[] = $rr['uid']; $uids[] = $rr['uid'];
} }
@ -153,18 +155,21 @@ function delegate_content(App $a)
} }
} }
if (!is_null($parent_user)) {
$parent_password = ['parent_password', L10n::t('Parent Password:'), '', L10n::t('Please enter the password of the parent account to legitimize your request.')];
}
$o = replace_macros(get_markup_template('delegate.tpl'), [ $o = replace_macros(get_markup_template('delegate.tpl'), [
'$form_security_token' => get_form_security_token('delegate'), '$form_security_token' => get_form_security_token('delegate'),
'$parent_header' => L10n::t('Parent User'), '$parent_header' => L10n::t('Parent User'),
'$parent_user' => $parent_user, '$parent_user' => $parent_user,
'$parent_password' => $parent_password,
'$parent_desc' => L10n::t('Parent users have total control about this account, including the account settings. Please double check whom you give this access.'), '$parent_desc' => L10n::t('Parent users have total control about this account, including the account settings. Please double check whom you give this access.'),
'$submit' => L10n::t('Save Settings'), '$submit' => L10n::t('Save Settings'),
'$header' => L10n::t('Delegate Page Management'), '$header' => L10n::t('Delegate Page Management'),
'$delegates_header' => L10n::t('Delegates'), '$delegates_header' => L10n::t('Delegates'),
'$base' => System::baseUrl(), '$base' => System::baseUrl(),
'$desc' => L10n::t('Delegates are able to manage all aspects of this account/page except for basic account settings. Please do not delegate your personal account to anybody that you do not trust completely.'), '$desc' => L10n::t('Delegates are able to manage all aspects of this account/page except for basic account settings. Please do not delegate your personal account to anybody that you do not trust completely.'),
'$head_managers' => L10n::t('Existing Page Managers'),
'$managers' => $full_managers,
'$head_delegates' => L10n::t('Existing Page Delegates'), '$head_delegates' => L10n::t('Existing Page Delegates'),
'$delegates' => $delegates, '$delegates' => $delegates,
'$head_potentials' => L10n::t('Potential Delegates'), '$head_potentials' => L10n::t('Potential Delegates'),

View file

@ -12,12 +12,60 @@ use Friendica\Core\System;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Protocol\DFRN; use Friendica\Protocol\DFRN;
use Friendica\Protocol\Diaspora;
require_once 'include/items.php'; require_once 'include/items.php';
require_once 'include/event.php';
function dfrn_notify_post(App $a) { function dfrn_notify_post(App $a) {
logger(__function__, LOGGER_TRACE); logger(__function__, LOGGER_TRACE);
$postdata = file_get_contents('php://input');
if (empty($_POST) || !empty($postdata)) {
$data = json_decode($postdata);
if (is_object($data)) {
$nick = defaults($a->argv, 1, '');
$user = dba::selectFirst('user', [], ['nickname' => $nick, 'account_expired' => false, 'account_removed' => false]);
if (!DBM::is_result($user)) {
System::httpExit(500);
}
$msg = Diaspora::decodeRaw($user, $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';
salmon_post($a, $postdata);
}
}
$dfrn_id = ((x($_POST,'dfrn_id')) ? notags(trim($_POST['dfrn_id'])) : ''); $dfrn_id = ((x($_POST,'dfrn_id')) ? notags(trim($_POST['dfrn_id'])) : '');
$dfrn_version = ((x($_POST,'dfrn_version')) ? (float) $_POST['dfrn_version'] : 2.0); $dfrn_version = ((x($_POST,'dfrn_version')) ? (float) $_POST['dfrn_version'] : 2.0);
$challenge = ((x($_POST,'challenge')) ? notags(trim($_POST['challenge'])) : ''); $challenge = ((x($_POST,'challenge')) ? notags(trim($_POST['challenge'])) : '');

View file

@ -12,12 +12,12 @@ use Friendica\Database\DBM;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Profile; use Friendica\Model\Profile;
function directory_init(App $a) { function directory_init(App $a)
{
$a->set_pager_itemspage(60); $a->set_pager_itemspage(60);
if(local_user()) { if (local_user()) {
$a->page['aside'] .= Widget::findPeople(); $a->page['aside'] .= Widget::findPeople();
$a->page['aside'] .= Widget::follow(); $a->page['aside'] .= Widget::follow();
} else { } else {
unset($_SESSION['theme']); unset($_SESSION['theme']);
@ -25,16 +25,20 @@ function directory_init(App $a) {
} }
} }
function directory_post(App $a) { function directory_post(App $a)
if(x($_POST,'search')) {
if (x($_POST, 'search')) {
$a->data['search'] = $_POST['search']; $a->data['search'] = $_POST['search'];
}
} }
function directory_content(App $a) { function directory_content(App $a)
{
require_once("mod/proxy.php"); require_once("mod/proxy.php");
if((Config::get('system','block_public')) && (! local_user()) && (! remote_user()) || if ((Config::get('system', 'block_public') && !local_user() && !remote_user())
(Config::get('system','block_local_dir')) && (! local_user()) && (! remote_user())) { || (Config::get('system', 'block_local_dir') && !local_user() && !remote_user())
) {
notice(L10n::t('Public access denied.') . EOL); notice(L10n::t('Public access denied.') . EOL);
return; return;
} }
@ -42,18 +46,19 @@ function directory_content(App $a) {
$o = ''; $o = '';
Nav::setSelected('directory'); Nav::setSelected('directory');
if(x($a->data,'search')) if (x($a->data, 'search')) {
$search = notags(trim($a->data['search'])); $search = notags(trim($a->data['search']));
else } else {
$search = ((x($_GET,'search')) ? notags(trim(rawurldecode($_GET['search']))) : ''); $search = ((x($_GET, 'search')) ? notags(trim(rawurldecode($_GET['search']))) : '');
$gdirpath = '';
$dirurl = Config::get('system','directory');
if(strlen($dirurl)) {
$gdirpath = Profile::zrl($dirurl,true);
} }
if($search) { $gdirpath = '';
$dirurl = Config::get('system', 'directory');
if (strlen($dirurl)) {
$gdirpath = Profile::zrl($dirurl, true);
}
if ($search) {
$search = dbesc($search); $search = dbesc($search);
$sql_extra = " AND ((`profile`.`name` LIKE '%$search%') OR $sql_extra = " AND ((`profile`.`name` LIKE '%$search%') OR
@ -73,35 +78,34 @@ function directory_content(App $a) {
(`profile`.`prv_keywords` LIKE '%$search%'))"; (`profile`.`prv_keywords` LIKE '%$search%'))";
} }
$publish = ((Config::get('system','publish_all')) ? '' : " AND `publish` = 1 " ); $publish = (Config::get('system', 'publish_all') ? '' : " AND `publish` = 1 " );
$r = q("SELECT COUNT(*) AS `total` FROM `profile` $cnt = dba::fetch_first("SELECT COUNT(*) AS `total` FROM `profile`
LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid` LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid`
WHERE `is-default` = 1 $publish AND `user`.`blocked` = 0 $sql_extra "); WHERE `is-default` $publish AND NOT `user`.`blocked` $sql_extra");
if (DBM::is_result($r)) if (DBM::is_result($cnt)) {
$a->set_pager_total($r[0]['total']); $a->set_pager_total($cnt['total']);
}
$order = " ORDER BY `name` ASC "; $order = " ORDER BY `name` ASC ";
$limit = intval($a->pager['start']).",".intval($a->pager['itemspage']); $limit = intval($a->pager['start'])."," . intval($a->pager['itemspage']);
$r = q("SELECT `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`, `user`.`timezone` , `user`.`page-flags`, $r = dba::p("SELECT `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`, `user`.`timezone` , `user`.`page-flags`,
`contact`.`addr`, `contact`.`url` AS profile_url FROM `profile` `contact`.`addr`, `contact`.`url` AS profile_url FROM `profile`
LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid` LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid`
LEFT JOIN `contact` ON `contact`.`uid` = `user`.`uid` LEFT JOIN `contact` ON `contact`.`uid` = `user`.`uid`
WHERE `is-default` $publish AND `user`.`blocked` = 0 AND `contact`.`self` $sql_extra $order LIMIT ".$limit); WHERE `is-default` $publish AND `user`.`blocked` = 0 AND `contact`.`self` $sql_extra $order LIMIT ".$limit
);
if (DBM::is_result($r)) { if (DBM::is_result($r)) {
if (in_array('small', $a->argv)) { if (in_array('small', $a->argv)) {
$photo = 'thumb'; $photo = 'thumb';
} } else {
else {
$photo = 'photo'; $photo = 'photo';
} }
foreach ($r as $rr) { while ($rr = dba::fetch($r)) {
$itemurl= ''; $itemurl= '';
$itemurl = (($rr['addr'] != "") ? $rr['addr'] : $rr['profile_url']); $itemurl = (($rr['addr'] != "") ? $rr['addr'] : $rr['profile_url']);
@ -111,16 +115,19 @@ function directory_content(App $a) {
$pdesc = (($rr['pdesc']) ? $rr['pdesc'] . '<br />' : ''); $pdesc = (($rr['pdesc']) ? $rr['pdesc'] . '<br />' : '');
$details = ''; $details = '';
if(strlen($rr['locality'])) if (strlen($rr['locality'])) {
$details .= $rr['locality']; $details .= $rr['locality'];
if(strlen($rr['region'])) { }
if(strlen($rr['locality'])) if (strlen($rr['region'])) {
if (strlen($rr['locality'])) {
$details .= ', '; $details .= ', ';
}
$details .= $rr['region']; $details .= $rr['region'];
} }
if(strlen($rr['country-name'])) { if (strlen($rr['country-name'])) {
if(strlen($details)) if (strlen($details)) {
$details .= ', '; $details .= ', ';
}
$details .= $rr['country-name']; $details .= $rr['country-name'];
} }
// if(strlen($rr['dob'])) { // if(strlen($rr['dob'])) {
@ -132,20 +139,19 @@ function directory_content(App $a) {
$profile = $rr; $profile = $rr;
if((x($profile,'address') == 1) if ((x($profile, 'address') == 1)
|| (x($profile,'locality') == 1) || (x($profile, 'locality') == 1)
|| (x($profile,'region') == 1) || (x($profile, 'region') == 1)
|| (x($profile,'postal-code') == 1) || (x($profile, 'postal-code') == 1)
|| (x($profile,'country-name') == 1)) || (x($profile, 'country-name') == 1)
) {
$location = L10n::t('Location:'); $location = L10n::t('Location:');
}
$gender = ((x($profile,'gender') == 1) ? L10n::t('Gender:') : False); $gender = ((x($profile, 'gender') == 1) ? L10n::t('Gender:') : false);
$marital = ((x($profile, 'marital') == 1) ? L10n::t('Status:') : false);
$marital = ((x($profile,'marital') == 1) ? L10n::t('Status:') : False); $homepage = ((x($profile, 'homepage') == 1) ? L10n::t('Homepage:') : false);
$about = ((x($profile, 'about') == 1) ? L10n::t('About:') : false);
$homepage = ((x($profile,'homepage') == 1) ? L10n::t('Homepage:') : False);
$about = ((x($profile,'about') == 1) ? L10n::t('About:') : False);
$location_e = $location; $location_e = $location;
@ -187,6 +193,7 @@ function directory_content(App $a) {
$entries[] = $arr['entry']; $entries[] = $arr['entry'];
} }
dba::close($r);
$tpl = get_markup_template('directory_header.tpl'); $tpl = get_markup_template('directory_header.tpl');

View file

@ -15,6 +15,7 @@ use Friendica\Model\Profile;
use Friendica\Network\Probe; use Friendica\Network\Probe;
use Friendica\Protocol\PortableContact; use Friendica\Protocol\PortableContact;
use Friendica\Util\Network; use Friendica\Util\Network;
use Friendica\Database\DBM;
require_once 'mod/contacts.php'; require_once 'mod/contacts.php';
@ -113,32 +114,22 @@ function dirfind_content(App $a, $prefix = "") {
/// @TODO These 2 SELECTs are not checked on validity with DBM::is_result() /// @TODO These 2 SELECTs are not checked on validity with DBM::is_result()
$count = q("SELECT count(*) AS `total` FROM `gcontact` $count = q("SELECT count(*) AS `total` FROM `gcontact`
LEFT JOIN `contact` ON `contact`.`nurl` = `gcontact`.`nurl` WHERE NOT `hide` AND `network` IN ('%s', '%s', '%s') AND
AND `contact`.`network` = `gcontact`.`network` ((`last_contact` >= `last_failure`) OR (`updated` >= `last_failure`)) AND
AND `contact`.`uid` = %d AND NOT `contact`.`blocked` (`url` LIKE '%s' OR `name` LIKE '%s' OR `location` LIKE '%s' OR
AND NOT `contact`.`pending` AND `contact`.`rel` IN ('%s', '%s') `addr` LIKE '%s' OR `about` LIKE '%s' OR `keywords` LIKE '%s') $extra_sql",
WHERE (`contact`.`id` > 0 OR (NOT `gcontact`.`hide` AND `gcontact`.`network` IN ('%s', '%s', '%s') AND
((`gcontact`.`last_contact` >= `gcontact`.`last_failure`) OR (`gcontact`.`updated` >= `gcontact`.`last_failure`)))) AND
(`gcontact`.`url` LIKE '%s' OR `gcontact`.`name` LIKE '%s' OR `gcontact`.`location` LIKE '%s' OR
`gcontact`.`addr` LIKE '%s' OR `gcontact`.`about` LIKE '%s' OR `gcontact`.`keywords` LIKE '%s') $extra_sql",
intval(local_user()), dbesc(CONTACT_IS_SHARING), dbesc(CONTACT_IS_FRIEND),
dbesc(NETWORK_DFRN), dbesc($ostatus), dbesc($diaspora), dbesc(NETWORK_DFRN), dbesc($ostatus), dbesc($diaspora),
dbesc(escape_tags($search2)), dbesc(escape_tags($search2)), dbesc(escape_tags($search2)), dbesc(escape_tags($search2)), dbesc(escape_tags($search2)), dbesc(escape_tags($search2)),
dbesc(escape_tags($search2)), dbesc(escape_tags($search2)), dbesc(escape_tags($search2))); dbesc(escape_tags($search2)), dbesc(escape_tags($search2)), dbesc(escape_tags($search2)));
$results = q("SELECT `contact`.`id` AS `cid`, `gcontact`.`url`, `gcontact`.`name`, `gcontact`.`photo`, `gcontact`.`network`, `gcontact`.`keywords`, `gcontact`.`addr` $results = q("SELECT `nurl`
FROM `gcontact` FROM `gcontact`
LEFT JOIN `contact` ON `contact`.`nurl` = `gcontact`.`nurl` WHERE NOT `hide` AND `network` IN ('%s', '%s', '%s') AND
AND `contact`.`network` = `gcontact`.`network` ((`last_contact` >= `last_failure`) OR (`updated` >= `last_failure`)) AND
AND `contact`.`uid` = %d AND NOT `contact`.`blocked` (`url` LIKE '%s' OR `name` LIKE '%s' OR `location` LIKE '%s' OR
AND NOT `contact`.`pending` AND `contact`.`rel` IN ('%s', '%s') `addr` LIKE '%s' OR `about` LIKE '%s' OR `keywords` LIKE '%s') $extra_sql
WHERE (`contact`.`id` > 0 OR (NOT `gcontact`.`hide` AND `gcontact`.`network` IN ('%s', '%s', '%s') AND GROUP BY `nurl`
((`gcontact`.`last_contact` >= `gcontact`.`last_failure`) OR (`gcontact`.`updated` >= `gcontact`.`last_failure`)))) AND ORDER BY `updated` DESC LIMIT %d, %d",
(`gcontact`.`url` LIKE '%s' OR `gcontact`.`name` LIKE '%s' OR `gcontact`.`location` LIKE '%s' OR
`gcontact`.`addr` LIKE '%s' OR `gcontact`.`about` LIKE '%s' OR `gcontact`.`keywords` LIKE '%s') $extra_sql
GROUP BY `gcontact`.`nurl`
ORDER BY `gcontact`.`updated` DESC LIMIT %d, %d",
intval(local_user()), dbesc(CONTACT_IS_SHARING), dbesc(CONTACT_IS_FRIEND),
dbesc(NETWORK_DFRN), dbesc($ostatus), dbesc($diaspora), dbesc(NETWORK_DFRN), dbesc($ostatus), dbesc($diaspora),
dbesc(escape_tags($search2)), dbesc(escape_tags($search2)), dbesc(escape_tags($search2)), dbesc(escape_tags($search2)), dbesc(escape_tags($search2)), dbesc(escape_tags($search2)),
dbesc(escape_tags($search2)), dbesc(escape_tags($search2)), dbesc(escape_tags($search2)), dbesc(escape_tags($search2)), dbesc(escape_tags($search2)), dbesc(escape_tags($search2)),
@ -148,14 +139,21 @@ function dirfind_content(App $a, $prefix = "") {
$j->items_page = $perpage; $j->items_page = $perpage;
$j->page = $a->pager['page']; $j->page = $a->pager['page'];
foreach ($results AS $result) { foreach ($results AS $result) {
if (PortableContact::alternateOStatusUrl($result["url"])) { if (PortableContact::alternateOStatusUrl($result["nurl"])) {
continue; continue;
} }
$result = Contact::getDetailsByURL($result["url"], local_user(), $result); $urlparts = parse_url($result["nurl"]);
// Ignore results that look strange.
// For historic reasons the gcontact table does contain some garbage.
if (!empty($urlparts['query']) || !empty($urlparts['fragment'])) {
continue;
}
$result = Contact::getDetailsByURL($result["nurl"], local_user());
if ($result["name"] == "") { if ($result["name"] == "") {
$urlparts = parse_url($result["url"]);
$result["name"] = end(explode("/", $urlparts["path"])); $result["name"] = end(explode("/", $urlparts["path"]));
} }
@ -204,11 +202,10 @@ function dirfind_content(App $a, $prefix = "") {
if ($jj->cid > 0) { if ($jj->cid > 0) {
$connlnk = ""; $connlnk = "";
$conntxt = ""; $conntxt = "";
$contact = q("SELECT * FROM `contact` WHERE `id` = %d", $contact = dba::selectFirst('contact', [], ['id' => $jj->cid]);
intval($jj->cid)); if (DBM::is_result($contact)) {
if ($contact) { $photo_menu = Contact::photoMenu($contact);
$photo_menu = Contact::photoMenu($contact[0]); $details = _contact_detail_for_template($contact);
$details = _contact_detail_for_template($contact[0]);
$alt_text = $details['alt_text']; $alt_text = $details['alt_text'];
} else { } else {
$photo_menu = []; $photo_menu = [];
@ -226,7 +223,7 @@ function dirfind_content(App $a, $prefix = "") {
$entry = [ $entry = [
'alt_text' => $alt_text, 'alt_text' => $alt_text,
'url' => Profile::zrl($jj->url), 'url' => Profile::magicLink($jj->url),
'itemurl' => $itemurl, 'itemurl' => $itemurl,
'name' => htmlentities($jj->name), 'name' => htmlentities($jj->name),
'thumb' => proxy_url($jj->photo, false, PROXY_SIZE_THUMB), 'thumb' => proxy_url($jj->photo, false, PROXY_SIZE_THUMB),

View file

@ -5,6 +5,7 @@
use Friendica\App; use Friendica\App;
use Friendica\Content\Text\BBCode; use Friendica\Content\Text\BBCode;
use Friendica\Content\Text\HTML;
use Friendica\Core\ACL; use Friendica\Core\ACL;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\L10n; use Friendica\Core\L10n;
@ -211,7 +212,11 @@ function display_content(App $a, $update = false, $update_uid = 0) {
if ($update) { if ($update) {
$item_id = $_REQUEST['item_id']; $item_id = $_REQUEST['item_id'];
$item = dba::selectFirst('item', ['uid', 'parent'], ['id' => $item_id]); $item = dba::selectFirst('item', ['uid', 'parent'], ['id' => $item_id]);
if ($item['uid'] != 0) {
$a->profile = ['uid' => intval($item['uid']), 'profile_uid' => intval($item['uid'])]; $a->profile = ['uid' => intval($item['uid']), 'profile_uid' => intval($item['uid'])];
} else {
$a->profile = ['uid' => intval($update_uid), 'profile_uid' => intval($update_uid)];
}
$item_parent = $item['parent']; $item_parent = $item['parent'];
} else { } else {
$item_id = (($a->argc > 2) ? $a->argv[2] : 0); $item_id = (($a->argc > 2) ? $a->argv[2] : 0);
@ -367,10 +372,8 @@ function display_content(App $a, $update = false, $update_uid = 0) {
$o .= conversation($a, $items, 'display', $update_uid); $o .= conversation($a, $items, 'display', $update_uid);
// Preparing the meta header // Preparing the meta header
require_once 'include/html2plain.php'; $description = trim(HTML::toPlaintext(BBCode::convert($s[0]["body"], false), 0, true));
$title = trim(HTML::toPlaintext(BBCode::convert($s[0]["title"], false), 0, true));
$description = trim(html2plain(BBCode::convert($s[0]["body"], false), 0, true));
$title = trim(html2plain(BBCode::convert($s[0]["title"], false), 0, true));
$author_name = $s[0]["author-name"]; $author_name = $s[0]["author-name"];
$image = $a->remove_baseurl($s[0]["author-thumb"]); $image = $a->remove_baseurl($s[0]["author-thumb"]);

View file

@ -6,17 +6,18 @@
use Friendica\App; use Friendica\App;
use Friendica\Content\Nav; use Friendica\Content\Nav;
use Friendica\Content\Widget\CalendarExport;
use Friendica\Core\ACL; use Friendica\Core\ACL;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Model\Event;
use Friendica\Model\Item; use Friendica\Model\Item;
use Friendica\Model\Profile; use Friendica\Model\Profile;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\Temporal; use Friendica\Util\Temporal;
require_once 'include/event.php';
require_once 'include/items.php'; require_once 'include/items.php';
function events_init(App $a) { function events_init(App $a) {
@ -24,21 +25,21 @@ function events_init(App $a) {
return; return;
} }
if ($a->argc > 1) {
// If it's a json request abort here because we don't // If it's a json request abort here because we don't
// need the widget data // need the widget data
if ($a->argv[1] === 'json') { if ($a->argc > 1 && $a->argv[1] === 'json') {
return; return;
} }
$cal_widget = widget_events(); if (empty($a->page['aside'])) {
if (! x($a->page,'aside')) {
$a->page['aside'] = ''; $a->page['aside'] = '';
} }
$a->data['user'] = $_SESSION['user'];
$cal_widget = CalendarExport::getHTML();
$a->page['aside'] .= $cal_widget; $a->page['aside'] .= $cal_widget;
}
return; return;
} }
@ -155,7 +156,6 @@ function events_post(App $a) {
$datarray = []; $datarray = [];
$datarray['guid'] = get_guid(32);
$datarray['start'] = $start; $datarray['start'] = $start;
$datarray['finish'] = $finish; $datarray['finish'] = $finish;
$datarray['summary'] = $summary; $datarray['summary'] = $summary;
@ -170,18 +170,16 @@ function events_post(App $a) {
$datarray['allow_gid'] = $str_group_allow; $datarray['allow_gid'] = $str_group_allow;
$datarray['deny_cid'] = $str_contact_deny; $datarray['deny_cid'] = $str_contact_deny;
$datarray['deny_gid'] = $str_group_deny; $datarray['deny_gid'] = $str_group_deny;
$datarray['private'] = (($private_event) ? 1 : 0); $datarray['private'] = $private_event;
$datarray['id'] = $event_id; $datarray['id'] = $event_id;
$datarray['created'] = $created;
$datarray['edited'] = $edited;
if (intval($_REQUEST['preview'])) { if (intval($_REQUEST['preview'])) {
$html = format_event_html($datarray); $html = Event::getHTML($datarray);
echo $html; echo $html;
killme(); killme();
} }
$item_id = event_store($datarray); $item_id = Event::store($datarray);
if (! $cid) { if (! $cid) {
Worker::add(PRIORITY_HIGH, "Notifier", "event", $item_id); Worker::add(PRIORITY_HIGH, "Notifier", "event", $item_id);
@ -222,7 +220,7 @@ function events_content(App $a) {
} }
// get the translation strings for the callendar // get the translation strings for the callendar
$i18n = get_event_strings(); $i18n = Event::getStrings();
$htpl = get_markup_template('event_head.tpl'); $htpl = get_markup_template('event_head.tpl');
$a->page['htmlhead'] .= replace_macros($htpl, [ $a->page['htmlhead'] .= replace_macros($htpl, [
@ -331,25 +329,25 @@ function events_content(App $a) {
// put the event parametes in an array so we can better transmit them // put the event parametes in an array so we can better transmit them
$event_params = [ $event_params = [
'event_id' => (x($_GET, 'id') ? $_GET['id'] : 0), 'event_id' => intval(defaults($_GET, 'id', 0)),
'start' => $start, 'start' => $start,
'finish' => $finish, 'finish' => $finish,
'adjust_start' => $adjust_start, 'adjust_start' => $adjust_start,
'adjust_finish' => $adjust_finish, 'adjust_finish' => $adjust_finish,
'ignored' => $ignored, 'ignore' => $ignored,
]; ];
// get events by id or by date // get events by id or by date
if (x($_GET, 'id')) { if ($event_params['event_id']) {
$r = event_by_id(local_user(), $event_params); $r = Event::getListById(local_user(), $event_params['event_id']);
} else { } else {
$r = events_by_date(local_user(), $event_params); $r = Event::getListByDate(local_user(), $event_params);
} }
$links = []; $links = [];
if (DBM::is_result($r)) { if (DBM::is_result($r)) {
$r = sort_by_date($r); $r = Event::sortByDate($r);
foreach ($r as $rr) { foreach ($r as $rr) {
$j = $rr['adjust'] ? DateTimeFormat::local($rr['start'], 'j') : DateTimeFormat::utc($rr['start'], 'j'); $j = $rr['adjust'] ? DateTimeFormat::local($rr['start'], 'j') : DateTimeFormat::utc($rr['start'], 'j');
if (! x($links,$j)) { if (! x($links,$j)) {
@ -362,8 +360,8 @@ function events_content(App $a) {
// transform the event in a usable array // transform the event in a usable array
if (DBM::is_result($r)) { if (DBM::is_result($r)) {
$r = sort_by_date($r); $r = Event::sortByDate($r);
$events = process_events($r); $events = Event::prepareListForTemplate($r);
} }
if ($a->argc > 1 && $a->argv[1] === 'json'){ if ($a->argc > 1 && $a->argv[1] === 'json'){
@ -543,8 +541,7 @@ function events_content(App $a) {
if ($mode === 'drop' && $event_id) { if ($mode === 'drop' && $event_id) {
$del = 0; $del = 0;
$params = ['event_id' => ($event_id)]; $ev = Event::getListById(local_user(), $event_id);
$ev = event_by_id(local_user(), $params);
// Delete only real events (no birthdays) // Delete only real events (no birthdays)
if (DBM::is_result($ev) && $ev[0]['type'] == 'event') { if (DBM::is_result($ev) && $ev[0]['type'] == 'event') {

53
mod/feedtest.php Normal file
View file

@ -0,0 +1,53 @@
<?php
/**
* @file_tag_list_to_file mod/feedtest.php
*/
use Friendica\App;
use Friendica\Core\L10n;
use Friendica\Model\Contact;
use Friendica\Protocol\Feed;
use Friendica\Util\Network;
require_once 'boot.php';
require_once 'include/dba.php';
require_once 'include/text.php';
function feedtest_content(App $a)
{
if (!local_user()) {
info(L10n::t('You must be logged in to use this module'));
return;
};
$result = [];
if (!empty($_REQUEST['url'])) {
$url = $_REQUEST['url'];
$importer = dba::selectFirst('user', [], ['uid' => local_user()]);
$contact_id = Contact::getIdForURL($url, local_user(), true);
$contact = dba::selectFirst('contact', [], ['id' => $contact_id]);
$ret = Network::curl($contact['poll']);
$xml = $ret['body'];
$dummy = null;
$import_result = Feed::import($xml, $importer, $contact, $dummy, true);
$result = [
'input' => text_highlight($xml, 'xml'),
'output' => var_export($import_result, true),
];
}
$tpl = get_markup_template('feedtest.tpl');
$o = replace_macros($tpl, [
'$url' => ['url', L10n::t('Source URL'), defaults($_REQUEST, 'url', ''), ''],
'$result' => $result
]);
return $o;
}

View file

@ -9,11 +9,12 @@ use Friendica\Core\System;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Profile; use Friendica\Model\Profile;
use Friendica\Network\Probe; use Friendica\Network\Probe;
use Friendica\Database\DBM;
function follow_post(App $a) { function follow_post(App $a)
{
if (!local_user()) { if (!local_user()) {
notice(L10n::t('Permission denied.') . EOL); notice(L10n::t('Permission denied.'));
goaway($_SESSION['return_url']); goaway($_SESSION['return_url']);
// NOTREACHED // NOTREACHED
} }
@ -28,7 +29,7 @@ function follow_post(App $a) {
// Makes the connection request for friendica contacts easier // Makes the connection request for friendica contacts easier
// This is just a precaution if maybe this page is called somewhere directly via POST // This is just a precaution if maybe this page is called somewhere directly via POST
$_SESSION["fastlane"] = $url; $_SESSION['fastlane'] = $url;
$result = Contact::createFromProbe($uid, $url, true); $result = Contact::createFromProbe($uid, $url, true);
@ -38,19 +39,19 @@ function follow_post(App $a) {
} }
goaway($return_url); goaway($return_url);
} elseif ($result['cid']) { } elseif ($result['cid']) {
goaway(System::baseUrl().'/contacts/'.$result['cid']); goaway(System::baseUrl() . '/contacts/' . $result['cid']);
} }
info(L10n::t('The contact could not be added.').EOL); info(L10n::t('The contact could not be added.'));
goaway($return_url); goaway($return_url);
// NOTREACHED // NOTREACHED
} }
function follow_content(App $a) { function follow_content(App $a)
{
if (!local_user()) { if (!local_user()) {
notice(L10n::t('Permission denied.') . EOL); notice(L10n::t('Permission denied.'));
goaway($_SESSION['return_url']); goaway($_SESSION['return_url']);
// NOTREACHED // NOTREACHED
} }
@ -60,121 +61,125 @@ function follow_content(App $a) {
$submit = L10n::t('Submit Request'); $submit = L10n::t('Submit Request');
// There is a current issue. It seems as if you can't start following a Friendica that is following you // Don't try to add a pending contact
// With Diaspora this works - but Friendica is special, it seems ... $r = q("SELECT `pending` FROM `contact` WHERE `uid` = %d AND ((`rel` != %d) OR (`network` = '%s')) AND
$r = q("SELECT `url` FROM `contact` WHERE `uid` = %d AND ((`rel` != %d) OR (`network` = '%s')) AND
(`nurl` = '%s' OR `alias` = '%s' OR `alias` = '%s') AND (`nurl` = '%s' OR `alias` = '%s' OR `alias` = '%s') AND
`network` != '%s' LIMIT 1", `network` != '%s' LIMIT 1",
intval(local_user()), dbesc(CONTACT_IS_FOLLOWER), dbesc(NETWORK_DFRN), dbesc(normalise_link($url)), intval(local_user()), dbesc(CONTACT_IS_FOLLOWER), dbesc(NETWORK_DFRN), dbesc(normalise_link($url)),
dbesc(normalise_link($url)), dbesc($url), dbesc(NETWORK_STATUSNET)); dbesc(normalise_link($url)), dbesc($url), dbesc(NETWORK_STATUSNET));
if ($r) { if ($r) {
notice(L10n::t('You already added this contact.').EOL); if ($r[0]['pending']) {
$submit = ""; notice(L10n::t('You already added this contact.'));
$submit = '';
//goaway($_SESSION['return_url']); //goaway($_SESSION['return_url']);
// NOTREACHED // NOTREACHED
} }
}
$ret = Probe::uri($url); $ret = Probe::uri($url);
if (($ret["network"] == NETWORK_DIASPORA) && !Config::get('system', 'diaspora_enabled')) { if (($ret['network'] == NETWORK_DIASPORA) && !Config::get('system', 'diaspora_enabled')) {
notice(L10n::t("Diaspora support isn't enabled. Contact can't be added.") . EOL); notice(L10n::t("Diaspora support isn't enabled. Contact can't be added."));
$submit = ""; $submit = '';
//goaway($_SESSION['return_url']); //goaway($_SESSION['return_url']);
// NOTREACHED // NOTREACHED
} }
if (($ret["network"] == NETWORK_OSTATUS) && Config::get('system', 'ostatus_disabled')) { if (($ret['network'] == NETWORK_OSTATUS) && Config::get('system', 'ostatus_disabled')) {
notice(L10n::t("OStatus support is disabled. Contact can't be added.") . EOL); notice(L10n::t("OStatus support is disabled. Contact can't be added."));
$submit = ""; $submit = '';
//goaway($_SESSION['return_url']); //goaway($_SESSION['return_url']);
// NOTREACHED // NOTREACHED
} }
if ($ret["network"] == NETWORK_PHANTOM) { if ($ret['network'] == NETWORK_PHANTOM) {
notice(L10n::t("The network type couldn't be detected. Contact can't be added.") . EOL); notice(L10n::t("The network type couldn't be detected. Contact can't be added."));
$submit = ""; $submit = '';
//goaway($_SESSION['return_url']); //goaway($_SESSION['return_url']);
// NOTREACHED // NOTREACHED
} }
if ($ret["network"] == NETWORK_MAIL) { if ($ret['network'] == NETWORK_MAIL) {
$ret["url"] = $ret["addr"]; $ret['url'] = $ret['addr'];
} }
if ($ret['network'] === NETWORK_DFRN) { if (($ret['network'] === NETWORK_DFRN) && !DBM::is_result($r)) {
$request = $ret["request"]; $request = $ret['request'];
$tpl = get_markup_template('dfrn_request.tpl'); $tpl = get_markup_template('dfrn_request.tpl');
} else { } else {
$request = System::baseUrl()."/follow"; $request = System::baseUrl() . '/follow';
$tpl = get_markup_template('auto_request.tpl'); $tpl = get_markup_template('auto_request.tpl');
} }
$r = q("SELECT `url` FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1", intval($uid)); $r = q("SELECT `url` FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1", intval($uid));
if (!$r) { if (!$r) {
notice(L10n::t('Permission denied.') . EOL); notice(L10n::t('Permission denied.'));
goaway($_SESSION['return_url']); goaway($_SESSION['return_url']);
// NOTREACHED // NOTREACHED
} }
$myaddr = $r[0]["url"]; $myaddr = $r[0]['url'];
$gcontact_id = 0; $gcontact_id = 0;
// Makes the connection request for friendica contacts easier // Makes the connection request for friendica contacts easier
$_SESSION["fastlane"] = $ret["url"]; $_SESSION['fastlane'] = $ret['url'];
$r = q("SELECT `id`, `location`, `about`, `keywords` FROM `gcontact` WHERE `nurl` = '%s'", $r = q("SELECT `id`, `location`, `about`, `keywords` FROM `gcontact` WHERE `nurl` = '%s'",
normalise_link($ret["url"])); normalise_link($ret['url']));
if (!$r) { if (!$r) {
$r = [["location" => "", "about" => "", "keywords" => ""]]; $r = [['location' => '', 'about' => '', 'keywords' => '']];
} else { } else {
$gcontact_id = $r[0]["id"]; $gcontact_id = $r[0]['id'];
} }
if ($ret['network'] === NETWORK_DIASPORA) { if ($ret['network'] === NETWORK_DIASPORA) {
$r[0]["location"] = ""; $r[0]['location'] = '';
$r[0]["about"] = ""; $r[0]['about'] = '';
} }
$header = L10n::t("Connect/Follow"); $header = L10n::t('Connect/Follow');
$o = replace_macros($tpl, [ $o = replace_macros($tpl, [
'$header' => htmlentities($header), '$header' => htmlentities($header),
//'$photo' => proxy_url($ret["photo"], false, PROXY_SIZE_SMALL), //'$photo' => proxy_url($ret['photo'], false, PROXY_SIZE_SMALL),
'$desc' => "", '$desc' => '',
'$pls_answer' => L10n::t('Please answer the following:'), '$pls_answer' => L10n::t('Please answer the following:'),
'$does_know_you' => ['knowyou', L10n::t('Does %s know you?', $ret["name"]), false, '', [L10n::t('No'), L10n::t('Yes')]], '$does_know_you' => ['knowyou', L10n::t('Does %s know you?', $ret['name']), false, '', [L10n::t('No'), L10n::t('Yes')]],
'$add_note' => L10n::t('Add a personal note:'), '$add_note' => L10n::t('Add a personal note:'),
'$page_desc' => "", '$page_desc' => '',
'$friendica' => "", '$friendica' => '',
'$statusnet' => "", '$statusnet' => '',
'$diaspora' => "", '$diaspora' => '',
'$diasnote' => "", '$diasnote' => '',
'$your_address' => L10n::t('Your Identity Address:'), '$your_address' => L10n::t('Your Identity Address:'),
'$invite_desc' => "", '$invite_desc' => '',
'$emailnet' => "", '$emailnet' => '',
'$submit' => $submit, '$submit' => $submit,
'$cancel' => L10n::t('Cancel'), '$cancel' => L10n::t('Cancel'),
'$nickname' => "", '$nickname' => '',
'$name' => $ret["name"], '$name' => $ret['name'],
'$url' => $ret["url"], '$url' => $ret['url'],
'$zrl' => Profile::zrl($ret["url"]), '$zrl' => Profile::zrl($ret['url']),
'$url_label' => L10n::t("Profile URL"), '$url_label' => L10n::t('Profile URL'),
'$myaddr' => $myaddr, '$myaddr' => $myaddr,
'$request' => $request, '$request' => $request,
/*'$location' => Friendica\Content\Text\BBCode::::convert($r[0]["location"]), /*'$location' => Friendica\Content\Text\BBCode::::convert($r[0]['location']),
'$location_label' => L10n::t("Location:"), '$location_label'=> L10n::t('Location:'),
'$about' => Friendica\Content\Text\BBCode::::convert($r[0]["about"], false, false), '$about' => Friendica\Content\Text\BBCode::::convert($r[0]['about'], false, false),
'$about_label' => L10n::t("About:"), */ '$about_label' => L10n::t('About:'),*/
'$keywords' => $r[0]["keywords"], '$keywords' => $r[0]['keywords'],
'$keywords_label' => L10n::t("Tags:") '$keywords_label'=> L10n::t('Tags:')
]); ]);
$a->page['aside'] = ""; $a->page['aside'] = '';
Profile::load($a, "", 0, Contact::getDetailsByURL($ret["url"]), false); $profiledata = Contact::getDetailsByURL($ret['url']);
if ($profiledata) {
Profile::load($a, '', 0, $profiledata, false);
}
if ($gcontact_id <> 0) { if ($gcontact_id <> 0) {
$o .= replace_macros(get_markup_template('section_title.tpl'), $o .= replace_macros(get_markup_template('section_title.tpl'),
@ -182,7 +187,7 @@ function follow_content(App $a) {
); );
// Show last public posts // Show last public posts
$o .= Contact::getPostsFromUrl($ret["url"]); $o .= Contact::getPostsFromUrl($ret['url']);
} }
return $o; return $o;

View file

@ -86,7 +86,7 @@ function friendica_content(App $a)
$o .= L10n::t('Bug reports and issues: please visit') . ' ' . '<a href="https://github.com/friendica/friendica/issues?state=open">'.L10n::t('the bugtracker at github').'</a>'; $o .= L10n::t('Bug reports and issues: please visit') . ' ' . '<a href="https://github.com/friendica/friendica/issues?state=open">'.L10n::t('the bugtracker at github').'</a>';
$o .= '</p>' . PHP_EOL; $o .= '</p>' . PHP_EOL;
$o .= '<p>'; $o .= '<p>';
$o .= L10n::t('Suggestions, praise, donations, etc. - please email "Info" at Friendica - dot com'); $o .= L10n::t('Suggestions, praise, etc. - please email "info" at "friendi - dot - ca');
$o .= '</p>' . PHP_EOL; $o .= '</p>' . PHP_EOL;
$visible_addons = []; $visible_addons = [];
@ -117,6 +117,11 @@ function friendica_content(App $a)
$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'))
{
$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 (count($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;

View file

@ -397,7 +397,8 @@ function check_funcs(&$checks) {
check_add($ck_funcs, L10n::t('PDO or MySQLi PHP module'), true, true, ""); check_add($ck_funcs, L10n::t('PDO or MySQLi PHP module'), true, true, "");
check_add($ck_funcs, L10n::t('mb_string PHP module'), true, true, ""); check_add($ck_funcs, L10n::t('mb_string PHP module'), true, true, "");
check_add($ck_funcs, L10n::t('XML PHP module'), true, true, ""); check_add($ck_funcs, L10n::t('XML PHP module'), true, true, "");
check_add($ck_funcs, L10n::t('iconv module'), true, true, ""); check_add($ck_funcs, L10n::t('iconv PHP module'), true, true, "");
check_add($ck_funcs, L10n::t('POSIX PHP module'), true, true, "");
if (function_exists('apache_get_modules')) { if (function_exists('apache_get_modules')) {
if (! in_array('mod_rewrite',apache_get_modules())) { if (! in_array('mod_rewrite',apache_get_modules())) {
@ -432,8 +433,12 @@ function check_funcs(&$checks) {
$ck_funcs[4]['help'] = L10n::t('Error: mb_string PHP module required but not installed.'); $ck_funcs[4]['help'] = L10n::t('Error: mb_string PHP module required but not installed.');
} }
if (! function_exists('iconv_strlen')) { if (! function_exists('iconv_strlen')) {
$ck_funcs[6]['status'] = false;
$ck_funcs[6]['help'] = L10n::t('Error: iconv PHP module required but not installed.');
}
if (! function_exists('posix_kill')) {
$ck_funcs[7]['status'] = false; $ck_funcs[7]['status'] = false;
$ck_funcs[7]['help'] = L10n::t('Error: iconv PHP module required but not installed.'); $ck_funcs[7]['help'] = L10n::t('Error: POSIX PHP module required but not installed.');
} }
$checks = array_merge($checks, $ck_funcs); $checks = array_merge($checks, $ck_funcs);
@ -442,8 +447,8 @@ function check_funcs(&$checks) {
try { try {
$xml = new DOMDocument(); $xml = new DOMDocument();
} catch (Exception $e) { } catch (Exception $e) {
$ck_funcs[6]['status'] = false; $ck_funcs[5]['status'] = false;
$ck_funcs[6]['help'] = L10n::t('Error, XML PHP module required but not installed.'); $ck_funcs[5]['help'] = L10n::t('Error, XML PHP module required but not installed.');
} }
} }
@ -540,7 +545,7 @@ function load_database_rem($v, $i) {
} }
function load_database() { function load_database() {
$errors = DBStructure::update(false, true); $errors = DBStructure::update(false, true, true);
return $errors; return $errors;
} }

View file

@ -35,28 +35,28 @@ function invite_post(App $a)
} }
$recips = ((x($_POST, 'recipients')) ? explode("\n", $_POST['recipients']) : []); $recipients = !empty($_POST['recipients']) ? explode("\n", $_POST['recipients']) : [];
$message = ((x($_POST, 'message')) ? notags(trim($_POST['message'])) : ''); $message = !empty($_POST['message']) ? notags(trim($_POST['message'])) : '';
$total = 0; $total = 0;
if (Config::get('system', 'invitation_only')) { if (Config::get('system', 'invitation_only')) {
$invonly = true; $invitation_only = true;
$x = PConfig::get(local_user(), 'system', 'invites_remaining'); $invites_remaining = PConfig::get(local_user(), 'system', 'invites_remaining');
if ((! $x) && (! is_site_admin())) { if ((! $invites_remaining) && (! is_site_admin())) {
return; return;
} }
} }
foreach ($recips as $recip) { foreach ($recipients as $recipient) {
$recip = trim($recip); $recipient = trim($recipient);
if (! valid_email($recip)) { if (! valid_email($recipient)) {
notice(L10n::t('%s : Not a valid email address.', $recip) . EOL); notice(L10n::t('%s : Not a valid email address.', $recipient) . EOL);
continue; continue;
} }
if ($invonly && ($x || is_site_admin())) { if ($invitation_only && ($invites_remaining || is_site_admin())) {
$code = autoname(8) . srand(1000, 9999); $code = autoname(8) . srand(1000, 9999);
$nmessage = str_replace('$invite_code', $code, $message); $nmessage = str_replace('$invite_code', $code, $message);
@ -66,9 +66,9 @@ function invite_post(App $a)
); );
if (! is_site_admin()) { if (! is_site_admin()) {
$x --; $invites_remaining --;
if ($x >= 0) { if ($invites_remaining >= 0) {
PConfig::set(local_user(), 'system', 'invites_remaining', $x); PConfig::set(local_user(), 'system', 'invites_remaining', $invites_remaining);
} else { } else {
return; return;
} }
@ -77,11 +77,16 @@ function invite_post(App $a)
$nmessage = $message; $nmessage = $message;
} }
$res = mail($recip, Email::encodeHeader(L10n::t('Please join us on Friendica'), 'UTF-8'), $additional_headers = 'From: ' . $a->user['email'] . "\n"
$nmessage, . 'Sender: ' . $a->getSenderEmailAddress() . "\n"
"From: " . $a->user['email'] . "\n"
. 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n"
. 'Content-transfer-encoding: 8bit' ); . 'Content-transfer-encoding: 8bit';
$res = mail(
$recipient,
Email::encodeHeader(L10n::t('Please join us on Friendica'), 'UTF-8'),
$nmessage,
$additional_headers);
if ($res) { if ($res) {
$total ++; $total ++;
@ -92,7 +97,7 @@ function invite_post(App $a)
return; return;
} }
} else { } else {
notice(L10n::t('%s : Message delivery failed.', $recip) . EOL); notice(L10n::t('%s : Message delivery failed.', $recipient) . EOL);
} }
} }

View file

@ -808,7 +808,6 @@ function item_post(App $a) {
$link = '<a href="' . System::baseUrl() . '/profile/' . $a->user['nickname'] . '"><img src="' . $author['thumb'] . '" alt="' . $a->user['username'] . '" /></a><br /><br />'; $link = '<a href="' . System::baseUrl() . '/profile/' . $a->user['nickname'] . '"><img src="' . $author['thumb'] . '" alt="' . $a->user['username'] . '" /></a><br /><br />';
$html = prepare_body($datarray); $html = prepare_body($datarray);
$message = '<html><body>' . $link . $html . $disclaimer . '</body></html>'; $message = '<html><body>' . $link . $html . $disclaimer . '</body></html>';
include_once 'include/html2plain.php';
$params = [ $params = [
'fromName' => $a->user['username'], 'fromName' => $a->user['username'],
'fromEmail' => $a->user['email'], 'fromEmail' => $a->user['email'],
@ -816,7 +815,7 @@ function item_post(App $a) {
'replyTo' => $a->user['email'], 'replyTo' => $a->user['email'],
'messageSubject' => $subject, 'messageSubject' => $subject,
'htmlVersion' => $message, 'htmlVersion' => $message,
'textVersion' => html2plain($html.$disclaimer) 'textVersion' => Friendica\Content\Text\HTML::toPlaintext($html.$disclaimer)
]; ];
Emailer::send($params); Emailer::send($params);
} }

View file

@ -69,6 +69,7 @@ function lostpass_post(App $a)
notification([ notification([
'type' => SYSTEM_EMAIL, 'type' => SYSTEM_EMAIL,
'to_email' => $user['email'], 'to_email' => $user['email'],
'uid' => $user['uid'],
'subject' => L10n::t('Password reset requested at %s', $sitename), 'subject' => L10n::t('Password reset requested at %s', $sitename),
'preamble' => $preamble, 'preamble' => $preamble,
'body' => $body 'body' => $body
@ -164,6 +165,7 @@ function lostpass_generate_password($user)
notification([ notification([
'type' => SYSTEM_EMAIL, 'type' => SYSTEM_EMAIL,
'to_email' => $user['email'], 'to_email' => $user['email'],
'uid' => $user['uid'],
'subject' => L10n::t('Your password has been changed at %s', $sitename), 'subject' => L10n::t('Your password has been changed at %s', $sitename),
'preamble' => $preamble, 'preamble' => $preamble,
'body' => $body 'body' => $body

View file

@ -771,10 +771,15 @@ function networkThreadedView(App $a, $update, $parent)
FROM `item` $sql_post_table FROM `item` $sql_post_table
STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
AND (NOT `contact`.`blocked` OR `contact`.`pending`) AND (NOT `contact`.`blocked` OR `contact`.`pending`)
AND (`item`.`parent-uri` != `item`.`uri`
OR `contact`.`uid` = `item`.`uid` AND `contact`.`self`
OR `contact`.`rel` IN (%d, %d) AND NOT `contact`.`readonly`)
WHERE `item`.`uid` = %d AND `item`.`visible` AND NOT `item`.`deleted` WHERE `item`.`uid` = %d AND `item`.`visible` AND NOT `item`.`deleted`
AND NOT `item`.`moderated` AND $sql_extra4 AND NOT `item`.`moderated` AND $sql_extra4
$sql_extra3 $sql_extra $sql_range $sql_nets $sql_extra3 $sql_extra $sql_range $sql_nets
ORDER BY `order_date` DESC LIMIT 100", ORDER BY `order_date` DESC LIMIT 100",
intval(CONTACT_IS_SHARING),
intval(CONTACT_IS_FRIEND),
intval(local_user()) intval(local_user())
); );
} else { } else {
@ -783,10 +788,15 @@ function networkThreadedView(App $a, $update, $parent)
STRAIGHT_JOIN `contact` ON `contact`.`id` = `thread`.`contact-id` STRAIGHT_JOIN `contact` ON `contact`.`id` = `thread`.`contact-id`
AND (NOT `contact`.`blocked` OR `contact`.`pending`) AND (NOT `contact`.`blocked` OR `contact`.`pending`)
STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid` STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid`
AND (`item`.`parent-uri` != `item`.`uri`
OR `contact`.`uid` = `item`.`uid` AND `contact`.`self`
OR `contact`.`rel` IN (%d, %d) AND NOT `contact`.`readonly`)
WHERE `thread`.`uid` = %d AND `thread`.`visible` AND NOT `thread`.`deleted` WHERE `thread`.`uid` = %d AND `thread`.`visible` AND NOT `thread`.`deleted`
AND NOT `thread`.`moderated` AND NOT `thread`.`moderated`
$sql_extra2 $sql_extra3 $sql_range $sql_extra $sql_nets $sql_extra2 $sql_extra3 $sql_range $sql_extra $sql_nets
ORDER BY `order_date` DESC $pager_sql", ORDER BY `order_date` DESC $pager_sql",
intval(CONTACT_IS_SHARING),
intval(CONTACT_IS_FRIEND),
intval(local_user()) intval(local_user())
); );
} }
@ -827,9 +837,14 @@ function networkThreadedView(App $a, $update, $parent)
(SELECT SUBSTR(`term`, 2) FROM `search` WHERE `uid` = ? AND `term` LIKE '#%') AND `otype` = ? AND `type` = ? AND `uid` = 0) AS `term` (SELECT SUBSTR(`term`, 2) FROM `search` WHERE `uid` = ? AND `term` LIKE '#%') AND `otype` = ? AND `type` = ? AND `uid` = 0) AS `term`
ON `item`.`id` = `term`.`oid` ON `item`.`id` = `term`.`oid`
STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`author-id` STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`author-id`
AND (`item`.`parent-uri` != `item`.`uri`
OR `contact`.`uid` = `item`.`uid` AND `contact`.`self`
OR `contact`.`rel` IN (?, ?) AND NOT `contact`.`readonly`)
WHERE `item`.`uid` = 0 AND `item`.$ordering < ? AND `item`.$ordering > ? WHERE `item`.`uid` = 0 AND `item`.$ordering < ? AND `item`.$ordering > ?
AND NOT `contact`.`hidden` AND NOT `contact`.`blocked`" . $sql_tag_nets, AND NOT `contact`.`hidden` AND NOT `contact`.`blocked`" . $sql_tag_nets,
local_user(), TERM_OBJ_POST, TERM_HASHTAG, $top_limit, $bottom_limit); local_user(), TERM_OBJ_POST, TERM_HASHTAG,
CONTACT_IS_SHARING, CONTACT_IS_FRIEND,
$top_limit, $bottom_limit);
$data = dba::inArray($items); $data = dba::inArray($items);

View file

@ -46,13 +46,11 @@ function oexchange_content(App $a) {
return; return;
} }
require_once('include/html2bbcode.php');
$post = []; $post = [];
$post['profile_uid'] = local_user(); $post['profile_uid'] = local_user();
$post['return'] = '/oexchange/done' ; $post['return'] = '/oexchange/done' ;
$post['body'] = html2bbcode($s); $post['body'] = Friendica\Content\Text\HTML::toBBCode($s);
$post['type'] = 'wall'; $post['type'] = 'wall';
$_REQUEST = $post; $_REQUEST = $post;

View file

@ -29,12 +29,14 @@ function ostatus_subscribe_content(App $a) {
if (PConfig::get($uid, "ostatus", "legacy_friends") == "") { if (PConfig::get($uid, "ostatus", "legacy_friends") == "") {
if ($_REQUEST["url"] == "") { if ($_REQUEST["url"] == "") {
PConfig::delete($uid, "ostatus", "legacy_contact");
return $o.L10n::t("No contact provided."); return $o.L10n::t("No contact provided.");
} }
$contact = Probe::uri($_REQUEST["url"]); $contact = Probe::uri($_REQUEST["url"]);
if (!$contact) { if (!$contact) {
PConfig::delete($uid, "ostatus", "legacy_contact");
return $o.L10n::t("Couldn't fetch information for contact."); return $o.L10n::t("Couldn't fetch information for contact.");
} }
@ -44,6 +46,7 @@ function ostatus_subscribe_content(App $a) {
$data = Network::curl($api."statuses/friends.json?screen_name=".$contact["nick"]); $data = Network::curl($api."statuses/friends.json?screen_name=".$contact["nick"]);
if (!$data["success"]) { if (!$data["success"]) {
PConfig::delete($uid, "ostatus", "legacy_contact");
return $o.L10n::t("Couldn't fetch friends for contact."); return $o.L10n::t("Couldn't fetch friends for contact.");
} }

View file

@ -9,6 +9,7 @@ use Friendica\Core\L10n;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Model\Contact;
use Friendica\Model\Photo; use Friendica\Model\Photo;
use Friendica\Model\Profile; use Friendica\Model\Profile;
use Friendica\Object\Image; use Friendica\Object\Image;
@ -105,18 +106,11 @@ function profile_photo_post(App $a) {
// If setting for the default profile, unset the profile photo flag from any other photos I own // If setting for the default profile, unset the profile photo flag from any other photos I own
if($is_default_profile) { if ($is_default_profile) {
$r = q("UPDATE `photo` SET `profile` = 0 WHERE `profile` = 1 AND `resource-id` != '%s' AND `uid` = %d", $r = q("UPDATE `photo` SET `profile` = 0 WHERE `profile` = 1 AND `resource-id` != '%s' AND `uid` = %d",
dbesc($base_image['resource-id']), dbesc($base_image['resource-id']),
intval(local_user()) intval(local_user())
); );
$r = q("UPDATE `contact` SET `photo` = '%s', `thumb` = '%s', `micro` = '%s' WHERE `self` AND `uid` = %d",
dbesc(System::baseUrl() . '/photo/' . $base_image['resource-id'] . '-4.' . $Image->getExt()),
dbesc(System::baseUrl() . '/photo/' . $base_image['resource-id'] . '-5.' . $Image->getExt()),
dbesc(System::baseUrl() . '/photo/' . $base_image['resource-id'] . '-6.' . $Image->getExt()),
intval(local_user())
);
} else { } else {
$r = q("update profile set photo = '%s', thumb = '%s' where id = %d and uid = %d", $r = q("update profile set photo = '%s', thumb = '%s' where id = %d and uid = %d",
dbesc(System::baseUrl() . '/photo/' . $base_image['resource-id'] . '-4.' . $Image->getExt()), dbesc(System::baseUrl() . '/photo/' . $base_image['resource-id'] . '-4.' . $Image->getExt()),
@ -126,13 +120,7 @@ function profile_photo_post(App $a) {
); );
} }
// we'll set the updated profile-photo timestamp even if it isn't the default profile, Contact::updateSelfFromUserID(local_user(), true);
// so that browsers will do a cache update unconditionally
$r = q("UPDATE `contact` SET `avatar-date` = '%s' WHERE `self` = 1 AND `uid` = %d",
dbesc(DateTimeFormat::utcNow()),
intval(local_user())
);
info(L10n::t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL); info(L10n::t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL);
// Update global directory in background // Update global directory in background
@ -229,10 +217,7 @@ function profile_photo_content(App $a) {
dbesc($resource_id) dbesc($resource_id)
); );
$r = q("UPDATE `contact` SET `avatar-date` = '%s' WHERE `self` = 1 AND `uid` = %d", Contact::updateSelfFromUserID(local_user(), true);
dbesc(DateTimeFormat::utcNow()),
intval(local_user())
);
// Update global directory in background // Update global directory in background
$url = $_SESSION['my_url']; $url = $_SESSION['my_url'];

View file

@ -14,6 +14,7 @@ use Friendica\Core\PConfig;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Model\Contact;
use Friendica\Model\GContact; use Friendica\Model\GContact;
use Friendica\Model\Item; use Friendica\Model\Item;
use Friendica\Model\Profile; use Friendica\Model\Profile;
@ -485,29 +486,15 @@ function profiles_post(App $a) {
info(L10n::t('Profile updated.') . EOL); info(L10n::t('Profile updated.') . EOL);
} }
if ($is_default) {
if ($namechanged && $is_default) { if ($namechanged) {
$r = q("UPDATE `contact` SET `name` = '%s', `name-date` = '%s' WHERE `self` = 1 AND `uid` = %d",
dbesc($name),
dbesc(DateTimeFormat::utcNow()),
intval(local_user())
);
$r = q("UPDATE `user` set `username` = '%s' where `uid` = %d", $r = q("UPDATE `user` set `username` = '%s' where `uid` = %d",
dbesc($name), dbesc($name),
intval(local_user()) intval(local_user())
); );
} }
if ($is_default) { Contact::updateSelfFromUserID(local_user());
$location = Profile::formatLocation(["locality" => $locality, "region" => $region, "country-name" => $country_name]);
q("UPDATE `contact` SET `about` = '%s', `location` = '%s', `keywords` = '%s', `gender` = '%s' WHERE `self` AND `uid` = %d",
dbesc($about),
dbesc($location),
dbesc($pub_keywords),
dbesc($gender),
intval(local_user())
);
// Update global directory in background // Update global directory in background
$url = $_SESSION['my_url']; $url = $_SESSION['my_url'];

View file

@ -2,162 +2,136 @@
use Friendica\App; use Friendica\App;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Protocol\OStatus;
function hub_return($valid,$body) { require_once('include/security.php');
require_once('include/items.php');
if($valid) { function hub_return($valid, $body)
header($_SERVER["SERVER_PROTOCOL"] . ' 200 ' . 'OK'); {
if ($valid) {
header($_SERVER["SERVER_PROTOCOL"] . ' 200 OK');
echo $body; echo $body;
killme(); } else {
header($_SERVER["SERVER_PROTOCOL"] . ' 404 Not Found');
} }
else {
header($_SERVER["SERVER_PROTOCOL"] . ' 404 ' . 'Not Found');
killme(); killme();
}
// NOTREACHED
} }
// when receiving an XML feed, always return OK // when receiving an XML feed, always return OK
function hub_post_return() { function hub_post_return()
{
header($_SERVER["SERVER_PROTOCOL"] . ' 200 ' . 'OK'); header($_SERVER["SERVER_PROTOCOL"] . ' 200 OK');
killme(); killme();
} }
function pubsub_init(App $a)
{
function pubsub_init(App $a) {
$nick = (($a->argc > 1) ? notags(trim($a->argv[1])) : ''); $nick = (($a->argc > 1) ? notags(trim($a->argv[1])) : '');
$contact_id = (($a->argc > 2) ? intval($a->argv[2]) : 0 ); $contact_id = (($a->argc > 2) ? intval($a->argv[2]) : 0 );
if($_SERVER['REQUEST_METHOD'] === 'GET') { if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$hub_mode = notags(trim(defaults($_GET, 'hub_mode', '')));
$hub_topic = notags(trim(defaults($_GET, 'hub_topic', '')));
$hub_challenge = notags(trim(defaults($_GET, 'hub_challenge', '')));
$hub_lease = notags(trim(defaults($_GET, 'hub_lease_seconds', '')));
$hub_verify = notags(trim(defaults($_GET, 'hub_verify_token', '')));
$hub_mode = ((x($_GET,'hub_mode')) ? notags(trim($_GET['hub_mode'])) : ''); logger('Subscription from ' . $_SERVER['REMOTE_ADDR'] . ' Mode: ' . $hub_mode . ' Nick: ' . $nick);
$hub_topic = ((x($_GET,'hub_topic')) ? notags(trim($_GET['hub_topic'])) : ''); logger('Data: ' . print_r($_GET,true), LOGGER_DATA);
$hub_challenge = ((x($_GET,'hub_challenge')) ? notags(trim($_GET['hub_challenge'])) : '');
$hub_lease = ((x($_GET,'hub_lease_seconds')) ? notags(trim($_GET['hub_lease_seconds'])) : '');
$hub_verify = ((x($_GET,'hub_verify_token')) ? notags(trim($_GET['hub_verify_token'])) : '');
logger('pubsub: Subscription from ' . $_SERVER['REMOTE_ADDR']);
logger('pubsub: data: ' . print_r($_GET,true), LOGGER_DATA);
$subscribe = (($hub_mode === 'subscribe') ? 1 : 0); $subscribe = (($hub_mode === 'subscribe') ? 1 : 0);
$r = q("SELECT * FROM `user` WHERE `nickname` = '%s' AND `account_expired` = 0 AND `account_removed` = 0 LIMIT 1", $owner = dba::selectFirst('user', ['uid'], ['nickname' => $nick, 'account_expired' => false, 'account_removed' => false]);
dbesc($nick) if (!DBM::is_result($owner)) {
); logger('Local account not found: ' . $nick);
if (! DBM::is_result($r)) {
logger('pubsub: local account not found: ' . $nick);
hub_return(false, ''); hub_return(false, '');
} }
$condition = ['uid' => $owner['uid'], 'id' => $contact_id, 'blocked' => false, 'pending' => false];
$owner = $r[0]; if (!empty($hub_verify)) {
$condition['hub-verify'] = $hub_verify;
}
$sql_extra = ((strlen($hub_verify)) ? sprintf(" AND `hub-verify` = '%s' ", dbesc($hub_verify)) : ''); $contact = dba::selectFirst('contact', ['id', 'poll'], $condition);
if (!DBM::is_result($contact)) {
$r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d logger('Contact ' . $contact_id . ' not found.');
AND `blocked` = 0 AND `pending` = 0 $sql_extra LIMIT 1",
intval($contact_id),
intval($owner['uid'])
);
if (! DBM::is_result($r)) {
logger('pubsub: contact '.$contact_id.' not found.');
hub_return(false, ''); hub_return(false, '');
} }
if ($hub_topic) if (!empty($hub_topic) && !link_compare($hub_topic, $contact['poll'])) {
if(! link_compare($hub_topic,$r[0]['poll'])) { logger('Hub topic ' . $hub_topic . ' != ' . $contact['poll']);
logger('pubsub: hub topic ' . $hub_topic . ' != ' . $r[0]['poll']); hub_return(false, '');
// should abort but let's humour them.
} }
$contact = $r[0];
// We must initiate an unsubscribe request with a verify_token. // We must initiate an unsubscribe request with a verify_token.
// Don't allow outsiders to unsubscribe us. // Don't allow outsiders to unsubscribe us.
if($hub_mode === 'unsubscribe') { if (($hub_mode === 'unsubscribe') && empty($hub_verify)) {
if(! strlen($hub_verify)) { logger('Bogus unsubscribe');
logger('pubsub: bogus unsubscribe');
hub_return(false, ''); hub_return(false, '');
} }
logger('pubsub: unsubscribe success');
if (!empty($hub_mode)) {
dba::update('contact', ['subhub' => $subscribe], ['id' => $contact['id']]);
logger($hub_mode . ' success for contact ' . $contact_id . '.');
} }
if ($hub_mode)
$r = q("UPDATE `contact` SET `subhub` = %d WHERE `id` = %d",
intval($subscribe),
intval($contact['id'])
);
hub_return(true, $hub_challenge); hub_return(true, $hub_challenge);
} }
} }
require_once('include/security.php'); function pubsub_post(App $a)
{
function pubsub_post(App $a) {
$xml = file_get_contents('php://input'); $xml = file_get_contents('php://input');
logger('pubsub: feed arrived from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $a->cmd ); logger('Feed arrived from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $a->cmd . ' with user-agent: ' . $_SERVER['HTTP_USER_AGENT']);
logger('pubsub: user-agent: ' . $_SERVER['HTTP_USER_AGENT'] ); logger('Data: ' . $xml, LOGGER_DATA);
logger('pubsub: data: ' . $xml, LOGGER_DATA);
// if(! stristr($xml,'<?xml')) {
// logger('pubsub_post: bad xml');
// hub_post_return();
// }
$nick = (($a->argc > 1) ? notags(trim($a->argv[1])) : ''); $nick = (($a->argc > 1) ? notags(trim($a->argv[1])) : '');
$contact_id = (($a->argc > 2) ? intval($a->argv[2]) : 0 ); $contact_id = (($a->argc > 2) ? intval($a->argv[2]) : 0 );
$r = q("SELECT * FROM `user` WHERE `nickname` = '%s' AND `account_expired` = 0 AND `account_removed` = 0 LIMIT 1", $importer = dba::selectFirst('user', [], ['nickname' => $nick, 'account_expired' => false, 'account_removed' => false]);
dbesc($nick) if (!DBM::is_result($importer)) {
);
if (! DBM::is_result($r)) {
hub_post_return(); hub_post_return();
} }
$importer = $r[0]; $condition = ['id' => $contact_id, 'uid' => $importer['uid'], 'subhub' => true, 'blocked' => false];
$contact = dba::selectFirst('contact', [], $condition);
$r = q("SELECT * FROM `contact` WHERE `subhub` AND `id` = %d AND `uid` = %d if (!DBM::is_result($contact)) {
AND (`rel` = %d OR `rel` = %d OR network = '%s') AND NOT `blocked` LIMIT 1", $author = OStatus::salmonAuthor($xml, $importer);
intval($contact_id), if (!empty($author['contact-id'])) {
intval($importer['uid']), $condition = ['id' => $author['contact-id'], 'uid' => $importer['uid'], 'subhub' => true, 'blocked' => false];
intval(CONTACT_IS_SHARING), $contact = dba::selectFirst('contact', [], $condition);
intval(CONTACT_IS_FRIEND), logger('No record for ' . $nick .' with contact id ' . $contact_id . ' - using '.$author['contact-id'].' instead.');
dbesc(NETWORK_FEED) }
); if (!DBM::is_result($contact)) {
logger('Contact ' . $author["author-link"] . ' (' . $contact_id . ') for user ' . $nick . " wasn't found - ignored. XML: " . $xml);
hub_post_return();
}
}
if (! DBM::is_result($r)) { if (!in_array($contact['rel'], [CONTACT_IS_SHARING, CONTACT_IS_FRIEND]) && ($contact['network'] != NETWORK_FEED)) {
logger('pubsub: no contact record for "'.$nick.' ('.$contact_id.')" - ignored. '.$xml); logger('Contact ' . $contact['id'] . ' is not expected to share with us - ignored.');
hub_post_return(); hub_post_return();
} }
$contact = $r[0]; // We import feeds from OStatus, Friendica and ATOM/RSS.
/// @todo Check if Friendica posts really arrive here - otherwise we can discard some stuff
// we have no way to match Diaspora guid's with atom post id's and could get duplicates. if (!in_array($contact['network'], [NETWORK_OSTATUS, NETWORK_DFRN, NETWORK_FEED])) {
// we'll assume that direct delivery is robust (and this is a bad assumption, but the duplicates are messy).
if($r[0]['network'] === NETWORK_DIASPORA)
hub_post_return(); hub_post_return();
}
logger('Import item for ' . $nick . ' from ' . $contact['nick'] . ' (' . $contact['id'] . ')');
$feedhub = ''; $feedhub = '';
consume_feed($xml, $importer, $contact, $feedhub);
require_once('include/items.php'); // do it a second time for DFRN so that any children find their parents.
if ($contact['network'] === NETWORK_DFRN) {
consume_feed($xml,$importer,$contact,$feedhub,1,1); consume_feed($xml, $importer, $contact, $feedhub);
}
// do it a second time so that any children find their parents.
consume_feed($xml,$importer,$contact,$feedhub,1,2);
hub_post_return(); hub_post_return();
} }

View file

@ -262,7 +262,7 @@ function register_content(App $a)
'$invite_id' => $invite_id, '$invite_id' => $invite_id,
'$realpeople' => $realpeople, '$realpeople' => $realpeople,
'$regtitle' => L10n::t('Registration'), '$regtitle' => L10n::t('Registration'),
'$registertext' => x($a->config, 'register_text') ? BBCode::convert($a->config['register_text']) : "", '$registertext' => BBCode::convert(Config::get('config', 'register_text', '')),
'$fillwith' => $fillwith, '$fillwith' => $fillwith,
'$fillext' => $fillext, '$fillext' => $fillext,
'$oidlabel' => $oidlabel, '$oidlabel' => $oidlabel,
@ -284,6 +284,9 @@ function register_content(App $a)
'$sitename' => $a->get_hostname(), '$sitename' => $a->get_hostname(),
'$importh' => L10n::t('Import'), '$importh' => L10n::t('Import'),
'$importt' => L10n::t('Import your profile to this friendica instance'), '$importt' => L10n::t('Import your profile to this friendica instance'),
'$showtoslink' => Config::get('system', 'tosdisplay'),
'$tostext' => L10n::t('Terms of Service'),
'$baseurl' => System::baseurl(),
'$form_security_token' => get_form_security_token("register") '$form_security_token' => get_form_security_token("register")
]); ]);
return $o; return $o;

View file

@ -7,6 +7,8 @@ use Friendica\Core\L10n;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Model\User; use Friendica\Model\User;
require_once 'include/enotify.php';
function removeme_post(App $a) function removeme_post(App $a)
{ {
if (!local_user()) { if (!local_user()) {
@ -29,6 +31,25 @@ function removeme_post(App $a)
return; return;
} }
// send notification to admins so that they can clean um the backups
// send email to admins
$admin_mail_list = "'" . implode("','", array_map(dbesc, explode(",", str_replace(" ", "", $a->config['admin_email'])))) . "'";
$adminlist = q("SELECT uid, language, email FROM user WHERE email IN (%s)",
$admin_mail_list
);
foreach ($adminlist as $admin) {
notification([
'type' => SYSTEM_EMAIL,
'subject' => L10n::t('[Friendica System Notify]') . ' ' . L10n::t('User deleted their account'),
'preamble' => L10n::t('On your Friendica node an user deleted their account. Please ensure that their data is removed from the backups.'),
'body' => L10n::t('The user id is %d', local_user()),
'to_email' => $admin['email'],
'uid' => $admin['uid'],
'language' => $admin['language'] ? $admin['language'] : 'en',
'show_in_notification_page' => false
]);
}
if (User::authenticate($a->user, trim($_POST['qxz_password']))) { if (User::authenticate($a->user, trim($_POST['qxz_password']))) {
User::remove($a->user['uid']); User::remove($a->user['uid']);
// NOTREACHED // NOTREACHED

View file

@ -13,9 +13,11 @@ use Friendica\Util\Crypto;
require_once 'include/items.php'; require_once 'include/items.php';
function salmon_post(App $a) { function salmon_post(App $a, $xml = '') {
if (empty($xml)) {
$xml = file_get_contents('php://input'); $xml = file_get_contents('php://input');
}
logger('new salmon ' . $xml, LOGGER_DATA); logger('new salmon ' . $xml, LOGGER_DATA);

View file

@ -14,11 +14,11 @@ use Friendica\Core\PConfig;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Model\Contact;
use Friendica\Model\GContact; use Friendica\Model\GContact;
use Friendica\Model\Group; use Friendica\Model\Group;
use Friendica\Model\User; use Friendica\Model\User;
use Friendica\Protocol\Email; use Friendica\Protocol\Email;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Network; use Friendica\Util\Network;
use Friendica\Util\Temporal; use Friendica\Util\Temporal;
@ -208,11 +208,11 @@ function settings_post(App $a)
return; return;
} }
if (($a->argc > 1) && ($a->argv[1] == 'connectors')) if (($a->argc > 1) && ($a->argv[1] == 'connectors')) {
{
check_form_security_token_redirectOnErr('/settings/connectors', 'settings_connectors'); check_form_security_token_redirectOnErr('/settings/connectors', 'settings_connectors');
if (x($_POST, 'general-submit')) { if (x($_POST, 'general-submit')) {
PConfig::set(local_user(), 'system', 'disable_cw', intval($_POST['disable_cw']));
PConfig::set(local_user(), 'system', 'no_intelligent_shortening', intval($_POST['no_intelligent_shortening'])); PConfig::set(local_user(), 'system', 'no_intelligent_shortening', intval($_POST['no_intelligent_shortening']));
PConfig::set(local_user(), 'system', 'ostatus_autofriend', intval($_POST['snautofollow'])); PConfig::set(local_user(), 'system', 'ostatus_autofriend', intval($_POST['snautofollow']));
PConfig::set(local_user(), 'ostatus', 'default_group', $_POST['group-selection']); PConfig::set(local_user(), 'ostatus', 'default_group', $_POST['group-selection']);
@ -390,6 +390,11 @@ function settings_post(App $a)
$err = true; $err = true;
} }
if (!Config::get('system', 'disable_password_exposed', false) && User::isPasswordExposed($newpass)) {
notice(L10n::t('The new password has been exposed in a public data dump, please choose another.') . EOL);
$err = true;
}
// check if the old password was supplied correctly before changing it to the new value // check if the old password was supplied correctly before changing it to the new value
if (!User::authenticate(intval(local_user()), $_POST['opassword'])) { if (!User::authenticate(intval(local_user()), $_POST['opassword'])) {
notice(L10n::t('Wrong password.') . EOL); notice(L10n::t('Wrong password.') . EOL);
@ -486,10 +491,7 @@ function settings_post(App $a)
$err = ''; $err = '';
$name_change = false;
if ($username != $a->user['username']) { if ($username != $a->user['username']) {
$name_change = true;
if (strlen($username) > 40) { if (strlen($username) > 40) {
$err .= L10n::t(' Please use a shorter name.'); $err .= L10n::t(' Please use a shorter name.');
} }
@ -629,14 +631,7 @@ function settings_post(App $a)
intval(local_user()) intval(local_user())
); );
Contact::updateSelfFromUserID(local_user());
if ($name_change) {
q("UPDATE `contact` SET `name` = '%s', `name-date` = '%s' WHERE `uid` = %d AND `self`",
dbesc($username),
dbesc(DateTimeFormat::utcNow()),
intval(local_user())
);
}
if (($old_visibility != $net_publish) || ($page_flags != $old_page_flags)) { if (($old_visibility != $net_publish) || ($page_flags != $old_page_flags)) {
// Update global directory in background // Update global directory in background
@ -792,6 +787,7 @@ function settings_content(App $a)
} }
if (($a->argc > 1) && ($a->argv[1] === 'connectors')) { if (($a->argc > 1) && ($a->argv[1] === 'connectors')) {
$disable_cw = intval(PConfig::get(local_user(), 'system', 'disable_cw'));
$no_intelligent_shortening = intval(PConfig::get(local_user(), 'system', 'no_intelligent_shortening')); $no_intelligent_shortening = intval(PConfig::get(local_user(), 'system', 'no_intelligent_shortening'));
$ostatus_autofriend = intval(PConfig::get(local_user(), 'system', 'ostatus_autofriend')); $ostatus_autofriend = intval(PConfig::get(local_user(), 'system', 'ostatus_autofriend'));
$default_group = PConfig::get(local_user(), 'ostatus', 'default_group'); $default_group = PConfig::get(local_user(), 'ostatus', 'default_group');
@ -849,6 +845,7 @@ function settings_content(App $a)
'$ostat_enabled' => $ostat_enabled, '$ostat_enabled' => $ostat_enabled,
'$general_settings' => L10n::t('General Social Media Settings'), '$general_settings' => L10n::t('General Social Media Settings'),
'$disable_cw' => ['disable_cw', L10n::t('Disable Content Warning'), $disable_cw, L10n::t('Users on networks like Mastodon or Pleroma are able to set a content warning field which collapse their post by default. This disables the automatic collapsing and sets the content warning as the post title. Doesn\'t affect any other content filtering you eventually set up.')],
'$no_intelligent_shortening' => ['no_intelligent_shortening', L10n::t('Disable intelligent shortening'), $no_intelligent_shortening, L10n::t('Normally the system tries to find the best link to add to shortened posts. If this option is enabled then every shortened post will always point to the original friendica post.')], '$no_intelligent_shortening' => ['no_intelligent_shortening', L10n::t('Disable intelligent shortening'), $no_intelligent_shortening, L10n::t('Normally the system tries to find the best link to add to shortened posts. If this option is enabled then every shortened post will always point to the original friendica post.')],
'$ostatus_autofriend' => ['snautofollow', L10n::t("Automatically follow any GNU Social \x28OStatus\x29 followers/mentioners"), $ostatus_autofriend, L10n::t('If you receive a message from an unknown OStatus user, this option decides what to do. If it is checked, a new contact will be created for every unknown user.')], '$ostatus_autofriend' => ['snautofollow', L10n::t("Automatically follow any GNU Social \x28OStatus\x29 followers/mentioners"), $ostatus_autofriend, L10n::t('If you receive a message from an unknown OStatus user, this option decides what to do. If it is checked, a new contact will be created for every unknown user.')],
'$default_group' => Group::displayGroupSelection(local_user(), $default_group, L10n::t("Default group for OStatus contacts")), '$default_group' => Group::displayGroupSelection(local_user(), $default_group, L10n::t("Default group for OStatus contacts")),
@ -1111,7 +1108,7 @@ function settings_content(App $a)
if (strlen(Config::get('system', 'directory'))) { if (strlen(Config::get('system', 'directory'))) {
$profile_in_net_dir = replace_macros($opt_tpl, [ $profile_in_net_dir = replace_macros($opt_tpl, [
'$field' => ['profile_in_netdirectory', L10n::t('Publish your default profile in the global social directory?'), $profile['net-publish'], L10n::t('Your profile will be publishedin this node\'s <a href="%s">local directory</a>. Your profile details may be publicly visible depending on the system settings.', System::baseUrl().'/directory'), [L10n::t('No'), L10n::t('Yes')]] '$field' => ['profile_in_netdirectory', L10n::t('Publish your default profile in the global social directory?'), $profile['net-publish'], L10n::t('Your profile will be published in this node\'s <a href="%s">local directory</a>. Your profile details may be publicly visible depending on the system settings.', System::baseUrl().'/directory'), [L10n::t('No'), L10n::t('Yes')]]
]); ]);
} else { } else {
$profile_in_net_dir = ''; $profile_in_net_dir = '';
@ -1274,7 +1271,7 @@ function settings_content(App $a)
'$detailed_notif' => ['detailed_notif', L10n::t('Show detailled notifications'), '$detailed_notif' => ['detailed_notif', L10n::t('Show detailled notifications'),
PConfig::get(local_user(), 'system', 'detailed_notif'), PConfig::get(local_user(), 'system', 'detailed_notif'),
L10n::t('Per default the notificiation are condensed to a single notification per item. When enabled, every notification is displayed.')], L10n::t('Per default, notifications are condensed to a single notification per item. When enabled every notification is displayed.')],
'$h_advn' => L10n::t('Advanced Account/Page Type Settings'), '$h_advn' => L10n::t('Advanced Account/Page Type Settings'),
'$h_descadvn' => L10n::t('Change the behaviour of this account for special situations'), '$h_descadvn' => L10n::t('Change the behaviour of this account for special situations'),

View file

@ -33,7 +33,7 @@ function unfollow_post(App $a)
if (!DBM::is_result($contact)) { if (!DBM::is_result($contact)) {
notice(L10n::t("Contact wasn't found or can't be unfollowed.")); notice(L10n::t("Contact wasn't found or can't be unfollowed."));
} else { } else {
if (in_array($contact['network'], [NETWORK_OSTATUS, NETWORK_DIASPORA])) { if (in_array($contact['network'], [NETWORK_OSTATUS, NETWORK_DIASPORA, NETWORK_DFRN])) {
$r = q("SELECT `contact`.*, `user`.* FROM `contact` INNER JOIN `user` ON `contact`.`uid` = `user`.`uid` $r = q("SELECT `contact`.*, `user`.* FROM `contact` INNER JOIN `user` ON `contact`.`uid` = `user`.`uid`
WHERE `user`.`uid` = %d AND `contact`.`self` LIMIT 1", WHERE `user`.`uid` = %d AND `contact`.`self` LIMIT 1",
intval($uid) intval($uid)
@ -75,7 +75,7 @@ function unfollow_content(App $a)
// NOTREACHED // NOTREACHED
} }
if (!in_array($contact['network'], [NETWORK_DIASPORA, NETWORK_OSTATUS])) { if (!in_array($contact['network'], [NETWORK_DIASPORA, NETWORK_OSTATUS, NETWORK_DFRN])) {
notice(L10n::t("Unfollowing is currently not supported by your network.").EOL); notice(L10n::t("Unfollowing is currently not supported by your network.").EOL);
$submit = ""; $submit = "";
// NOTREACHED // NOTREACHED

21
mods/home.css Normal file
View file

@ -0,0 +1,21 @@
.homeinfocontainer {
display: grid;
grid-template-columns: 33% 33% 33%;
grid-column-gap: 15px;
padding: 10px;
}
.homeinfobox p {
text-align: justify;
}
#c1 {
grid-column-start: 1;
grid-column-end: 2;
}
#c2 {
grid-column-start: 2;
grid-column-end: 3;
}
#c3 {
grid-column-start: 3;
grid-column-end: 4;
}

23
mods/home.html Normal file
View file

@ -0,0 +1,23 @@
<!-- styling for this page is done in the home.css file //-->
<!-- Some node specifiv welcome message //-->
<p>Welcome to this <a href="https://friendi.ca">Friendica</a> node!</p>
<!-- Some general notes about Friendica, the other networks and difficulty to run //-->
<div class="homeinfocontainer">
<div id="c1" class="homeinfobox">
<h4>What is Friendica?</h4>
<p>Friendica is a decentral social network platform everybody can use to setup their own social networking node. It interacts with many other FLOSS microblogging and social networking platforms as well as some walled gardens.</p>
<p><a href="https://friendi.ca">Learn more at friendi.ca</a><br /><a href="https://dir.friendica.social/servers">Find an open Friendica node to join</a></p>
</div>
<div id="c2" class="homeinfobox">
<h4>What other networks does it interact with?</h4>
<p>Every network that speaks either the DFRN2, OStatus or diaspora* protocol. Currently this list includes: diaspora*, friendica, ganggo, GNU social, Hubzilla, Mastodon, Pleroma, postActivi and Socialhome.</p>
<p><a href="http://fediverse.party/">Learn more at fediverse.party</a></p>
</div>
<div id="c3" class="homeinfobox">
<h4>Is it hard to run Friendica?</h4>
<p>No, not at all! You need a LAMP server, most shared hosting services that offer MySQL, PHP and the ability to run cron jobs will do just fine. If you have your own (virtual) server, for a small Friendica server something like a Raspberry2B is sufficenent from the specs.</p>
<p><a href="https://github.com/friendica/friendica">Get the source</a></p>
</div>
</div>

View file

@ -5,3 +5,27 @@ sample-nginx.config
or Nginx. Pleas check software documentation to know how modify or Nginx. Pleas check software documentation to know how modify
these examples to make them work on your server. these examples to make them work on your server.
sample-systemd.timer
sample-systemd.service
Sample systemd unit files to start worker.php periodically.
Please place them in the correct location for your system,
typically this is /etc/systemd/system/friendicaworker.timer
and /etc/systemd/system/friendicaworker.service.
Please report problems and improvements to
!helpers@forum.friendi.ca and @utzer@social.yl.ms or open an
issue in Github (https://github.com/friendica/friendica/issues).
This is for usage of systemd instead of cron to start the worker.php
periodically, the solution is work-in-progress and can surely be improved.
home.css
home.html
Example files to customize the landing page of your Friendica node.
The home.html file contains the text of the page, the home.css file
the style information. The login box will be added according to the
other system settings.
Both files have to be placed in the base directory of your Friendica
installation to be used for the landing page.

View file

@ -0,0 +1,9 @@
[Unit]
Description=Friendica Worker
[Service]
#User should be the same as the user the webserver runs under, typically http or www
User=http
#Adapt the path in the following line to your system, use 'which php' to find php path,
#provide the absolute path for worker.php
ExecStart=/usr/bin/php /www/path/bin/worker.php &

10
mods/sample-systemd.timer Normal file
View file

@ -0,0 +1,10 @@
[Unit]
Description=Run Friendica Poller every n minutes
[Timer]
OnBootSec=120
OnUnitActiveSec=120
RemainAfterElapse=False
[Install]
WantedBy=timers.target

8
phpunit.xml Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<phpunit bootstrap="boot.php">
<testsuites>
<testsuite>
<directory>tests/</directory>
</testsuite>
</testsuites>
</phpunit>

View file

@ -1,66 +0,0 @@
#!/usr/bin/env php
<?php
/**
* @file scripts/dbstructure.php
* @brief Does database updates from the command line
*/
use Friendica\App;
use Friendica\Core\Config;
use Friendica\Database\DBStructure;
require_once "boot.php";
require_once "include/dba.php";
$a = new App(dirname(__DIR__));
@include ".htconfig.php";
dba::connect($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data);
if ($_SERVER["argc"] == 2) {
switch ($_SERVER["argv"][1]) {
case "dryrun":
DBStructure::update(true, false);
return;
case "update":
DBStructure::update(true, true);
$build = Config::get('system','build');
if (!x($build)) {
Config::set('system', 'build', DB_UPDATE_VERSION);
$build = DB_UPDATE_VERSION;
}
$stored = intval($build);
$current = intval(DB_UPDATE_VERSION);
// run any left update_nnnn functions in update.php
for ($x = $stored; $x < $current; $x ++) {
$r = run_update_function($x);
if (!$r) {
break;
}
}
Config::set('system','build',DB_UPDATE_VERSION);
return;
case "dumpsql":
DBStructure::printStructure();
return;
case "toinnodb":
DBStructure::convertToInnoDB();
return;
}
}
// print help
echo $_SERVER["argv"][0]." <command>\n";
echo "\n";
echo "Commands:\n";
echo "dryrun show database update schema queries without running them\n";
echo "update update database schema\n";
echo "dumpsql dump database schema\n";
echo "toinnodb convert all tables from MyISAM to InnoDB\n";
killme();

View file

@ -212,12 +212,6 @@ class App
. $this->basepath . DIRECTORY_SEPARATOR . 'library' . PATH_SEPARATOR . $this->basepath . DIRECTORY_SEPARATOR . 'library' . PATH_SEPARATOR
. $this->basepath); . $this->basepath);
if (is_array($_SERVER['argv']) && $_SERVER['argc'] > 1 && substr(end($_SERVER['argv']), 0, 4) == 'http') {
$this->set_baseurl(array_pop($_SERVER['argv']));
$_SERVER['argc'] --;
}
if ((x($_SERVER, 'QUERY_STRING')) && substr($_SERVER['QUERY_STRING'], 0, 9) === 'pagename=') { if ((x($_SERVER, 'QUERY_STRING')) && substr($_SERVER['QUERY_STRING'], 0, 9) === 'pagename=') {
$this->query_string = substr($_SERVER['QUERY_STRING'], 9); $this->query_string = substr($_SERVER['QUERY_STRING'], 9);
@ -868,9 +862,6 @@ class App
array_unshift($args, ((x($this->config, 'php_path')) && (strlen($this->config['php_path'])) ? $this->config['php_path'] : 'php')); array_unshift($args, ((x($this->config, 'php_path')) && (strlen($this->config['php_path'])) ? $this->config['php_path'] : 'php'));
// add baseurl to args. cli scripts can't construct it
$args[] = $this->get_baseurl();
for ($x = 0; $x < count($args); $x ++) { for ($x = 0; $x < count($args); $x ++) {
$args[$x] = escapeshellarg($args[$x]); $args[$x] = escapeshellarg($args[$x]);
} }
@ -944,4 +935,136 @@ class App
return true; return true;
} }
/**
* @param string $cat Config category
* @param string $k Config key
* @param mixed $default Default value if it isn't set
*/
public function getConfigValue($cat, $k, $default = null)
{
$return = $default;
if ($cat === 'config') {
if (isset($this->config[$k])) {
$return = $this->config[$k];
}
} else {
if (isset($this->config[$cat][$k])) {
$return = $this->config[$cat][$k];
}
}
return $return;
}
/**
* Sets a value in the config cache. Accepts raw output from the config table
*
* @param string $cat Config category
* @param string $k Config key
* @param mixed $v Value to set
*/
public function setConfigValue($cat, $k, $v)
{
// Only arrays are serialized in database, so we have to unserialize sparingly
$value = is_string($v) && preg_match("|^a:[0-9]+:{.*}$|s", $v) ? unserialize($v) : $v;
if ($cat === 'config') {
$this->config[$k] = $value;
} else {
$this->config[$cat][$k] = $value;
}
}
/**
* Deletes a value from the config cache
*
* @param string $cat Config category
* @param string $k Config key
*/
public function deleteConfigValue($cat, $k)
{
if ($cat === 'config') {
if (isset($this->config[$k])) {
unset($this->config[$k]);
}
} else {
if (isset($this->config[$cat][$k])) {
unset($this->config[$cat][$k]);
}
}
}
/**
* Retrieves a value from the user config cache
*
* @param int $uid User Id
* @param string $cat Config category
* @param string $k Config key
* @param mixed $default Default value if key isn't set
*/
public function getPConfigValue($uid, $cat, $k, $default = null)
{
$return = $default;
if (isset($this->config[$uid][$cat][$k])) {
$return = $this->config[$uid][$cat][$k];
}
return $return;
}
/**
* Sets a value in the user config cache
*
* Accepts raw output from the pconfig table
*
* @param int $uid User Id
* @param string $cat Config category
* @param string $k Config key
* @param mixed $v Value to set
*/
public function setPConfigValue($uid, $cat, $k, $v)
{
// Only arrays are serialized in database, so we have to unserialize sparingly
$value = is_string($v) && preg_match("|^a:[0-9]+:{.*}$|s", $v) ? unserialize($v) : $v;
$this->config[$uid][$cat][$k] = $value;
}
/**
* Deletes a value from the user config cache
*
* @param int $uid User Id
* @param string $cat Config category
* @param string $k Config key
*/
public function deletePConfigValue($uid, $cat, $k)
{
if (isset($this->config[$uid][$cat][$k])) {
unset($this->config[$uid][$cat][$k]);
}
}
/**
* Generates the site's default sender email address
*
* @return string
*/
public function getSenderEmailAddress()
{
$sender_email = Config::get('config', 'sender_email');
if (empty($sender_email)) {
$hostname = $this->get_hostname();
if (strpos($hostname, ':')) {
$hostname = substr($hostname, 0, strpos($hostname, ':'));
}
$sender_email = 'noreply@' . $hostname;
}
return $sender_email;
}
} }

View file

@ -6,6 +6,9 @@ namespace Friendica;
* All modules in Friendica should extend BaseModule, although not all modules * All modules in Friendica should extend BaseModule, although not all modules
* need to extend all the methods described here * need to extend all the methods described here
* *
* The filename of the module in src/Module needs to match the class name
* exactly to make the module available.
*
* @author Hypolite Petovan mrpetovan@gmail.com * @author Hypolite Petovan mrpetovan@gmail.com
*/ */
abstract class BaseModule extends BaseObject abstract class BaseModule extends BaseObject

View file

@ -27,7 +27,7 @@ class ContactSelector
$o .= "<select id=\"contact-profile-selector\" class=\"form-control\" $disabled name=\"profile-assign\" >\r\n"; $o .= "<select id=\"contact-profile-selector\" class=\"form-control\" $disabled name=\"profile-assign\" >\r\n";
$s = dba::select('profile', ['id', 'profile-name', 'is-default'], ['uid' => $$_SESSION['uid']]); $s = dba::select('profile', ['id', 'profile-name', 'is-default'], ['uid' => $_SESSION['uid']]);
$r = dba::inArray($s); $r = dba::inArray($s);
if (DBM::is_result($r)) { if (DBM::is_result($r)) {

View file

@ -7,7 +7,7 @@
namespace Friendica\Content\Text; namespace Friendica\Content\Text;
use DOMDocument; use DOMDocument;
use DomXPath; use DOMXPath;
use Exception; use Exception;
use Friendica\BaseObject; use Friendica\BaseObject;
use Friendica\Content\OEmbed; use Friendica\Content\OEmbed;
@ -20,6 +20,7 @@ use Friendica\Core\PConfig;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Event;
use Friendica\Network\Probe; use Friendica\Network\Probe;
use Friendica\Object\Image; use Friendica\Object\Image;
use Friendica\Util\Map; use Friendica\Util\Map;
@ -27,8 +28,6 @@ use Friendica\Util\Network;
use Friendica\Util\ParseUrl; use Friendica\Util\ParseUrl;
use League\HTMLToMarkdown\HtmlConverter; use League\HTMLToMarkdown\HtmlConverter;
require_once "include/event.php";
require_once "include/html2plain.php";
require_once "mod/proxy.php"; require_once "mod/proxy.php";
class BBCode extends BaseObject class BBCode extends BaseObject
@ -77,12 +76,14 @@ class BBCode extends BaseObject
$picturedata = Image::getInfoFromURL($matches[1]); $picturedata = Image::getInfoFromURL($matches[1]);
if ($picturedata) {
if (($picturedata[0] >= 500) && ($picturedata[0] >= $picturedata[1])) { if (($picturedata[0] >= 500) && ($picturedata[0] >= $picturedata[1])) {
$post["image"] = $matches[1]; $post["image"] = $matches[1];
} else { } else {
$post["preview"] = $matches[1]; $post["preview"] = $matches[1];
} }
} }
}
if (preg_match("/\[bookmark\=([$URLSearchString]*)\](.*?)\[\/bookmark\]/ism", $attacheddata, $matches)) { if (preg_match("/\[bookmark\=([$URLSearchString]*)\](.*?)\[\/bookmark\]/ism", $attacheddata, $matches)) {
$post["url"] = $matches[1]; $post["url"] = $matches[1];
@ -242,6 +243,9 @@ class BBCode extends BaseObject
$body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body); $body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body);
$URLSearchString = "^\[\]"; $URLSearchString = "^\[\]";
$body = preg_replace("/\[img\=([$URLSearchString]*)\](.*?)\[\/img\]/ism", '[img]$1[/img]', $body);
if (preg_match_all("(\[url=([$URLSearchString]*)\]\s*\[img\]([$URLSearchString]*)\[\/img\]\s*\[\/url\])ism", $body, $pictures, PREG_SET_ORDER)) { if (preg_match_all("(\[url=([$URLSearchString]*)\]\s*\[img\]([$URLSearchString]*)\[\/img\]\s*\[\/url\])ism", $body, $pictures, PREG_SET_ORDER)) {
if ((count($pictures) == 1) && !$has_title) { if ((count($pictures) == 1) && !$has_title) {
// Checking, if the link goes to a picture // Checking, if the link goes to a picture
@ -267,7 +271,7 @@ class BBCode extends BaseObject
$post["text"] = str_replace($pictures[0][0], "", $body); $post["text"] = str_replace($pictures[0][0], "", $body);
} else { } else {
$imgdata = Image::getInfoFromURL($pictures[0][1]); $imgdata = Image::getInfoFromURL($pictures[0][1]);
if (substr($imgdata["mime"], 0, 6) == "image/") { if ($imgdata && substr($imgdata["mime"], 0, 6) == "image/") {
$post["type"] = "photo"; $post["type"] = "photo";
$post["image"] = $pictures[0][1]; $post["image"] = $pictures[0][1];
$post["preview"] = $pictures[0][2]; $post["preview"] = $pictures[0][2];
@ -413,7 +417,7 @@ class BBCode extends BaseObject
} }
$html = self::convert($post["text"].$post["after"], false, $htmlmode); $html = self::convert($post["text"].$post["after"], false, $htmlmode);
$msg = html2plain($html, 0, true); $msg = HTML::toPlaintext($html, 0, true);
$msg = trim(html_entity_decode($msg, ENT_QUOTES, 'UTF-8')); $msg = trim(html_entity_decode($msg, ENT_QUOTES, 'UTF-8'));
$link = ""; $link = "";
@ -681,7 +685,7 @@ class BBCode extends BaseObject
$return = ''; $return = '';
if ($simplehtml == 7) { if ($simplehtml == 7) {
$return = self::convertUrlForMastodon($data["url"]); $return = self::convertUrlForOStatus($data["url"]);
} elseif (($simplehtml != 4) && ($simplehtml != 0)) { } elseif (($simplehtml != 4) && ($simplehtml != 0)) {
$return = sprintf('<a href="%s" target="_blank">%s</a><br>', $data["url"], $data["title"]); $return = sprintf('<a href="%s" target="_blank">%s</a><br>', $data["url"], $data["title"]);
} else { } else {
@ -709,9 +713,10 @@ class BBCode extends BaseObject
} }
if ($data["description"] != "" && $data["description"] != $data["title"]) { if ($data["description"] != "" && $data["description"] != $data["title"]) {
$return .= sprintf('<blockquote>%s</blockquote>', trim(self::convert($data["description"]))); // Sanitize the HTML by converting it to BBCode
$bbcode = HTML::toBBCode($data["description"]);
$return .= sprintf('<blockquote>%s</blockquote>', trim(self::convert($bbcode)));
} }
if ($data["type"] == "link") { if ($data["type"] == "link") {
$return .= sprintf('<sup><a href="%s">%s</a></sup>', $data['url'], parse_url($data['url'], PHP_URL_HOST)); $return .= sprintf('<sup><a href="%s">%s</a></sup>', $data['url'], parse_url($data['url'], PHP_URL_HOST));
} }
@ -758,33 +763,12 @@ class BBCode extends BaseObject
if (($data["url"] != "") && ($data["title"] != "")) { if (($data["url"] != "") && ($data["title"] != "")) {
$text .= "\n[url=" . $data["url"] . "]" . $data["title"] . "[/url]"; $text .= "\n[url=" . $data["url"] . "]" . $data["title"] . "[/url]";
} elseif (($data["url"] != "")) { } elseif (($data["url"] != "")) {
$text .= "\n" . $data["url"]; $text .= "\n[url]" . $data["url"] . "[/url]";
} }
return $text . "\n" . $data["after"]; return $text . "\n" . $data["after"];
} }
private static function cleanCss($input)
{
$cleaned = "";
$input = strtolower($input);
for ($i = 0; $i < strlen($input); $i++) {
$char = substr($input, $i, 1);
if (($char >= "a") && ($char <= "z")) {
$cleaned .= $char;
}
if (!(strpos(" #;:0123456789-_.%", $char) === false)) {
$cleaned .= $char;
}
}
return $cleaned;
}
/** /**
* Converts [url] BBCodes in a format that looks fine on Mastodon. (callback function) * Converts [url] BBCodes in a format that looks fine on Mastodon. (callback function)
* *
@ -792,7 +776,7 @@ class BBCode extends BaseObject
* @param array $match Array with the matching values * @param array $match Array with the matching values
* @return string reformatted link including HTML codes * @return string reformatted link including HTML codes
*/ */
private static function convertUrlForMastodonCallback($match) private static function convertUrlForOStatusCallback($match)
{ {
$url = $match[1]; $url = $match[1];
@ -805,34 +789,27 @@ class BBCode extends BaseObject
return $match[0]; return $match[0];
} }
return self::convertUrlForMastodon($url); return self::convertUrlForOStatus($url);
} }
/** /**
* @brief Converts [url] BBCodes in a format that looks fine on Mastodon and GNU Social. * @brief Converts [url] BBCodes in a format that looks fine on OStatus systems.
* @param string $url URL that is about to be reformatted * @param string $url URL that is about to be reformatted
* @return string reformatted link including HTML codes * @return string reformatted link including HTML codes
*/ */
private static function convertUrlForMastodon($url) private static function convertUrlForOStatus($url)
{ {
$parts = parse_url($url); $parts = parse_url($url);
$scheme = $parts['scheme'] . '://'; $scheme = $parts['scheme'] . '://';
$styled_url = str_replace($scheme, '', $url); $styled_url = str_replace($scheme, '', $url);
$html = '<a href="%s" class="attachment" rel="nofollow noopener" target="_blank">' .
'<span class="invisible">%s</span>';
if (strlen($styled_url) > 30) { if (strlen($styled_url) > 30) {
$html .= '<span class="ellipsis">%s</span>' . $styled_url = substr($styled_url, 0, 30) . "";
'<span class="invisible">%s</span></a>';
$ellipsis = substr($styled_url, 0, 30);
$rest = substr($styled_url, 30);
return sprintf($html, $url, $scheme, $ellipsis, $rest);
} else {
$html .= '%s</a>';
return sprintf($html, $url, $scheme, $styled_url);
} }
$html = '<a href="%s" target="_blank">%s</a>';
return sprintf($html, $url, $styled_url);
} }
/* /*
@ -1127,13 +1104,13 @@ class BBCode extends BaseObject
} }
if (stripos(normalise_link($link), 'http://twitter.com/') === 0) { if (stripos(normalise_link($link), 'http://twitter.com/') === 0) {
$text .= '<br /><a href="' . $link . '">' . $link . '</a>';
} else {
$text .= $headline . '<blockquote>' . trim($share[3]) . "</blockquote><br />"; $text .= $headline . '<blockquote>' . trim($share[3]) . "</blockquote><br />";
if ($link != "") { if ($link != "") {
$text .= '<br /><a href="' . $link . '">[l]</a>'; $text .= '<br /><a href="' . $link . '">[l]</a>';
} }
} else {
$text .= '<br /><a href="' . $link . '">' . $link . '</a>';
} }
break; break;
@ -1229,7 +1206,7 @@ class BBCode extends BaseObject
$doc = new DOMDocument(); $doc = new DOMDocument();
@$doc->loadHTML($body); @$doc->loadHTML($body);
$xpath = new DomXPath($doc); $xpath = new DOMXPath($doc);
$list = $xpath->query("//meta[@name]"); $list = $xpath->query("//meta[@name]");
foreach ($list as $node) { foreach ($list as $node) {
$attr = []; $attr = [];
@ -1318,13 +1295,17 @@ class BBCode extends BaseObject
private static function textHighlightCallback($match) private static function textHighlightCallback($match)
{ {
// Fallback in case the language doesn't exist
$return = '[code]' . $match[2] . '[/code]';
if (in_array(strtolower($match[1]), if (in_array(strtolower($match[1]),
['php', 'css', 'mysql', 'sql', 'abap', 'diff', 'html', 'perl', 'ruby', ['php', 'css', 'mysql', 'sql', 'abap', 'diff', 'html', 'perl', 'ruby',
'vbscript', 'avrc', 'dtd', 'java', 'xml', 'cpp', 'python', 'javascript', 'js', 'sh']) 'vbscript', 'avrc', 'dtd', 'java', 'xml', 'cpp', 'python', 'javascript', 'js', 'sh', 'bash'])
) { ) {
return text_highlight($match[2], strtolower($match[1])); $return = text_highlight($match[2], strtolower($match[1]));
} }
return $match[0];
return $return;
} }
/** /**
@ -1401,7 +1382,7 @@ class BBCode extends BaseObject
// After we're finished processing the bbcode we'll // After we're finished processing the bbcode we'll
// replace all of the event code with a reformatted version. // replace all of the event code with a reformatted version.
$ev = bbtoevent($text); $ev = Event::fromBBCode($text);
// Replace any html brackets with HTML Entities to prevent executing HTML or script // Replace any html brackets with HTML Entities to prevent executing HTML or script
// Don't use strip_tags here because it breaks [url] search by replacing & with amp // Don't use strip_tags here because it breaks [url] search by replacing & with amp
@ -1461,8 +1442,8 @@ class BBCode extends BaseObject
$autolink_regex = "/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism"; $autolink_regex = "/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism";
$text = preg_replace($autolink_regex, '$1[url]$2[/url]', $text); $text = preg_replace($autolink_regex, '$1[url]$2[/url]', $text);
if ($simple_html == 7) { if ($simple_html == 7) {
$text = preg_replace_callback("/\[url\]([$URLSearchString]*)\[\/url\]/ism", 'self::convertUrlForMastodonCallback', $text); $text = preg_replace_callback("/\[url\]([$URLSearchString]*)\[\/url\]/ism", 'self::convertUrlForOStatusCallback', $text);
$text = preg_replace_callback("/\[url\=([$URLSearchString]*)\]([$URLSearchString]*)\[\/url\]/ism", 'self::convertUrlForMastodonCallback', $text); $text = preg_replace_callback("/\[url\=([$URLSearchString]*)\]([$URLSearchString]*)\[\/url\]/ism", 'self::convertUrlForOStatusCallback', $text);
} }
} else { } else {
$text = preg_replace("(\[url\]([$URLSearchString]*)\[\/url\])ism", " $1 ", $text); $text = preg_replace("(\[url\]([$URLSearchString]*)\[\/url\])ism", " $1 ", $text);
@ -1562,10 +1543,8 @@ class BBCode extends BaseObject
if (strpos($text, '[/map]') !== false) { if (strpos($text, '[/map]') !== false) {
$text = preg_replace_callback( $text = preg_replace_callback(
"/\[map\](.*?)\[\/map\]/ism", "/\[map\](.*?)\[\/map\]/ism",
function ($match) { function ($match) use ($simple_html) {
// the extra space in the following line is intentional return str_replace($match[0], '<p class="map">' . Map::byLocation($match[1], $simple_html) . '</p>', $match[0]);
// Whyyy? - @MrPetovan
return str_replace($match[0], '<div class="map" >' . Map::byLocation($match[1]) . '</div>', $match[0]);
}, },
$text $text
); );
@ -1573,16 +1552,14 @@ class BBCode extends BaseObject
if (strpos($text, '[map=') !== false) { if (strpos($text, '[map=') !== false) {
$text = preg_replace_callback( $text = preg_replace_callback(
"/\[map=(.*?)\]/ism", "/\[map=(.*?)\]/ism",
function ($match) { function ($match) use ($simple_html) {
// the extra space in the following line is intentional return str_replace($match[0], '<p class="map">' . Map::byCoordinates(str_replace('/', ' ', $match[1]), $simple_html) . '</p>', $match[0]);
// Whyyy? - @MrPetovan
return str_replace($match[0], '<div class="map" >' . Map::byCoordinates(str_replace('/', ' ', $match[1])) . '</div>', $match[0]);
}, },
$text $text
); );
} }
if (strpos($text, '[map]') !== false) { if (strpos($text, '[map]') !== false) {
$text = preg_replace("/\[map\]/", '<div class="map"></div>', $text); $text = preg_replace("/\[map\]/", '<p class="map"></p>', $text);
} }
// Check for headers // Check for headers
@ -1606,7 +1583,7 @@ class BBCode extends BaseObject
$text = preg_replace("(\[u\](.*?)\[\/u\])ism", '<u>$1</u>', $text); $text = preg_replace("(\[u\](.*?)\[\/u\])ism", '<u>$1</u>', $text);
// Check for strike-through text // Check for strike-through text
$text = preg_replace("(\[s\](.*?)\[\/s\])ism", '<strike>$1</strike>', $text); $text = preg_replace("(\[s\](.*?)\[\/s\])ism", '<s>$1</s>', $text);
// Check for over-line text // Check for over-line text
$text = preg_replace("(\[o\](.*?)\[\/o\])ism", '<span class="overline">$1</span>', $text); $text = preg_replace("(\[o\](.*?)\[\/o\])ism", '<span class="overline">$1</span>', $text);
@ -1629,7 +1606,7 @@ class BBCode extends BaseObject
$text = preg_replace_callback( $text = preg_replace_callback(
"(\[style=(.*?)\](.*?)\[\/style\])ism", "(\[style=(.*?)\](.*?)\[\/style\])ism",
function ($match) { function ($match) {
return "<span style=\"" . self::cleanCss($match[1]) . ";\">" . $match[2] . "</span>"; return "<span style=\"" . HTML::sanitizeCSS($match[1]) . ";\">" . $match[2] . "</span>";
}, },
$text $text
); );
@ -1638,7 +1615,7 @@ class BBCode extends BaseObject
$text = preg_replace_callback( $text = preg_replace_callback(
"(\[class=(.*?)\](.*?)\[\/class\])ism", "(\[class=(.*?)\](.*?)\[\/class\])ism",
function ($match) { function ($match) {
return "<span class=\"" . self::cleanCss($match[1]) . "\">" . $match[2] . "</span>"; return "<span class=\"" . HTML::sanitizeCSS($match[1]) . "\">" . $match[2] . "</span>";
}, },
$text $text
); );
@ -1747,6 +1724,14 @@ class BBCode extends BaseObject
$text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '<img src="$3" style="width: $1px;" >', $text); $text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '<img src="$3" style="width: $1px;" >', $text);
$text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*)\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$3" style="width: $1px;" >', $text); $text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*)\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$3" style="width: $1px;" >', $text);
$text = preg_replace_callback("/\[img\=([$URLSearchString]*)\](.*?)\[\/img\]/ism",
function ($matches) {
$matches[1] = proxy_url($matches[1]);
$matches[2] = htmlspecialchars($matches[2], ENT_COMPAT);
return '<img src="' . $matches[1] . '" alt="' . $matches[2] . '">';
},
$text);
// Images // Images
// [img]pathtoimage[/img] // [img]pathtoimage[/img]
$text = preg_replace_callback( $text = preg_replace_callback(
@ -1843,7 +1828,7 @@ class BBCode extends BaseObject
// start which is always required). Allow desc with a missing summary for compatibility. // start which is always required). Allow desc with a missing summary for compatibility.
if ((x($ev, 'desc') || x($ev, 'summary')) && x($ev, 'start')) { if ((x($ev, 'desc') || x($ev, 'summary')) && x($ev, 'start')) {
$sub = format_event_html($ev, $simple_html); $sub = Event::getHTML($ev, $simple_html);
$text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/ism", '', $text); $text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/ism", '', $text);
$text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/ism", '', $text); $text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/ism", '', $text);
@ -1878,10 +1863,12 @@ class BBCode extends BaseObject
$text = preg_replace_callback("/\[nobb\](.*?)\[\/nobb\]/ism", 'self::unescapeNoparseCallback', $text); $text = preg_replace_callback("/\[nobb\](.*?)\[\/nobb\]/ism", 'self::unescapeNoparseCallback', $text);
$text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", 'self::unescapeNoparseCallback', $text); $text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", 'self::unescapeNoparseCallback', $text);
/// @todo What is the meaning of these lines?
$text = preg_replace('/\[\&amp\;([#a-z0-9]+)\;\]/', '&$1;', $text); $text = preg_replace('/\[\&amp\;([#a-z0-9]+)\;\]/', '&$1;', $text);
$text = preg_replace('/\&\#039\;/', '\'', $text); $text = preg_replace('/\&\#039\;/', '\'', $text);
$text = preg_replace('/\&quot\;/', '"', $text);
// Currently deactivated, it made problems with " inside of alt texts.
//$text = preg_replace('/\&quot\;/', '"', $text);
// fix any escaped ampersands that may have been converted into links // fix any escaped ampersands that may have been converted into links
$text = preg_replace('/\<([^>]*?)(src|href)=(.*?)\&amp\;(.*?)\>/ism', '<$1$2=$3&$4>', $text); $text = preg_replace('/\<([^>]*?)(src|href)=(.*?)\&amp\;(.*?)\>/ism', '<$1$2=$3&$4>', $text);

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