mirror of
https://github.com/YunoHost-Apps/hubzilla_ynh.git
synced 2024-09-03 19:26:21 +02:00
commit
ca18e08f9d
370 changed files with 80521 additions and 45846 deletions
|
@ -14,5 +14,5 @@ Before installing, read the [Hubzilla installation instructions](https://github.
|
|||
|
||||
Current snapshot in *sources*:
|
||||
|
||||
* https://github.com/redmatrix/hubzilla: 1.2
|
||||
* https://github.com/redmatrix/hubzilla-addons: 1.2
|
||||
* https://github.com/redmatrix/hubzilla: 1.3.1
|
||||
* https://github.com/redmatrix/hubzilla-addons: 1.3.1
|
||||
|
|
164
sources/.homeinstall/README.md
Normal file
164
sources/.homeinstall/README.md
Normal file
|
@ -0,0 +1,164 @@
|
|||
# Hubzilla at Home next to your Router
|
||||
|
||||
Run hubzilla-setup.sh for an unattended installation of hubzilla.
|
||||
|
||||
The script is known to work with Debian 8.3 stable (Jessie)
|
||||
|
||||
+ Home-PC (Debian-8.3.0-amd64)
|
||||
+ DigitalOcean droplet (Debian 8.3 x64 / 512 MB Memory / 20 GB Disk / NYC3)
|
||||
|
||||
# Step-by-Step Overwiew
|
||||
|
||||
## Preconditions
|
||||
|
||||
Hardware
|
||||
|
||||
+ Internet connection and router at home
|
||||
+ Mini-pc connected to your router
|
||||
+ USB drive for backups
|
||||
|
||||
Software
|
||||
|
||||
+ Fresh installation of Debian on your mini-pc
|
||||
+ Router with open ports 80 and 443 for your Debian
|
||||
|
||||
## The basic steps (quick overview)
|
||||
|
||||
+ Register your own domain (for example at selfHOST) or a free subdomain (for example at freeDNS)
|
||||
+ Log on to your new debian (server)
|
||||
- apt-get install git
|
||||
- mkdir -p /var/www/html
|
||||
- cd /var/www/html
|
||||
- git clone https://github.com/redmatrix/hubzilla.git .
|
||||
- cp .homeinstall/hubzilla-config.txt.template .homeinstall/hubzilla-config.txt
|
||||
- nano .homeinstall/hubzilla-config.txt
|
||||
- Enter your values there: db pass, domain, values for dyn DNS
|
||||
- hubzilla-setup.sh as root
|
||||
- ... wait, wait, wait until the script is finised
|
||||
- reboot
|
||||
+ Open your domain with a browser and step throught the initial configuration of hubzilla.
|
||||
|
||||
# Step-by-Step in Detail
|
||||
|
||||
## Preparations Hardware
|
||||
|
||||
### Mini-PC
|
||||
|
||||
### Recommended: USB Drive for Backups
|
||||
|
||||
The installation will create a daily backup.
|
||||
|
||||
If the backup process does not find an external device than the backup goes to
|
||||
the internal disk.
|
||||
|
||||
The USB drive must be compatible with an encrpyted filesystem LUKS + ext4.
|
||||
|
||||
## Preparations Software
|
||||
|
||||
### Install Debian Linux on the Mini-PC
|
||||
|
||||
Download the stable Debian at https://www.debian.org/
|
||||
|
||||
Create bootable USB drive with Debian on it. You could use the programm
|
||||
unetbootin, https://en.wikipedia.org/wiki/UNetbootin
|
||||
|
||||
Switch of your mini pc, plug in your USB drive and start the mini pc from the
|
||||
stick. Install Debian. Follow the instructions of the installation.
|
||||
|
||||
### Configure your Router
|
||||
|
||||
Open the ports 80 and 443 on your router for your Debian
|
||||
|
||||
## Preparations Dynamic IP Address
|
||||
|
||||
Your Hubzilla must be reachable by a domain that you can type in your browser
|
||||
|
||||
cooldomain.org
|
||||
|
||||
You can use subdomains as well
|
||||
|
||||
my.cooldomain.org
|
||||
|
||||
There are two way to get a domain
|
||||
|
||||
- buy a domain (recommended) or
|
||||
- register a free subdomain
|
||||
|
||||
### Method 1: Get yourself an own Domain (recommended)
|
||||
|
||||
...for example at selfHOST.de
|
||||
|
||||
### Method 2 Register a (free) Subdomain
|
||||
|
||||
Register a free subdomain for example at
|
||||
|
||||
- freeDNS
|
||||
- selfHOST
|
||||
|
||||
WATCH THIS: A free subdomain is not the prefered way to get a domain name. Why?
|
||||
|
||||
Let's encrpyt issues a limited number of certificates each
|
||||
day. Possibly other users of this domain will try to issue a certificate
|
||||
at the same day as you do. So make sure you choose a domain with as less subdomains as
|
||||
possible.
|
||||
|
||||
## Install Hubzilla on your Debian
|
||||
|
||||
Login to your debian
|
||||
(Provided your username is "you" and the name of the mini pc is "debian". You
|
||||
could take the IP address instead of "debian")
|
||||
|
||||
ssh -X you@debian
|
||||
|
||||
Change to root user
|
||||
|
||||
su -l
|
||||
|
||||
Install git
|
||||
|
||||
apt-get install git
|
||||
|
||||
Make the directory for apache and change diretory to it
|
||||
|
||||
mkdir /var/www
|
||||
cd /var/www/
|
||||
|
||||
Clone hubzilla from git ("git pull" will update it later)
|
||||
|
||||
git clone https://github.com/redmatrix/hubzilla html
|
||||
|
||||
Change to the install script
|
||||
|
||||
cd html/.homeinstall/
|
||||
|
||||
Copy the template file
|
||||
|
||||
cp hubzilla-config.txt.template hubzilla-config.txt
|
||||
|
||||
Change the file "hubzilla-config.txt". Read the instructions there and enter your values.
|
||||
|
||||
nano hubzilla-config.txt
|
||||
|
||||
Run the script
|
||||
|
||||
./hubzilla-setup.sh
|
||||
|
||||
Wait... The script should not finish with an error message.
|
||||
|
||||
In a webbrowser open your domain.
|
||||
Expected: A test page of hubzilla is shown. All checks there shoulg be
|
||||
successfull. Go on...
|
||||
Expected: A page for the Hubzilla server configuration shows up.
|
||||
|
||||
Leave db server name "127.0.0.1" and port "0" untouched.
|
||||
|
||||
Enter
|
||||
|
||||
- DB user name = hubzilla
|
||||
- DB pass word = This is the password you entered in "hubzilla-config.txt"
|
||||
- DB name = hubzilla
|
||||
|
||||
Leave db type "MySQL" untouched.
|
||||
|
||||
Follow the instructions in the next pages.
|
||||
|
177
sources/.homeinstall/hubzilla-config.txt.template
Normal file
177
sources/.homeinstall/hubzilla-config.txt.template
Normal file
|
@ -0,0 +1,177 @@
|
|||
###############################################
|
||||
### MANDATORY - database password #############
|
||||
#
|
||||
# Please give your database password
|
||||
# Example: db_pass=pass_word_with_no_blanks_in_it
|
||||
# Example: db_pass="this password has blanks in it"
|
||||
db_pass=
|
||||
|
||||
###############################################
|
||||
### MANDATORY - let's encrypt #################
|
||||
#
|
||||
# Hubilla requires encrypted communication via secure HTTP (HTTPS).
|
||||
# This script automates installation of an SSL certificate from
|
||||
# Let's Encrypt (https://letsencrypt.org)
|
||||
#
|
||||
# Please give the domain name of your hub
|
||||
#
|
||||
# Example: my.cooldomain.org
|
||||
# Example: cooldomain.org
|
||||
#
|
||||
# Email is optional
|
||||
#
|
||||
#
|
||||
le_domain=
|
||||
le_email=
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - selfHOST - dynamic IP address ##
|
||||
#
|
||||
# 1. Register a domain at selfhost.de
|
||||
# - choose offer "DOMAIN dynamisch" 1,50€/mon at 08.01.2016
|
||||
# 2. Get your configuration for dynamic IP update
|
||||
# - Log in at selfhost.de
|
||||
# - go to "DynDNS Accounte"
|
||||
# - klick "Details" of your (freshly) registered domain
|
||||
# - You will find the configuration there
|
||||
# - Benutzername (user name) > use this for "selfhost_user="
|
||||
# - Passwort (pass word) > use this for "selfhost_pass="
|
||||
#
|
||||
#
|
||||
selfhost_user=
|
||||
selfhost_pass=
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - FreeDNS - dynamic IP address ###
|
||||
#
|
||||
# Please give the alpha-numeric-key of freedns
|
||||
#
|
||||
# Get a free subdomain from freedns and use it for your dynamic ip address
|
||||
# Documentation under http://www.techjawab.com/2013/06/setup-dynamic-dns-dyndns-for-free-on.html
|
||||
#
|
||||
# - Register for a Free domain at http://freedns.afraid.org/signup/
|
||||
# - WATCH THIS: Make sure you choose a domain with as less subdomains as
|
||||
# possible. Why? Let's encrpyt issues a limited count of certificates each
|
||||
# day. Possible other users of this domain will try to issue a certificate
|
||||
# at the same day.
|
||||
# - Logon to FreeDNS (where you just registered)
|
||||
# - Goto http://freedns.afraid.org/dynamic/
|
||||
# - Right click on "Direct Link" and copy the URL and paste it somewhere.
|
||||
# - You should notice a large and unique alpha-numeric key in the URL
|
||||
#
|
||||
# http://freedns.afraid.org/dynamic/update.php?alpha-numeric-key
|
||||
#
|
||||
# Provided your url from freedns is
|
||||
#
|
||||
# http://freedns.afraid.org/dynamic/update.php?U1Z6aGt2R0NzMFNPNWRjbWxxZGpsd093OjE1Mzg5NDE5
|
||||
#
|
||||
# Then you have to provide
|
||||
#
|
||||
# freedns_key=U1Z6aGt2R0NzMFNPNWRjbWxxZGpsd093OjE1Mzg5NDE5
|
||||
#
|
||||
#
|
||||
#freedns_key=
|
||||
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - Backup to external device ######
|
||||
#
|
||||
# The script can use an external device for the daily backup.
|
||||
# The file system of the device (USB stick for example) must be compatible
|
||||
# with encrypted LUKS + ext4
|
||||
#
|
||||
# You should test to mount the device befor you run the script
|
||||
# (hubzilla-setup.sh).
|
||||
# How to find your (pluged-in) devices?
|
||||
#
|
||||
# fdisk -l
|
||||
#
|
||||
# Provided your device was listed as is /dev/sdb1. You could check with:
|
||||
#
|
||||
# blkid | grep /dev/sdb1
|
||||
#
|
||||
# Try to decrypt
|
||||
# (You might install cryptsetup befor using apt-get install.
|
||||
#
|
||||
# apt-get install cryptsetup
|
||||
# cryptsetup luksOpen /dev/sdb1 cryptobackup
|
||||
#
|
||||
# Try to mount
|
||||
# You might create the directory /media/hubzilla_backup it it does not exist
|
||||
# using mkdir.
|
||||
#
|
||||
# mkdir /media/hubzilla_backup
|
||||
# mount /dev/mapper/cryptobackup /media/hubzilla_backup
|
||||
#
|
||||
# Unmounting device goes like this
|
||||
#
|
||||
# umount /media/hubzilla_backup
|
||||
# cryptsetup luksClose cryptobackup
|
||||
#
|
||||
# To check if still mounted
|
||||
#
|
||||
# lsof /media/hubzilla_backup
|
||||
#
|
||||
# If you leave the following parameters
|
||||
# - "backup_device_name" and
|
||||
# - "backup_device_pass"
|
||||
# empty the script will create daily backups on the internal disk (which could
|
||||
# save you as well).
|
||||
#
|
||||
# Example: backup_device_name=/dev/sdc1
|
||||
#
|
||||
backup_device_name=
|
||||
backup_device_pass=
|
||||
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - Owncloud - deprecated ##########
|
||||
#
|
||||
# To install owncloud: owncloud=y
|
||||
# Leave empty if you don't want to install owncloud
|
||||
#
|
||||
#owncloud=
|
||||
|
||||
|
||||
|
||||
###############################################
|
||||
### OPTIONAL - do not mess with things below ##
|
||||
# (...if you are not certain)
|
||||
#
|
||||
# Usually you are done here
|
||||
# Everything below is OPTIONAL
|
||||
#
|
||||
###############################################
|
||||
#
|
||||
# Database for hubzilla
|
||||
hubzilla_db_name=hubzilla
|
||||
hubzilla_db_user=hubzilla
|
||||
hubzilla_db_pass=$db_pass
|
||||
#
|
||||
#
|
||||
# Password for package mysql-server
|
||||
# Example: mysqlpass=aberhallo
|
||||
# Example: mysqlpass="aber hallo has blanks in it"
|
||||
#
|
||||
mysqlpass=$db_pass
|
||||
|
||||
# Password for package phpmyadmin
|
||||
# Example: phpmyadminpass=aberhallo
|
||||
# Example: phpmyadminpass="aber hallo has blanks in it"
|
||||
phpmyadminpass=$db_pass
|
||||
|
||||
# TODO Prepare hubzilla for programmers
|
||||
# - install eclipse and plugins
|
||||
# - install xdebug to debug the php with eclipse
|
||||
# - weaken permissions on /var/www/html
|
||||
# - manual steps after this script
|
||||
# * in eclipse: install plugins for php git hub
|
||||
# * in eclipse: configure firefox (chrome,...) as browser to run with the php debuger
|
||||
# * in eclipse: switch php debugger from zend to xdebug
|
||||
# * in eclipse: add local hubzilla github repository
|
||||
#
|
||||
# Which user will use eclipse?
|
||||
# Leave this empty if you do not want to prepare hubzilla for debugging
|
||||
#
|
||||
#developer_name=
|
||||
|
949
sources/.homeinstall/hubzilla-setup.sh
Executable file
949
sources/.homeinstall/hubzilla-setup.sh
Executable file
|
@ -0,0 +1,949 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# How to use
|
||||
# ----------
|
||||
#
|
||||
# This file automates the installation of hubzilla under Debian Linux
|
||||
#
|
||||
# 1) Copy the file "hubzilla-config.txt.template" to "hubzilla-config.txt"
|
||||
# Follow the instuctions there
|
||||
#
|
||||
# 2) Switch to user "root" by typing "su -"
|
||||
#
|
||||
# 3) Run with "./hubzilla-setup.sh"
|
||||
# If this fails check if you can execute the script.
|
||||
# - To make it executable type "chmod +x hubzilla-setup.sh"
|
||||
# - or run "bash hubzilla-setup.sh"
|
||||
#
|
||||
#
|
||||
# What does this script do basically?
|
||||
# -----------------------------------
|
||||
#
|
||||
# This file automates the installation of hubzilla under Debian Linux
|
||||
# - install
|
||||
# * apache webserer,
|
||||
# * php,
|
||||
# * mysql - the database for hubzilla,
|
||||
# * phpmyadmin,
|
||||
# * git to download and update hubzilla itself
|
||||
# - download hubzilla core and addons
|
||||
# - configure cron
|
||||
# * "poller.php" for regular background prozesses of hubzilla
|
||||
# * to_do "apt-get update" and "apt-get dist-upgrade" to keep linux
|
||||
# up-to-date
|
||||
# * to_do backup hubzillas database and files (rsnapshot)
|
||||
# - configure dynamic ip with cron
|
||||
# - to_do letsencrypt
|
||||
# - to_do redirection to https
|
||||
#
|
||||
#
|
||||
# Discussion
|
||||
# ----------
|
||||
#
|
||||
# Security - password is the same for mysql-server, phpmyadmin and hubzilla db
|
||||
# - The script runs into installation errors for phpmyadmin if it uses
|
||||
# different passwords. For the sake of simplicity one singel password.
|
||||
#
|
||||
# Security - suhosin for PHP
|
||||
# - The script does not install suhosin.
|
||||
# - Is the security package suhosin usefull or not usefull?
|
||||
#
|
||||
# Hubzilla - email verification
|
||||
# - The script switches off email verification off in all htconfig.tpl.
|
||||
# Example: /var/www/html/view/en/htconfig.tpl
|
||||
# - Is this a silly idea or not?
|
||||
#
|
||||
#
|
||||
# Remove Hubzilla (for a fresh start using the script)
|
||||
# ----------------------------------------------------
|
||||
#
|
||||
# You could use /var/www/hubzilla-remove.sh
|
||||
# that is created by hubzilla-setup.sh.
|
||||
#
|
||||
# The script will remove (almost everything) what was installed by the script.
|
||||
# After the removal you could run the script again to have a fresh install
|
||||
# of all applications including hubzilla and its database.
|
||||
#
|
||||
# How to restore from backup
|
||||
# --------------------------
|
||||
#
|
||||
# Daily backup
|
||||
# - - - - - -
|
||||
#
|
||||
# The installation
|
||||
# - writes a script /var/www/hubzilla-daily.sh
|
||||
# - creates a daily cron that runs the hubzilla-daily.sh
|
||||
#
|
||||
# hubzilla-daily.sh makes a (daily) backup of all relevant files
|
||||
# - /var/lib/mysql/ > hubzilla database
|
||||
# - /var/www/html/ > hubzilla from github
|
||||
# - /var/www/letsencrypt/ > certificates
|
||||
#
|
||||
# hubzilla-daily.sh writes the backup
|
||||
# - either to an external disk compatible to LUKS+ext4 (see hubzilla-config.txt)
|
||||
# - or to /var/cache/rsnapshot in case the external disk is not plugged in
|
||||
#
|
||||
# Restore backup
|
||||
# - - - - - - -
|
||||
#
|
||||
# This was not tested yet.
|
||||
# Bacically you can copy the files from the backup to the server.
|
||||
#
|
||||
# Credits
|
||||
# -------
|
||||
#
|
||||
# The script is based on Thomas Willinghams script "debian-setup.sh"
|
||||
# which he used to install the red#matrix.
|
||||
#
|
||||
# The script uses another script from https://github.com/lukas2511/letsencrypt.sh
|
||||
#
|
||||
# The documentation for bash is here
|
||||
# https://www.gnu.org/software/bash/manual/bash.html
|
||||
#
|
||||
function check_sanity {
|
||||
# Do some sanity checking.
|
||||
print_info "Sanity check..."
|
||||
if [ $(/usr/bin/id -u) != "0" ]
|
||||
then
|
||||
die 'Must be run by root user'
|
||||
fi
|
||||
|
||||
if [ -f /etc/lsb-release ]
|
||||
then
|
||||
die "Distribution is not supported"
|
||||
fi
|
||||
if [ ! -f /etc/debian_version ]
|
||||
then
|
||||
die "Ubuntu is not supported"
|
||||
fi
|
||||
}
|
||||
|
||||
function check_config {
|
||||
print_info "config check..."
|
||||
# Check for required parameters
|
||||
if [ -z "$db_pass" ]
|
||||
then
|
||||
die "db_pass not set in $configfile"
|
||||
fi
|
||||
if [ -z "$le_domain" ]
|
||||
then
|
||||
die "le_domain not set in $configfile"
|
||||
fi
|
||||
# backup is important and should be checked
|
||||
if [ -n "$backup_device_name" ]
|
||||
then
|
||||
device_mounted=0
|
||||
if fdisk -l | grep -i "$backup_device_name.*linux"
|
||||
then
|
||||
print_info "ok - filesystem of external device is linux"
|
||||
if [ -n "$backup_device_pass" ]
|
||||
then
|
||||
echo "$backup_device_pass" | cryptsetup luksOpen $backup_device_name cryptobackup
|
||||
if [ ! -d /media/hubzilla_backup ]
|
||||
then
|
||||
mkdir /media/hubzilla_backup
|
||||
fi
|
||||
if mount /dev/mapper/cryptobackup /media/hubzilla_backup
|
||||
then
|
||||
device_mounted=1
|
||||
print_info "ok - could encrypt and mount external backup device"
|
||||
umount /media/hubzilla_backup
|
||||
else
|
||||
print_warn "backup to external device will fail because encryption failed"
|
||||
fi
|
||||
cryptsetup luksClose cryptobackup
|
||||
else
|
||||
if mount $backup_device_name /media/hubzilla_backup
|
||||
then
|
||||
device_mounted=1
|
||||
print_info "ok - could mount external backup device"
|
||||
umount /media/hubzilla_backup
|
||||
else
|
||||
print_warn "backup to external device will fail because mount failed"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
print_warn "backup to external device will fail because filesystem is either not linux or 'backup_device_name' is not correct in $configfile"
|
||||
fi
|
||||
if [ $device_mounted == 0 ]
|
||||
then
|
||||
die "backup device not ready"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function die {
|
||||
echo "ERROR: $1" > /dev/null 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
function update_upgrade {
|
||||
print_info "updated and upgrade..."
|
||||
# Run through the apt-get update/upgrade first. This should be done before
|
||||
# we try to install any package
|
||||
apt-get -q -y update && apt-get -q -y dist-upgrade
|
||||
print_info "updated and upgraded linux"
|
||||
}
|
||||
|
||||
function check_install {
|
||||
if [ -z "`which "$1" 2>/dev/null`" ]
|
||||
then
|
||||
# export DEBIAN_FRONTEND=noninteractive ... answers from the package
|
||||
# configuration database
|
||||
# - q ... without progress information
|
||||
# - y ... answer interactive questions with "yes"
|
||||
# DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends -q -y install $2
|
||||
DEBIAN_FRONTEND=noninteractive apt-get -q -y install $2
|
||||
print_info "installed $2 installed for $1"
|
||||
else
|
||||
print_warn "$2 already installed"
|
||||
fi
|
||||
}
|
||||
|
||||
function nocheck_install {
|
||||
# export DEBIAN_FRONTEND=noninteractive ... answers from the package configuration database
|
||||
# - q ... without progress information
|
||||
# - y ... answer interactive questions with "yes"
|
||||
# DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends -q -y install $2
|
||||
# DEBIAN_FRONTEND=noninteractive apt-get --install-suggests -q -y install $1
|
||||
DEBIAN_FRONTEND=noninteractive apt-get -q -y install $1
|
||||
print_info "installed $1"
|
||||
}
|
||||
|
||||
|
||||
function print_info {
|
||||
echo -n -e '\e[1;34m'
|
||||
echo -n $1
|
||||
echo -e '\e[0m'
|
||||
}
|
||||
|
||||
function print_warn {
|
||||
echo -n -e '\e[1;31m'
|
||||
echo -n $1
|
||||
echo -e '\e[0m'
|
||||
}
|
||||
|
||||
function stop_hubzilla {
|
||||
if [ -d /etc/apache2 ]
|
||||
then
|
||||
print_info "stopping apache webserver..."
|
||||
service apache2 stop
|
||||
fi
|
||||
if [ -f /etc/init.d/mysql ]
|
||||
then
|
||||
print_info "stopping mysql db..."
|
||||
/etc/init.d/mysql stop
|
||||
fi
|
||||
}
|
||||
|
||||
function install_apache {
|
||||
print_info "installing apache..."
|
||||
nocheck_install "apache2 apache2-utils"
|
||||
}
|
||||
|
||||
function install_curl {
|
||||
print_info "installing curl..."
|
||||
nocheck_install "curl"
|
||||
}
|
||||
|
||||
function install_sendmail {
|
||||
print_info "installing sendmail..."
|
||||
nocheck_install "sendmail sendmail-bin"
|
||||
}
|
||||
|
||||
function install_php {
|
||||
# openssl and mbstring are included in libapache2-mod-php5
|
||||
# to_to: php5-suhosin
|
||||
print_info "installing php..."
|
||||
nocheck_install "libapache2-mod-php5 php5 php-pear php5-xcache php5-curl php5-mcrypt php5-gd"
|
||||
php5enmod mcrypt
|
||||
}
|
||||
|
||||
function install_mysql {
|
||||
# http://www.microhowto.info/howto/perform_an_unattended_installation_of_a_debian_package.html
|
||||
#
|
||||
# To determine the required package name, key and type you can perform
|
||||
# a trial installation then search the configuration database.
|
||||
#
|
||||
# debconf-get-selections | grep mysql-server
|
||||
#
|
||||
# The command debconf-get-selections is provided by the package
|
||||
# debconf-utils, which you may need to install.
|
||||
#
|
||||
# apt-get install debconf-utils
|
||||
#
|
||||
# If you want to supply an answer to a configuration question but do not
|
||||
# want to be prompted for it then this can be arranged by preseeding the
|
||||
# DebConf database with the required information.
|
||||
#
|
||||
# echo mysql-server-5.5 mysql-server/root_password password xyzzy | debconf-set-selections
|
||||
# echo mysql-server-5.5 mysql-server/root_password_again password xyzzy | debconf-set-selections
|
||||
#
|
||||
print_info "installing mysql..."
|
||||
if [ -z "$mysqlpass" ]
|
||||
then
|
||||
die "mysqlpass not set in $configfile"
|
||||
fi
|
||||
echo mysql-server-5.5 mysql-server/root_password password $mysqlpass | debconf-set-selections
|
||||
echo mysql-server-5.5 mysql-server/root_password_again password $mysqlpass | debconf-set-selections
|
||||
nocheck_install "php5-mysql mysql-server mysql-client"
|
||||
php5enmod mcrypt
|
||||
}
|
||||
|
||||
function install_phpmyadmin {
|
||||
print_info "installing phpmyadmin..."
|
||||
if [ -z "$phpmyadminpass" ]
|
||||
then
|
||||
die "phpmyadminpass not set in $configfile"
|
||||
fi
|
||||
echo phpmyadmin phpmyadmin/setup-password password $phpmyadminpass | debconf-set-selections
|
||||
echo phpmyadmin phpmyadmin/mysql/app-pass password $phpmyadminpass | debconf-set-selections
|
||||
echo phpmyadmin phpmyadmin/app-password-confirm password $phpmyadminpass | debconf-set-selections
|
||||
echo phpmyadmin phpmyadmin/mysql/admin-pass password $phpmyadminpass | debconf-set-selections
|
||||
echo phpmyadmin phpmyadmin/password-confirm password $phpmyadminpass | debconf-set-selections
|
||||
echo phpmyadmin phpmyadmin/reconfigure-webserver multiselect apache2 | debconf-set-selections
|
||||
nocheck_install "phpmyadmin"
|
||||
|
||||
# It seems to be not neccessary to check rewrite.load because it comes
|
||||
# with the installation. To be sure you could check this manually by:
|
||||
#
|
||||
# nano /etc/apache2/mods-available/rewrite.load
|
||||
#
|
||||
# You should find the content:
|
||||
#
|
||||
# LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so
|
||||
|
||||
a2enmod rewrite
|
||||
if [ ! -f /etc/apache2/apache2.conf ]
|
||||
then
|
||||
die "could not find file /etc/apache2/apache2.conf"
|
||||
fi
|
||||
sed -i \
|
||||
"s/AllowOverride None/AllowOverride all/" \
|
||||
/etc/apache2/apache2.conf
|
||||
if [ -z "`grep 'Include /etc/phpmyadmin/apache.conf' /etc/apache2/apache2.conf`" ]
|
||||
then
|
||||
echo "Include /etc/phpmyadmin/apache.conf" >> /etc/apache2/apache2.conf
|
||||
fi
|
||||
service apache2 restart
|
||||
}
|
||||
|
||||
function create_hubzilla_db {
|
||||
print_info "creating hubzilla database..."
|
||||
if [ -z "$hubzilla_db_name" ]
|
||||
then
|
||||
die "hubzilla_db_name not set in $configfile"
|
||||
fi
|
||||
if [ -z "$hubzilla_db_user" ]
|
||||
then
|
||||
die "hubzilla_db_user not set in $configfile"
|
||||
fi
|
||||
if [ -z "$hubzilla_db_pass" ]
|
||||
then
|
||||
die "hubzilla_db_pass not set in $configfile"
|
||||
fi
|
||||
Q1="CREATE DATABASE IF NOT EXISTS $hubzilla_db_name;"
|
||||
Q2="GRANT USAGE ON *.* TO $hubzilla_db_user@localhost IDENTIFIED BY '$hubzilla_db_pass';"
|
||||
Q3="GRANT ALL PRIVILEGES ON $hubzilla_db_name.* to $hubzilla_db_user@localhost identified by '$hubzilla_db_pass';"
|
||||
Q4="FLUSH PRIVILEGES;"
|
||||
SQL="${Q1}${Q2}${Q3}${Q4}"
|
||||
mysql -uroot -p$phpmyadminpass -e "$SQL"
|
||||
}
|
||||
|
||||
function run_freedns {
|
||||
print_info "run freedns (dynamic IP)..."
|
||||
if [ -z "$freedns_key" ]
|
||||
then
|
||||
print_info "freedns was not started because 'freedns_key' is empty in $configfile"
|
||||
else
|
||||
if [ -n "$selfhost_user" ]
|
||||
then
|
||||
die "You can not use freeDNS AND selfHOST for dynamic IP updates ('freedns_key' AND 'selfhost_user' set in $configfile)"
|
||||
fi
|
||||
wget --no-check-certificate -O - https://freedns.afraid.org/dynamic/update.php?$freedns_key
|
||||
fi
|
||||
}
|
||||
|
||||
function install_run_selfhost {
|
||||
print_info "install and start selfhost (dynamic IP)..."
|
||||
if [ -z "$selfhost_user" ]
|
||||
then
|
||||
print_info "selfHOST was not started because 'selfhost_user' is empty in $configfile"
|
||||
else
|
||||
if [ -n "$freedns_key" ]
|
||||
then
|
||||
die "You can not use freeDNS AND selfHOST for dynamic IP updates ('freedns_key' AND 'selfhost_user' set in $configfile)"
|
||||
fi
|
||||
if [ -z "$selfhost_pass" ]
|
||||
then
|
||||
die "selfHOST was not started because 'selfhost_pass' is empty in $configfile"
|
||||
fi
|
||||
if [ ! -d $selfhostdir ]
|
||||
then
|
||||
mkdir $selfhostdir
|
||||
fi
|
||||
# the old way
|
||||
# https://carol.selfhost.de/update?username=123456&password=supersafe
|
||||
#
|
||||
# the prefered way
|
||||
wget --output-document=$selfhostdir/$selfhostscript http://jonaspasche.de/selfhost-updater
|
||||
echo "router" > $selfhostdir/device
|
||||
echo "$selfhost_user" > $selfhostdir/user
|
||||
echo "$selfhost_pass" > $selfhostdir/pass
|
||||
bash $selfhostdir/$selfhostscript update
|
||||
fi
|
||||
}
|
||||
|
||||
function ping_domain {
|
||||
print_info "ping domain $domain..."
|
||||
# Is the domain resolved? Try to ping 6 times à 10 seconds
|
||||
COUNTER=0
|
||||
for i in {1..6}
|
||||
do
|
||||
print_info "loop $i for ping -c 1 $domain ..."
|
||||
if ping -c 4 -W 1 $le_domain
|
||||
then
|
||||
print_info "$le_domain resolved"
|
||||
break
|
||||
else
|
||||
if [ $i -gt 5 ]
|
||||
then
|
||||
die "Failed to: ping -c 1 $domain not resolved"
|
||||
fi
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
sleep 5
|
||||
}
|
||||
|
||||
function configure_cron_freedns {
|
||||
print_info "configure cron for freedns..."
|
||||
if [ -z "$freedns_key" ]
|
||||
then
|
||||
print_info "freedns is not configured because freedns_key is empty in $configfile"
|
||||
else
|
||||
# Use cron for dynamich ip update
|
||||
# - at reboot
|
||||
# - every 30 minutes
|
||||
if [ -z "`grep 'freedns.afraid.org' /etc/crontab`" ]
|
||||
then
|
||||
echo "@reboot root https://freedns.afraid.org/dynamic/update.php?$freedns_key > /dev/null 2>&1" >> /etc/crontab
|
||||
echo "*/30 * * * * root wget --no-check-certificate -O - https://freedns.afraid.org/dynamic/update.php?$freedns_key > /dev/null 2>&1" >> /etc/crontab
|
||||
else
|
||||
print_info "cron for freedns was configured already"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function configure_cron_selfhost {
|
||||
print_info "configure cron for selfhost..."
|
||||
if [ -z "$selfhost_user" ]
|
||||
then
|
||||
print_info "freedns is not configured because freedns_key is empty in $configfile"
|
||||
else
|
||||
# Use cron for dynamich ip update
|
||||
# - at reboot
|
||||
# - every 30 minutes
|
||||
if [ -z "`grep 'selfhost-updater.sh' /etc/crontab`" ]
|
||||
then
|
||||
echo "@reboot root bash /etc/selfhost/selfhost-updater.sh update > /dev/null 2>&1" >> /etc/crontab
|
||||
echo "*/5 * * * * root /bin/bash /etc/selfhost/selfhost-updater.sh update > /dev/null 2>&1" >> /etc/crontab
|
||||
else
|
||||
print_info "cron for selfhost was configured already"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function install_git {
|
||||
print_info "installing git..."
|
||||
nocheck_install "git"
|
||||
}
|
||||
|
||||
function install_letsencrypt {
|
||||
print_info "installing let's encrypt ..."
|
||||
# check if user gave domain
|
||||
if [ -z "$le_domain" ]
|
||||
then
|
||||
die "Failed to install let's encrypt: 'le_domain' is empty in $configfile"
|
||||
fi
|
||||
# configure apache
|
||||
apache_le_conf=/etc/apache2/sites-available/le-default.conf
|
||||
if [ -f $apache_le_conf ]
|
||||
then
|
||||
print_info "$apache_le_conf exist already"
|
||||
else
|
||||
cat > $apache_le_conf <<END
|
||||
# letsencrypt default Apache configuration
|
||||
Alias /.well-known/acme-challenge /var/www/letsencrypt
|
||||
|
||||
<Directory /var/www/letsencrypt>
|
||||
Options FollowSymLinks
|
||||
Allow from all
|
||||
</Directory>
|
||||
END
|
||||
a2ensite le-default.conf
|
||||
service apache2 restart
|
||||
fi
|
||||
# download the shell script
|
||||
if [ -d $le_dir ]
|
||||
then
|
||||
print_info "letsenrypt exists already (nothing downloaded > no certificate created and registered)"
|
||||
return 0
|
||||
fi
|
||||
git clone https://github.com/lukas2511/letsencrypt.sh $le_dir
|
||||
cd $le_dir
|
||||
# create config file for letsencrypt.sh
|
||||
echo "WELLKNOWN=$le_dir" > $le_dir/config.sh
|
||||
if [ -n "$le_email" ]
|
||||
then
|
||||
echo "CONTACT_EMAIL=$le_email" >> $le_dir/config.sh
|
||||
fi
|
||||
# create domain file for letsencrypt.sh
|
||||
# WATCH THIS:
|
||||
# - It did not work wit "sub.domain.org www.sub.domain.org".
|
||||
# - So just use "sub.domain.org" only!
|
||||
echo "$le_domain" > $le_dir/domains.txt
|
||||
# test apache config for letsencrpyt
|
||||
url_http=http://$le_domain/.well-known/acme-challenge/domains.txt
|
||||
wget_output=$(wget -nv --spider --max-redirect 0 $url_http)
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
die "Failed to load $url_http"
|
||||
fi
|
||||
# run letsencrypt.sh
|
||||
#
|
||||
./letsencrypt.sh --cron
|
||||
}
|
||||
|
||||
function configure_apache_for_https {
|
||||
print_info "configuring apache to use httpS ..."
|
||||
# letsencrypt.sh
|
||||
#
|
||||
# "${BASEDIR}/certs/${domain}/privkey.pem"
|
||||
# "${BASEDIR}/certs/${domain}/cert.pem"
|
||||
# "${BASEDIR}/certs/${domain}/fullchain.pem"
|
||||
#
|
||||
SSLCertificateFile=${le_dir}/certs/${le_domain}/cert.pem
|
||||
SSLCertificateKeyFile=${le_dir}/certs/${le_domain}/privkey.pem
|
||||
SSLCertificateChainFile=${le_dir}/certs/${le_domain}/fullchain.pem
|
||||
if [ ! -f $SSLCertificateFile ]
|
||||
then
|
||||
print_warn "Failed to configure apache for httpS: Missing certificate file $SSLCertificateFile"
|
||||
return 0
|
||||
fi
|
||||
# make sure that the ssl mode is enabled
|
||||
print_info "...configuring apache to use httpS - a2enmod ssl ..."
|
||||
a2enmod ssl
|
||||
# modify apach' ssl conf file
|
||||
if grep -i "ServerName" $sslconf
|
||||
then
|
||||
print_info "seems that apache was already configered to use httpS with $sslconf"
|
||||
else
|
||||
sed -i "s/ServerAdmin.*$/ServerAdmin webmaster@localhost\\n ServerName ${le_domain}/" $sslconf
|
||||
fi
|
||||
sed -i s#/etc/ssl/certs/ssl-cert-snakeoil.pem#$SSLCertificateFile# $sslconf
|
||||
sed -i s#/etc/ssl/private/ssl-cert-snakeoil.key#$SSLCertificateKeyFile# $sslconf
|
||||
sed -i s#/etc/apache2/ssl.crt/server-ca.crt#$SSLCertificateChainFile# $sslconf
|
||||
sed -i s/#SSLCertificateChainFile/SSLCertificateChainFile/ $sslconf
|
||||
# apply changes
|
||||
a2ensite default-ssl.conf
|
||||
service apache2 restart
|
||||
}
|
||||
|
||||
function check_https {
|
||||
print_info "checking httpS > testing ..."
|
||||
url_https=https://$le_domain
|
||||
wget_output=$(wget -nv --spider --max-redirect 0 $url_https)
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
print_warn "check not ok"
|
||||
else
|
||||
print_info "check ok"
|
||||
fi
|
||||
}
|
||||
|
||||
function install_hubzilla {
|
||||
print_info "installing hubzilla..."
|
||||
# rm -R /var/www/html/ # for "stand alone" usage
|
||||
cd /var/www/
|
||||
# git clone https://github.com/redmatrix/hubzilla html # for "stand alone" usage
|
||||
cd html/
|
||||
git clone https://github.com/redmatrix/hubzilla-addons addon
|
||||
mkdir -p "store/[data]/smarty3"
|
||||
chmod -R 777 store
|
||||
touch .htconfig.php
|
||||
chmod ou+w .htconfig.php
|
||||
install_hubzilla_plugins
|
||||
cd /var/www/
|
||||
chown -R www-data:www-data html
|
||||
chown root:www-data /var/www/html/
|
||||
chown root:www-data /var/www/html/.htaccess
|
||||
chmod 0644 /var/www/html/.htaccess
|
||||
# try to switch off email registration
|
||||
sed -i "s/verify_email.*1/verify_email'] = 0/" /var/www/html/view/*/ht*
|
||||
if [ -n "`grep -r 'verify_email.*1' /var/www/html/view/`" ]
|
||||
then
|
||||
print_warn "Hubzillas registration prozess might have email verification switched on."
|
||||
fi
|
||||
print_info "installed hubzilla"
|
||||
}
|
||||
|
||||
function install_hubzilla_plugins {
|
||||
print_info "installing hubzilla plugins..."
|
||||
cd /var/www/html
|
||||
plugin_install=.homeinstall/plugin_install.txt
|
||||
theme_install=.homeinstall/theme_install.txt
|
||||
# overwrite script to update the plugin and themes
|
||||
rm -f $plugins_update
|
||||
echo "cd /var/www/html" >> $plugins_update
|
||||
###################
|
||||
# write plugin file
|
||||
if [ ! -f "$plugin_install" ]
|
||||
then
|
||||
echo "# To install a plugin" >> $plugin_install
|
||||
echo "# 1. add the plugin in a new line and run" >> $plugin_install
|
||||
echo "# 2. run" >> $plugin_install
|
||||
echo "# cd /var/www/html/.homeinstall" >> $plugin_install
|
||||
echo "# ./hubzilla-setup.sh" >> $plugin_install
|
||||
echo "https://gitlab.com/zot/ownmapp.git ownMapp" >> $plugin_install
|
||||
echo "https://gitlab.com/zot/hubzilla-chess.git chess" >> $plugin_install
|
||||
fi
|
||||
# install plugins
|
||||
while read -r line; do
|
||||
[[ "$line" =~ ^#.*$ ]] && continue
|
||||
p_url=$(echo $line | awk -F' ' '{print $1}')
|
||||
p_name=$(echo $line | awk -F' ' '{print $2}')
|
||||
# basic check of format
|
||||
if [ ${#p_url} -ge 1 ] && [ ${#p_name} -ge 1 ]
|
||||
then
|
||||
# install addon
|
||||
util/add_addon_repo $line
|
||||
util/update_addon_repo $p_name # not sure if this line is neccessary
|
||||
echo "util/update_addon_repo $p_name" >> $plugins_update
|
||||
else
|
||||
print_info "skipping installation of a plugin from file $plugin_install - something wrong with format in line: $line"
|
||||
fi
|
||||
done < "$plugin_install"
|
||||
###################
|
||||
# write theme file
|
||||
if [ ! -f "$theme_install" ]
|
||||
then
|
||||
echo "# To install a theme" >> $theme_install
|
||||
echo "# 1. add the theme in a new line and run" >> $theme_install
|
||||
echo "# 2. run" >> $theme_install
|
||||
echo "# cd /var/www/html/.homeinstall" >> $theme_install
|
||||
echo "# ./hubzilla-setup.sh" >> $theme_install
|
||||
echo "https://github.com/DeadSuperHero/hubzilla-themes.git DeadSuperHeroThemes" >> $theme_install
|
||||
|
||||
fi
|
||||
# install plugins
|
||||
while read -r line; do
|
||||
[[ "$line" =~ ^#.*$ ]] && continue
|
||||
p_url=$(echo $line | awk -F' ' '{print $1}')
|
||||
p_name=$(echo $line | awk -F' ' '{print $2}')
|
||||
# basic check of format
|
||||
if [ ${#p_url} -ge 1 ] && [ ${#p_name} -ge 1 ]
|
||||
then
|
||||
# install addon
|
||||
util/add_theme_repo $line
|
||||
util/update_theme_repo $p_name # not sure if this line is neccessary
|
||||
echo "util/update_theme_repo $p_name" >> $plugins_update
|
||||
else
|
||||
print_info "skipping installation of a theme from file $theme_install - something wrong with format in line: $line"
|
||||
fi
|
||||
done < "$theme_install"
|
||||
print_info "installed hubzilla plugins and themes"
|
||||
}
|
||||
|
||||
function rewrite_to_https {
|
||||
print_info "configuring apache to redirect http to httpS ..."
|
||||
htaccessfile=/var/www/html/.htaccess
|
||||
if grep -i "https" $htaccessfile
|
||||
then
|
||||
print_info "...configuring apache to redirect http to httpS was already done in $htaccessfile"
|
||||
else
|
||||
sed -i "s#QSA]#QSA]\\n RewriteCond %{SERVER_PORT} !^443$\\n RewriteRule (.*) https://%{HTTP_HOST}/$1 [R=301,L]#" $htaccessfile
|
||||
fi
|
||||
service apache2 restart
|
||||
}
|
||||
|
||||
|
||||
function install_owncloud {
|
||||
if [ -z "$owncloud" ]
|
||||
then
|
||||
print_info "Do not install owncloud"
|
||||
return 0
|
||||
fi
|
||||
if [ -f /etc/apt/sources.list.d/owncloud.list ]
|
||||
then
|
||||
print_info "owncloud is already installed and is left untouched"
|
||||
return 0
|
||||
fi
|
||||
print_info "installing owncloud..."
|
||||
# add the repository key to apt
|
||||
wget -nv https://download.owncloud.org/download/repositories/stable/Debian_8.0/Release.key -O Release.key
|
||||
apt-key add - < Release.key
|
||||
# add the repository and install from there
|
||||
sh -c "echo 'deb http://download.owncloud.org/download/repositories/stable/Debian_8.0/ /' >> /etc/apt/sources.list.d/owncloud.list"
|
||||
apt-get update
|
||||
nocheck_install "owncloud"
|
||||
chown -R www-data:www-data /var/www/owncloud/
|
||||
# set strong permissions
|
||||
ocpath='/var/www/owncloud'
|
||||
htuser='www-data'
|
||||
htgroup='www-data'
|
||||
rootuser='root' # On QNAP this is admin
|
||||
find ${ocpath}/ -type f -print0 | xargs -0 chmod 0640
|
||||
find ${ocpath}/ -type d -print0 | xargs -0 chmod 0750
|
||||
chown -R ${rootuser}:${htgroup} ${ocpath}/
|
||||
chown -R ${htuser}:${htgroup} ${ocpath}/apps/
|
||||
chown -R ${htuser}:${htgroup} ${ocpath}/config/
|
||||
chown -R ${htuser}:${htgroup} ${ocpath}/data/
|
||||
chown -R ${htuser}:${htgroup} ${ocpath}/themes/
|
||||
chown ${rootuser}:${htgroup} ${ocpath}/.htaccess
|
||||
chown ${rootuser}:${htgroup} ${ocpath}/data/.htaccess
|
||||
chmod 0644 ${ocpath}/.htaccess
|
||||
chmod 0644 ${ocpath}/data/.htaccess
|
||||
}
|
||||
|
||||
# This will allways overwrite both config files
|
||||
# - internal disk
|
||||
# - external disk (LUKS + ext4)
|
||||
# of rsnapshot for hubzilla
|
||||
function install_rsnapshot {
|
||||
print_info "installing rsnapshot..."
|
||||
nocheck_install "rsnapshot"
|
||||
# internal disk
|
||||
cp -f /etc/rsnapshot.conf $snapshotconfig
|
||||
sed -i "/hourly/s/retain/#retain/" $snapshotconfig
|
||||
sed -i "/monthly/s/#retain/retain/" $snapshotconfig
|
||||
sed -i "s/^cmd_cp/#cmd_cp/" $snapshotconfig
|
||||
sed -i "s/^backup/#backup/" $snapshotconfig
|
||||
if [ -z "`grep 'letsencrypt' $snapshotconfig`" ]
|
||||
then
|
||||
echo "backup /var/lib/mysql/ localhost/" >> $snapshotconfig
|
||||
echo "backup /var/www/html/ localhost/" >> $snapshotconfig
|
||||
echo "backup /var/www/letsencrypt/ localhost/" >> $snapshotconfig
|
||||
fi
|
||||
# external disk
|
||||
if [ -n "$backup_device_name" ] && [ -n "$backup_device_pass" ]
|
||||
then
|
||||
cp -f /etc/rsnapshot.conf $snapshotconfig_external_device
|
||||
sed -i "s#snapshot_root.*#snapshot_root $backup_mount_point#" $snapshotconfig_external_device
|
||||
sed -i "/hourly/s/retain/#retain/" $snapshotconfig_external_device
|
||||
sed -i "/monthly/s/#retain/retain/" $snapshotconfig_external_device
|
||||
sed -i "s/^cmd_cp/#cmd_cp/" $snapshotconfig_external_device
|
||||
sed -i "s/^backup/#backup/" $snapshotconfig_external_device
|
||||
if [ -z "`grep 'letsencrypt' $snapshotconfig_external_device`" ]
|
||||
then
|
||||
echo "backup /var/lib/mysql/ localhost/" >> $snapshotconfig_external_device
|
||||
echo "backup /var/www/html/ localhost/" >> $snapshotconfig_external_device
|
||||
echo "backup /var/www/letsencrypt/ localhost/" >> $snapshotconfig_external_device
|
||||
fi
|
||||
else
|
||||
print_info "No backup configuration (rsnapshot) for external device configured. Reason: backup_device_name and/or backup_device_pass not given in $configfile"
|
||||
fi
|
||||
}
|
||||
|
||||
function install_cryptosetup {
|
||||
print_info "installing cryptsetup..."
|
||||
nocheck_install "cryptsetup"
|
||||
}
|
||||
|
||||
function configure_cron_daily {
|
||||
print_info "configuring cron..."
|
||||
# every 10 min for poller.php
|
||||
if [ -z "`grep 'poller.php' /etc/crontab`" ]
|
||||
then
|
||||
echo "*/10 * * * * www-data cd /var/www/html; php include/poller.php >> /dev/null 2>&1" >> /etc/crontab
|
||||
fi
|
||||
# Run external script daily at 05:30
|
||||
# - stop apache and mysql-server
|
||||
# - backup hubzilla
|
||||
# - update hubzilla core and addon
|
||||
# - update and upgrade linux
|
||||
# - reboot
|
||||
echo "#!/bin/sh" > /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "echo \" \"" >> /var/www/$hubzilladaily
|
||||
echo "echo \"+++ \$(date) +++\"" >> /var/www/$hubzilladaily
|
||||
echo "echo \" \"" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - renew certificat if 30 days old...\"" >> /var/www/$hubzilladaily
|
||||
echo "bash /var/www/letsencrypt/letsencrypt.sh --cron" >> /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "# stop hubzilla" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - stoping apaache and mysql...\"" >> /var/www/$hubzilladaily
|
||||
echo "service apache2 stop" >> /var/www/$hubzilladaily
|
||||
echo "/etc/init.d/mysql stop # to avoid inconsistancies" >> /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "# backup" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - try to mount external device for backup...\"" >> /var/www/$hubzilladaily
|
||||
echo "backup_device_name=$backup_device_name" >> /var/www/$hubzilladaily
|
||||
echo "backup_device_pass=$backup_device_pass" >> /var/www/$hubzilladaily
|
||||
echo "backup_mount_point=$backup_mount_point" >> /var/www/$hubzilladaily
|
||||
echo "device_mounted=0" >> /var/www/$hubzilladaily
|
||||
echo "if [ -n \"$backup_device_name\" ]" >> /var/www/$hubzilladaily
|
||||
echo "then" >> /var/www/$hubzilladaily
|
||||
echo " if blkid | grep $backup_device_name" >> /var/www/$hubzilladaily
|
||||
echo " then" >> /var/www/$hubzilladaily
|
||||
if [ -n "$backup_device_pass" ]
|
||||
then
|
||||
echo " echo \"decrypting backup device...\"" >> /var/www/$hubzilladaily
|
||||
echo " echo "\"$backup_device_pass\"" | cryptsetup luksOpen $backup_device_name cryptobackup" >> /var/www/$hubzilladaily
|
||||
fi
|
||||
echo " if [ ! -d $backup_mount_point ]" >> /var/www/$hubzilladaily
|
||||
echo " then" >> /var/www/$hubzilladaily
|
||||
echo " mkdir $backup_mount_point" >> /var/www/$hubzilladaily
|
||||
echo " fi" >> /var/www/$hubzilladaily
|
||||
echo " echo \"mounting backup device...\"" >> /var/www/$hubzilladaily
|
||||
if [ -n "$backup_device_pass" ]
|
||||
then
|
||||
echo " if mount /dev/mapper/cryptobackup $backup_mount_point" >> /var/www/$hubzilladaily
|
||||
else
|
||||
echo " if mount $backup_device_name $backup_mount_point" >> /var/www/$hubzilladaily
|
||||
fi
|
||||
echo " then" >> /var/www/$hubzilladaily
|
||||
echo " device_mounted=1" >> /var/www/$hubzilladaily
|
||||
echo " echo \"device $backup_device_name is now mounted. Starting backup...\"" >> /var/www/$hubzilladaily
|
||||
echo " rsnapshot -c $snapshotconfig_external_device daily" >> /var/www/$hubzilladaily
|
||||
echo " rsnapshot -c $snapshotconfig_external_device weekly" >> /var/www/$hubzilladaily
|
||||
echo " rsnapshot -c $snapshotconfig_external_device monthly" >> /var/www/$hubzilladaily
|
||||
echo " echo \"\$(date) - disk sizes...\"" >> /var/www/$hubzilladaily
|
||||
echo " df -h" >> /var/www/$hubzilladaily
|
||||
echo " echo \"\$(date) - db size...\"" >> /var/www/$hubzilladaily
|
||||
echo " du -h $backup_mount_point | grep mysql/hubzilla" >> /var/www/$hubzilladaily
|
||||
echo " echo \"unmounting backup device...\"" >> /var/www/$hubzilladaily
|
||||
echo " umount $backup_mount_point" >> /var/www/$hubzilladaily
|
||||
echo " else" >> /var/www/$hubzilladaily
|
||||
echo " echo \"failed to mount device $backup_device_name\"" >> /var/www/$hubzilladaily
|
||||
echo " fi" >> /var/www/$hubzilladaily
|
||||
if [ -n "$backup_device_pass" ]
|
||||
then
|
||||
echo " echo \"closing decrypted backup device...\"" >> /var/www/$hubzilladaily
|
||||
echo " cryptsetup luksClose cryptobackup" >> /var/www/$hubzilladaily
|
||||
fi
|
||||
echo " fi" >> /var/www/$hubzilladaily
|
||||
echo "fi" >> /var/www/$hubzilladaily
|
||||
echo "if [ \$device_mounted == 0 ]" >> /var/www/$hubzilladaily
|
||||
echo "then" >> /var/www/$hubzilladaily
|
||||
echo " echo \"device could not be mounted $backup_device_name. Using internal disk for backup...\"" >> /var/www/$hubzilladaily
|
||||
echo " rsnapshot -c $snapshotconfig daily" >> /var/www/$hubzilladaily
|
||||
echo " rsnapshot -c $snapshotconfig weekly" >> /var/www/$hubzilladaily
|
||||
echo " rsnapshot -c $snapshotconfig monthly" >> /var/www/$hubzilladaily
|
||||
echo "fi" >> /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - db size...\"" >> /var/www/$hubzilladaily
|
||||
echo "du -h /var/cache/rsnapshot/ | grep mysql/hubzilla" >> /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "# update" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - updating letsencrypt.sh...\"" >> /var/www/$hubzilladaily
|
||||
echo "git -C /var/www/letsencrypt/ pull" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - updating hubhilla core...\"" >> /var/www/$hubzilladaily
|
||||
echo "git -C /var/www/html/ pull" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - updating hubhilla addons...\"" >> /var/www/$hubzilladaily
|
||||
echo "git -C /var/www/html/addon/ pull" >> /var/www/$hubzilladaily
|
||||
echo "bash /var/www/html/$plugins_update" >> /var/www/$hubzilladaily
|
||||
echo "chown -R www-data:www-data /var/www/html/ # make all accessable for the webserver" >> /var/www/$hubzilladaily
|
||||
echo "chown root:www-data /var/www/html/.htaccess" >> /var/www/$hubzilladaily
|
||||
echo "chmod 0644 /var/www/html/.htaccess # www-data can read but not write it" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - updating linux...\"" >> /var/www/$hubzilladaily
|
||||
echo "apt-get -q -y update && apt-get -q -y dist-upgrade # update linux and upgrade" >> /var/www/$hubzilladaily
|
||||
echo "echo \"\$(date) - Backup hubzilla and update linux finished. Rebooting...\"" >> /var/www/$hubzilladaily
|
||||
echo "#" >> /var/www/$hubzilladaily
|
||||
echo "reboot" >> /var/www/$hubzilladaily
|
||||
|
||||
if [ -z "`grep 'hubzilla-daily.sh' /etc/crontab`" ]
|
||||
then
|
||||
echo "30 05 * * * root /bin/bash /var/www/$hubzilladaily >> /var/www/html/hubzilla-daily.log 2>&1" >> /etc/crontab
|
||||
echo "0 0 1 * * root rm /var/www/html/hubzilla-daily.log" >> /etc/crontab
|
||||
fi
|
||||
|
||||
# This is active after either "reboot" or "/etc/init.d/cron reload"
|
||||
print_info "configured cron for updates/upgrades"
|
||||
}
|
||||
|
||||
function write_uninstall_script {
|
||||
print_info "writing uninstall script..."
|
||||
|
||||
cat > /var/www/hubzilla-remove.sh <<END
|
||||
#!/bin/sh
|
||||
#
|
||||
# This script removes Hubzilla.
|
||||
# You might do this for a fresh start using the script.
|
||||
# The script will remove (almost everything) what was installed by the script,
|
||||
# all applications including hubzilla and its database.
|
||||
#
|
||||
# Backup the certificates of letsencrypt (you never know)
|
||||
cp -a /var/www/letsencrypt/ ~/backup_le_certificats
|
||||
#
|
||||
# Removal
|
||||
apt-get remove apache2 apache2-utils libapache2-mod-php5 php5 php-pear php5-xcache php5-curl php5-mcrypt php5-gd php5-mysql mysql-server mysql-client phpmyadmin
|
||||
apt-get purge apache2 apache2-utils libapache2-mod-php5 php5 php-pear php5-xcache php5-curl php5-mcrypt php5-gd php5-mysql mysql-server mysql-client phpmyadmin
|
||||
apt-get autoremove
|
||||
apt-get clean
|
||||
rm /etc/rsnapshot_hubzilla.conf
|
||||
rm /etc/rsnapshot_hubzilla_external_device.conf
|
||||
rm -R /etc/apache2/
|
||||
rm -R /var/lib/mysql/
|
||||
rm -R /var/www
|
||||
rm -R /etc/selfhost/
|
||||
# uncomment the next line if you want to remove the backups
|
||||
# rm -R /var/cache/rsnapshot
|
||||
nano /etc/crontab # remove entries there manually
|
||||
END
|
||||
chmod -x /var/www/hubzilla-remove.sh
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# START OF PROGRAM
|
||||
########################################################################
|
||||
export PATH=/bin:/usr/bin:/sbin:/usr/sbin
|
||||
|
||||
check_sanity
|
||||
|
||||
# Read config file edited by user
|
||||
configfile=hubzilla-config.txt
|
||||
source $configfile
|
||||
|
||||
selfhostdir=/etc/selfhost
|
||||
selfhostscript=selfhost-updater.sh
|
||||
hubzilladaily=hubzilla-daily.sh
|
||||
plugins_update=.homeinstall/plugins_update.sh
|
||||
snapshotconfig=/etc/rsnapshot_hubzilla.conf
|
||||
snapshotconfig_external_device=/etc/rsnapshot_hubzilla_external_device.conf
|
||||
backup_mount_point=/media/hubzilla_backup
|
||||
le_dir=/var/www/letsencrypt
|
||||
sslconf=/etc/apache2/sites-available/default-ssl.conf
|
||||
|
||||
#set -x # activate debugging from here
|
||||
|
||||
check_config
|
||||
stop_hubzilla
|
||||
update_upgrade
|
||||
install_curl
|
||||
install_sendmail
|
||||
install_apache
|
||||
install_php
|
||||
install_mysql
|
||||
install_phpmyadmin
|
||||
create_hubzilla_db
|
||||
run_freedns
|
||||
install_run_selfhost
|
||||
ping_domain
|
||||
configure_cron_freedns
|
||||
configure_cron_selfhost
|
||||
install_git
|
||||
install_letsencrypt
|
||||
configure_apache_for_https
|
||||
check_https
|
||||
install_hubzilla
|
||||
rewrite_to_https
|
||||
# install_owncloud # deprecated
|
||||
install_rsnapshot
|
||||
configure_cron_daily
|
||||
install_cryptosetup
|
||||
write_uninstall_script
|
||||
|
||||
#set +x # stop debugging from here
|
||||
|
|
@ -24,6 +24,9 @@ AddType audio/ogg .oga
|
|||
# Also place auth information into REMOTE_USER for sites running
|
||||
# in CGI mode.
|
||||
|
||||
RewriteCond %{REQUEST_URI} ^/\.well\-known/.*
|
||||
RewriteRule ^(.*)$ index.php?q=$1 [E=REMOTE_USER:%{HTTP:Authorization},L,QSA]
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(.*)$ index.php?q=$1 [E=REMOTE_USER:%{HTTP:Authorization},L,QSA]
|
||||
|
|
|
@ -181,6 +181,7 @@ echo "chmod done, permissions set to 777 on poller script."
|
|||
# to make Hubzilla on OpenShift a more pleasant experience
|
||||
echo "Changing default configuration to conserve space and autocreate a social private channel upon account registration"
|
||||
cd ${OPENSHIFT_REPO_DIR}
|
||||
util/config system auto_channel_create
|
||||
util/config system default_permissions_role social_private
|
||||
util/config system workflow_channel_next channel
|
||||
util/config system expire_delivery_reports 3
|
||||
|
|
135
sources/CHANGELOG
Normal file
135
sources/CHANGELOG
Normal file
|
@ -0,0 +1,135 @@
|
|||
Hubzilla 1.3
|
||||
Admin Security configuration page created which consolidates several previously hidden settings:
|
||||
Communication white/black lists
|
||||
Channel white/black lists
|
||||
OEmbed white/black lists
|
||||
Admin Profile Fields page created which manages the availability and order of standard profile fields and allows new fields to be created/managed
|
||||
"Poke" module reworked - page UI updated and "poke basic" setting introduced which limits the available poke "verbs".
|
||||
"Mood" module UI reworked
|
||||
"profile_photo" module UI reworked
|
||||
"cover_photo" module UI reworked
|
||||
"new_channel" module UI reworked
|
||||
"register" module UI reworked
|
||||
"pubsites" module UI reworked
|
||||
item-meta ("iconfig") created which implements arbitrary storage for item metadata for plugins
|
||||
abook-meta ("abconfig") created which implements arbitrary storage for connection metadata for plugins
|
||||
"Strict transport security header" made optional as it conflicts with some existing Apache/nginx configurations
|
||||
"Hubzilla UNO" (Hubzilla with radically simplified and locked site settings) implemented as an install configuration.
|
||||
.well-known directory conflict worked out to support LetsEncrypt cert ownership checks without disrupting webfinger and other internal uses of .well-known
|
||||
Lots of work on 'zcards' which are self-contained HTML representations of a channel including cover photos, profile photos, and some text information
|
||||
Long standing bug uncovered which failed to properly restrict the lower time limit for public feed requests
|
||||
A number of fixes to "readmore" to fix page jumping
|
||||
Bugfix: persons other than the channel owner who have permission to upload photos to a channel could not do so if the js_upload plugin/addon was enabled
|
||||
Siteinfo incorrectly identifying secondary directory servers
|
||||
Allow admin to set and lock features when UNO is configured
|
||||
Atom feeds: alter how events are formatted to be compatible with GNU-social
|
||||
Allow guest/visitor access to view personal calendar
|
||||
Moved several more classes to "composer format" and provided an autoloader.
|
||||
Bugfix: require existing password to change password
|
||||
Bugfix: allow relative_date() to be translated to Polish which has more than two plural forms.
|
||||
Plugin API: add "requires" keyword to module header to indicate dependent addons
|
||||
ActivityStreams improvements and cleanup: photo and file activities
|
||||
UI cleanup for editing profile when multiple profiles enabled
|
||||
Removed the "markdown" feature as there are numerous issues and no maintainer.
|
||||
Provide "footer" bbcode to ease theming of post footer content
|
||||
Bugfix: install issues caused by composer code refactor and typo in postgres load file
|
||||
Plugins:
|
||||
keepout - "block public on steroids"
|
||||
pubsubhubbub - provides PuSH support to Atom feeds, required for GNU-social federation
|
||||
GNUsocial protocol - under development
|
||||
Diaspora protocol - some work to ease migration to the new signing format
|
||||
Diaspost - disabled; numerous issues and no maintainer
|
||||
smileybutton - theme work and fixed compatibility with other jot-tools plugins
|
||||
|
||||
|
||||
Hubzilla 1.2
|
||||
Provide extra HTTP security headers (several of them).
|
||||
Allow a site to disable delivery reports if disk space is limited
|
||||
Regression: Wrong theme when viewing single post as non-member
|
||||
Some Diaspora profile photos use relative URLs - force absolute
|
||||
Add locked features to siteinfo report to aid remote debugging
|
||||
Provide version compatibility checking to plugins (minversion, maxversion, and minphpversion)
|
||||
Account config storage
|
||||
Provide optional integrated registration and channel create form
|
||||
cli utility for managing addons
|
||||
issue with sharing photo "items"
|
||||
cover photo manager: upload, crop, and store
|
||||
cover photo widget created
|
||||
rework the connections list page and provide a few management features there
|
||||
fixed issue with Comanche layout definitions loaded by plugins
|
||||
provide ability to separate delivery functions from item_store() and item_store_update() - some forum messages were being redelivered when cloned.
|
||||
call build_sync_packet() on pdledit changes
|
||||
Abstract the project name and version so these can be customised or removed
|
||||
Allow hiding the ratings links on a per-site basis
|
||||
db_type not present in international setup templates - was unable to choose postgres.
|
||||
item_photo_menu logically divided into a) actions on the post, b) actions related to the author
|
||||
bug: default channel not reset to 0 when last channel removed
|
||||
create widget containing only the contact block
|
||||
regression: public forums granted send stream permissions to connections
|
||||
workaround Firefox's refusal to honour disabling autocomplete of passwords
|
||||
regression: photo's uploaded to a channel by a guest (with file write permissions) not saved correctly.
|
||||
provide mechanisms for custom .well-known handlers (needed for LetsEncrypt ownership verification)
|
||||
proc_run modified to use exec() instead of proc_open() - causing issues on some PHP installations
|
||||
remote delegation failure under a specific set of circumstances which we were finally able to duplicate
|
||||
Delegation section of Channel Manager was missing names and contained useless notification icons.
|
||||
Change "expire" channel setting to show system limit if there is one.
|
||||
Regression: provide a one-click ignore of pending connection
|
||||
Config to control directory keyword generation on client and server.
|
||||
"Collections" renamed to "Privacy Groups", documentation improved
|
||||
widget_item - allow use of page title instead of message id
|
||||
Add site black/white list checking to all .well-known services
|
||||
reduce incidents of screen jumping when "showmore" is activated
|
||||
add oembed provider for photos
|
||||
|
||||
Addons:
|
||||
|
||||
CSS theming of pageheader plugin
|
||||
xmpp addon ported from Friendica
|
||||
Diaspora private mail issues after the third reply
|
||||
Occasional issue with Diaspora connection requests
|
||||
Add notification email to Diaspora PMs
|
||||
Allow anonymising platform and version for statistics
|
||||
msgfooter addon created
|
||||
removed embedly plugin
|
||||
sync clones after superblock addition
|
||||
"keepout" plugin created
|
||||
|
||||
|
||||
Hubzilla 1.1
|
||||
|
||||
Rewrote and simplified the Queue manager and delivery system
|
||||
Rewrote and simplified the outer layers of the Zot protocol
|
||||
Use a standard version numbering scheme in addition to the snapshot tags
|
||||
Provide a channel blacklist for blocking channels with abusive or illegal content at the hub level
|
||||
Make the black/white lists pluggable
|
||||
Update template library
|
||||
Support for letsencrypt certs in various places
|
||||
Cleanup of login and register pages
|
||||
Better error responses for permission denied on channel file repositories
|
||||
Disabled the public stream by default for new installs (can be enabled if desired)
|
||||
Cleanup of API authentication and rework the old OAuth1 stuff
|
||||
Add API "status with media" support compatible with Twitter and conflicting method for GNU-social
|
||||
Rework photo ActivityStreams objects to align better with ActivityStreams producers/consumers
|
||||
Several minor API fixes to work better with AndStatus client
|
||||
Invitation only site - experimental support added, needs more work
|
||||
Fix delivery loop condition due to corrupted data which resulted in recursive upstream delivery
|
||||
Provide more support for external (git) widget collections.
|
||||
Extend the Queue API to 3rd-party network addons which have experienced downtime recently.
|
||||
Regression: Inherited permissions were not explicitly set
|
||||
Regression: "Xyz posted on your wall" notification sent when creating webpages at another channel
|
||||
Regression: Custom permissions not pre-populated on channel creation with named role.
|
||||
Provide "Public" string when a post can be made public, instead of "visible to default audience"
|
||||
Allow hub admin to specify a default role type for the first channel created, reducing complexity
|
||||
Ability for a hub admin to set feature defaults and lock them, reducing complexity
|
||||
Change default expiration of delivery reports to 10 days to accomodate sites with reduced resources
|
||||
Addons/Plugins:
|
||||
Pageheader addon ported from Friendica
|
||||
Hubwall (allow admin to send email to all accounts on this hub) created
|
||||
GNU-social - queueing added
|
||||
Diaspora - fixes for various failures to update profile photos, updates to queue API
|
||||
Cross Domain Authenticated Chess (Andrew Manning's repository)
|
||||
|
||||
And... the normal "lots of bugs fixed, translations updated, and documentation improved"
|
||||
|
||||
|
||||
|
92
sources/Zotlabs/Access/AccessList.php
Normal file
92
sources/Zotlabs/Access/AccessList.php
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
namespace Zotlabs\Access;
|
||||
|
||||
|
||||
class AccessList {
|
||||
|
||||
private $allow_cid;
|
||||
private $allow_gid;
|
||||
private $deny_cid;
|
||||
private $deny_gid;
|
||||
|
||||
/* indicates if we are using the default constructor values or values that have been set explicitly. */
|
||||
|
||||
private $explicit;
|
||||
|
||||
function __construct($channel) {
|
||||
|
||||
if($channel) {
|
||||
$this->allow_cid = $channel['channel_allow_cid'];
|
||||
$this->allow_gid = $channel['channel_allow_gid'];
|
||||
$this->deny_cid = $channel['channel_deny_cid'];
|
||||
$this->deny_gid = $channel['channel_deny_gid'];
|
||||
}
|
||||
else {
|
||||
$this->allow_cid = '';
|
||||
$this->allow_gid = '';
|
||||
$this->deny_cid = '';
|
||||
$this->deny_gid = '';
|
||||
}
|
||||
|
||||
$this->explicit = false;
|
||||
}
|
||||
|
||||
function get_explicit() {
|
||||
return $this->explicit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set AccessList from strings such as those in already
|
||||
* existing stored data items
|
||||
*/
|
||||
|
||||
function set($arr,$explicit = true) {
|
||||
$this->allow_cid = $arr['allow_cid'];
|
||||
$this->allow_gid = $arr['allow_gid'];
|
||||
$this->deny_cid = $arr['deny_cid'];
|
||||
$this->deny_gid = $arr['deny_gid'];
|
||||
|
||||
$this->explicit = $explicit;
|
||||
}
|
||||
|
||||
/**
|
||||
* return an array consisting of the current
|
||||
* access list components where the elements
|
||||
* are directly storable.
|
||||
*/
|
||||
|
||||
function get() {
|
||||
return array(
|
||||
'allow_cid' => $this->allow_cid,
|
||||
'allow_gid' => $this->allow_gid,
|
||||
'deny_cid' => $this->deny_cid,
|
||||
'deny_gid' => $this->deny_gid,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set AccessList from arrays, such as those provided by
|
||||
* acl_selector(). For convenience, a string (or non-array) input is
|
||||
* assumed to be a comma-separated list and auto-converted into an array.
|
||||
*/
|
||||
|
||||
function set_from_array($arr,$explicit = true) {
|
||||
$this->allow_cid = perms2str((is_array($arr['contact_allow']))
|
||||
? $arr['contact_allow'] : explode(',',$arr['contact_allow']));
|
||||
$this->allow_gid = perms2str((is_array($arr['group_allow']))
|
||||
? $arr['group_allow'] : explode(',',$arr['group_allow']));
|
||||
$this->deny_cid = perms2str((is_array($arr['contact_deny']))
|
||||
? $arr['contact_deny'] : explode(',',$arr['contact_deny']));
|
||||
$this->deny_gid = perms2str((is_array($arr['group_deny']))
|
||||
? $arr['group_deny'] : explode(',',$arr['group_deny']));
|
||||
|
||||
$this->explicit = $explicit;
|
||||
}
|
||||
|
||||
function is_private() {
|
||||
return (($this->allow_cid || $this->allow_gid || $this->deny_cid || $this->deny_gid) ? true : false);
|
||||
}
|
||||
|
||||
}
|
||||
|
62
sources/Zotlabs/Project/System.php
Normal file
62
sources/Zotlabs/Project/System.php
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
namespace Zotlabs\Project;
|
||||
|
||||
class System {
|
||||
|
||||
function get_platform_name() {
|
||||
$a = get_app();
|
||||
if(is_array($a->config) && is_array($a->config['system']) && $a->config['system']['platform_name'])
|
||||
return $a->config['system']['platform_name'];
|
||||
return PLATFORM_NAME;
|
||||
}
|
||||
|
||||
function get_project_version() {
|
||||
$a = get_app();
|
||||
if(is_array($a->config) && is_array($a->config['system']) && $a->config['system']['hide_version'])
|
||||
return '';
|
||||
return RED_VERSION;
|
||||
}
|
||||
|
||||
function get_update_version() {
|
||||
$a = get_app();
|
||||
if(is_array($a->config) && is_array($a->config['system']) && $a->config['system']['hide_version'])
|
||||
return '';
|
||||
return DB_UPDATE_VERSION;
|
||||
}
|
||||
|
||||
|
||||
function get_notify_icon() {
|
||||
$a = get_app();
|
||||
if(is_array($a->config) && is_array($a->config['system']) && $a->config['system']['email_notify_icon_url'])
|
||||
return $a->config['system']['email_notify_icon_url'];
|
||||
return z_root() . '/images/hz-white-32.png';
|
||||
}
|
||||
|
||||
function get_site_icon() {
|
||||
$a = get_app();
|
||||
if(is_array($a->config) && is_array($a->config['system']) && $a->config['system']['site_icon_url'])
|
||||
return $a->config['system']['site_icon_url'];
|
||||
return z_root() . '/images/hz-32.png';
|
||||
}
|
||||
|
||||
|
||||
function get_server_role() {
|
||||
if(UNO)
|
||||
return 'basic';
|
||||
return 'advanced';
|
||||
}
|
||||
|
||||
// return the standardised version. Since we can't easily compare
|
||||
// before the STD_VERSION definition was applied, we have to treat
|
||||
// all prior release versions the same. You can dig through them
|
||||
// with other means (such as RED_VERSION) if necessary.
|
||||
|
||||
function get_std_version() {
|
||||
if(defined('STD_VERSION'))
|
||||
return STD_VERSION;
|
||||
return '0.0.0';
|
||||
}
|
||||
|
||||
|
||||
}
|
212
sources/Zotlabs/Storage/BasicAuth.php
Normal file
212
sources/Zotlabs/Storage/BasicAuth.php
Normal file
|
@ -0,0 +1,212 @@
|
|||
<?php
|
||||
|
||||
namespace Zotlabs\Storage;
|
||||
|
||||
use Sabre\DAV;
|
||||
|
||||
/**
|
||||
* @brief Authentication backend class for DAV.
|
||||
*
|
||||
* This class also contains some data which is not necessary for authentication
|
||||
* like timezone settings.
|
||||
*
|
||||
* @extends Sabre\DAV\Auth\Backend\AbstractBasic
|
||||
*
|
||||
* @link http://github.com/friendica/red
|
||||
* @license http://opensource.org/licenses/mit-license.php The MIT License (MIT)
|
||||
*/
|
||||
class BasicAuth extends DAV\Auth\Backend\AbstractBasic {
|
||||
|
||||
/**
|
||||
* @brief This variable holds the currently logged-in channel_address.
|
||||
*
|
||||
* It is used for building path in filestorage/.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $channel_name = null;
|
||||
/**
|
||||
* channel_id of the current channel of the logged-in account.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $channel_id = 0;
|
||||
/**
|
||||
* channel_hash of the current channel of the logged-in account.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $channel_hash = '';
|
||||
/**
|
||||
* Set in mod/cloud.php to observer_hash.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $observer = '';
|
||||
/**
|
||||
*
|
||||
* @see Browser::set_writeable()
|
||||
* @var \Sabre\DAV\Browser\Plugin
|
||||
*/
|
||||
public $browser;
|
||||
/**
|
||||
* channel_id of the current visited path. Set in Directory::getDir().
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $owner_id = 0;
|
||||
/**
|
||||
* channel_name of the current visited path. Set in Directory::getDir().
|
||||
*
|
||||
* Used for creating the path in cloud/
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $owner_nick = '';
|
||||
/**
|
||||
* Timezone from the visiting channel's channel_timezone.
|
||||
*
|
||||
* Used in @ref RedBrowser
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $timezone = '';
|
||||
|
||||
|
||||
/**
|
||||
* @brief Validates a username and password.
|
||||
*
|
||||
* Guest access is granted with the password "+++".
|
||||
*
|
||||
* @see \Sabre\DAV\Auth\Backend\AbstractBasic::validateUserPass
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @return bool
|
||||
*/
|
||||
protected function validateUserPass($username, $password) {
|
||||
if (trim($password) === '+++') {
|
||||
logger('guest: ' . $username);
|
||||
return true;
|
||||
}
|
||||
|
||||
require_once('include/auth.php');
|
||||
$record = account_verify_password($username, $password);
|
||||
if ($record && $record['account_default_channel']) {
|
||||
$r = q("SELECT * FROM channel WHERE channel_account_id = %d AND channel_id = %d LIMIT 1",
|
||||
intval($record['account_id']),
|
||||
intval($record['account_default_channel'])
|
||||
);
|
||||
if ($r) {
|
||||
return $this->setAuthenticated($r[0]);
|
||||
}
|
||||
}
|
||||
$r = q("SELECT * FROM channel WHERE channel_address = '%s' LIMIT 1",
|
||||
dbesc($username)
|
||||
);
|
||||
if ($r) {
|
||||
$x = q("SELECT account_flags, account_salt, account_password FROM account WHERE account_id = %d LIMIT 1",
|
||||
intval($r[0]['channel_account_id'])
|
||||
);
|
||||
if ($x) {
|
||||
// @fixme this foreach should not be needed?
|
||||
foreach ($x as $record) {
|
||||
if ((($record['account_flags'] == ACCOUNT_OK) || ($record['account_flags'] == ACCOUNT_UNVERIFIED))
|
||||
&& (hash('whirlpool', $record['account_salt'] . $password) === $record['account_password'])) {
|
||||
logger('password verified for ' . $username);
|
||||
return $this->setAuthenticated($r[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$error = 'password failed for ' . $username;
|
||||
logger($error);
|
||||
log_failed_login($error);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets variables and session parameters after successfull authentication.
|
||||
*
|
||||
* @param array $r
|
||||
* Array with the values for the authenticated channel.
|
||||
* @return bool
|
||||
*/
|
||||
protected function setAuthenticated($r) {
|
||||
$this->channel_name = $r['channel_address'];
|
||||
$this->channel_id = $r['channel_id'];
|
||||
$this->channel_hash = $this->observer = $r['channel_hash'];
|
||||
$_SESSION['uid'] = $r['channel_id'];
|
||||
$_SESSION['account_id'] = $r['channel_account_id'];
|
||||
$_SESSION['authenticated'] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the channel_name from the currently logged-in channel.
|
||||
*
|
||||
* @param string $name
|
||||
* The channel's name
|
||||
*/
|
||||
public function setCurrentUser($name) {
|
||||
$this->channel_name = $name;
|
||||
}
|
||||
/**
|
||||
* Returns information about the currently logged-in channel.
|
||||
*
|
||||
* If nobody is currently logged in, this method should return null.
|
||||
*
|
||||
* @see \Sabre\DAV\Auth\Backend\AbstractBasic::getCurrentUser
|
||||
* @return string|null
|
||||
*/
|
||||
public function getCurrentUser() {
|
||||
return $this->channel_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the timezone from the channel in RedBasicAuth.
|
||||
*
|
||||
* Set in mod/cloud.php if the channel has a timezone set.
|
||||
*
|
||||
* @param string $timezone
|
||||
* The channel's timezone.
|
||||
* @return void
|
||||
*/
|
||||
public function setTimezone($timezone) {
|
||||
$this->timezone = $timezone;
|
||||
}
|
||||
/**
|
||||
* @brief Returns the timezone.
|
||||
*
|
||||
* @return string
|
||||
* Return the channel's timezone.
|
||||
*/
|
||||
public function getTimezone() {
|
||||
return $this->timezone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set browser plugin for SabreDAV.
|
||||
*
|
||||
* @see RedBrowser::set_writeable()
|
||||
* @param \Sabre\DAV\Browser\Plugin $browser
|
||||
*/
|
||||
public function setBrowserPlugin($browser) {
|
||||
$this->browser = $browser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prints out all BasicAuth variables to logger().
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function log() {
|
||||
logger('channel_name ' . $this->channel_name, LOGGER_DATA);
|
||||
logger('channel_id ' . $this->channel_id, LOGGER_DATA);
|
||||
logger('channel_hash ' . $this->channel_hash, LOGGER_DATA);
|
||||
logger('observer ' . $this->observer, LOGGER_DATA);
|
||||
logger('owner_id ' . $this->owner_id, LOGGER_DATA);
|
||||
logger('owner_nick ' . $this->owner_nick, LOGGER_DATA);
|
||||
}
|
||||
}
|
372
sources/Zotlabs/Storage/Browser.php
Normal file
372
sources/Zotlabs/Storage/Browser.php
Normal file
|
@ -0,0 +1,372 @@
|
|||
<?php
|
||||
|
||||
namespace Zotlabs\Storage;
|
||||
|
||||
use Sabre\DAV;
|
||||
|
||||
/**
|
||||
* @brief Provides a DAV frontend for the webbrowser.
|
||||
*
|
||||
* RedBrowser is a SabreDAV server-plugin to provide a view to the DAV storage
|
||||
* for the webbrowser.
|
||||
*
|
||||
* @extends \Sabre\DAV\Browser\Plugin
|
||||
*
|
||||
* @link http://github.com/friendica/red
|
||||
* @license http://opensource.org/licenses/mit-license.php The MIT License (MIT)
|
||||
*/
|
||||
class Browser extends DAV\Browser\Plugin {
|
||||
|
||||
/**
|
||||
* @see set_writeable()
|
||||
* @see \Sabre\DAV\Auth\Backend\BackendInterface
|
||||
* @var RedBasicAuth
|
||||
*/
|
||||
private $auth;
|
||||
|
||||
/**
|
||||
* @brief Constructor for RedBrowser class.
|
||||
*
|
||||
* $enablePost will be activated through set_writeable() in a later stage.
|
||||
* At the moment the write_storage permission is only valid for the whole
|
||||
* folder. No file specific permissions yet.
|
||||
* @todo disable enablePost by default and only activate if permissions
|
||||
* grant edit rights.
|
||||
*
|
||||
* Disable assets with $enableAssets = false. Should get some thumbnail views
|
||||
* anyway.
|
||||
*
|
||||
* @param RedBasicAuth &$auth
|
||||
*/
|
||||
public function __construct(&$auth) {
|
||||
$this->auth = $auth;
|
||||
parent::__construct(true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* The DAV browser is instantiated after the auth module and directory classes
|
||||
* but before we know the current directory and who the owner and observer
|
||||
* are. So we add a pointer to the browser into the auth module and vice versa.
|
||||
* Then when we've figured out what directory is actually being accessed, we
|
||||
* call the following function to decide whether or not to show web elements
|
||||
* which include writeable objects.
|
||||
*
|
||||
* @fixme It only disable/enable the visible parts. Not the POST handler
|
||||
* which handels the actual requests when uploading files or creating folders.
|
||||
*
|
||||
* @todo Maybe this whole way of doing this can be solved with some
|
||||
* $server->subscribeEvent().
|
||||
*/
|
||||
public function set_writeable() {
|
||||
if (! $this->auth->owner_id) {
|
||||
$this->enablePost = false;
|
||||
}
|
||||
|
||||
if (! perm_is_allowed($this->auth->owner_id, get_observer_hash(), 'write_storage')) {
|
||||
$this->enablePost = false;
|
||||
} else {
|
||||
$this->enablePost = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates the directory listing for the given path.
|
||||
*
|
||||
* @param string $path which should be displayed
|
||||
*/
|
||||
public function generateDirectoryIndex($path) {
|
||||
// (owner_id = channel_id) is visitor owner of this directory?
|
||||
$is_owner = ((local_channel() && $this->auth->owner_id == local_channel()) ? true : false);
|
||||
|
||||
if ($this->auth->getTimezone())
|
||||
date_default_timezone_set($this->auth->getTimezone());
|
||||
|
||||
require_once('include/conversation.php');
|
||||
require_once('include/text.php');
|
||||
if ($this->auth->owner_nick) {
|
||||
$html = profile_tabs(get_app(), (($is_owner) ? true : false), $this->auth->owner_nick);
|
||||
}
|
||||
|
||||
$files = $this->server->getPropertiesForPath($path, array(
|
||||
'{DAV:}displayname',
|
||||
'{DAV:}resourcetype',
|
||||
'{DAV:}getcontenttype',
|
||||
'{DAV:}getcontentlength',
|
||||
'{DAV:}getlastmodified',
|
||||
), 1);
|
||||
|
||||
|
||||
$parent = $this->server->tree->getNodeForPath($path);
|
||||
|
||||
$parentpath = array();
|
||||
// only show parent if not leaving /cloud/; TODO how to improve this?
|
||||
if ($path && $path != "cloud") {
|
||||
list($parentUri) = DAV\URLUtil::splitPath($path);
|
||||
$fullPath = DAV\URLUtil::encodePath($this->server->getBaseUri() . $parentUri);
|
||||
|
||||
$parentpath['icon'] = $this->enableAssets ? '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl('icons/parent' . $this->iconExtension) . '" width="24" alt="' . t('parent') . '"></a>' : '';
|
||||
$parentpath['path'] = $fullPath;
|
||||
}
|
||||
|
||||
$f = array();
|
||||
foreach ($files as $file) {
|
||||
$ft = array();
|
||||
$type = null;
|
||||
|
||||
// This is the current directory, we can skip it
|
||||
if (rtrim($file['href'],'/') == $path) continue;
|
||||
|
||||
list(, $name) = DAV\URLUtil::splitPath($file['href']);
|
||||
|
||||
if (isset($file[200]['{DAV:}resourcetype'])) {
|
||||
$type = $file[200]['{DAV:}resourcetype']->getValue();
|
||||
|
||||
// resourcetype can have multiple values
|
||||
if (!is_array($type)) $type = array($type);
|
||||
|
||||
foreach ($type as $k=>$v) {
|
||||
// Some name mapping is preferred
|
||||
switch ($v) {
|
||||
case '{DAV:}collection' :
|
||||
$type[$k] = t('Collection');
|
||||
break;
|
||||
case '{DAV:}principal' :
|
||||
$type[$k] = t('Principal');
|
||||
break;
|
||||
case '{urn:ietf:params:xml:ns:carddav}addressbook' :
|
||||
$type[$k] = t('Addressbook');
|
||||
break;
|
||||
case '{urn:ietf:params:xml:ns:caldav}calendar' :
|
||||
$type[$k] = t('Calendar');
|
||||
break;
|
||||
case '{urn:ietf:params:xml:ns:caldav}schedule-inbox' :
|
||||
$type[$k] = t('Schedule Inbox');
|
||||
break;
|
||||
case '{urn:ietf:params:xml:ns:caldav}schedule-outbox' :
|
||||
$type[$k] = t('Schedule Outbox');
|
||||
break;
|
||||
case '{http://calendarserver.org/ns/}calendar-proxy-read' :
|
||||
$type[$k] = 'Proxy-Read';
|
||||
break;
|
||||
case '{http://calendarserver.org/ns/}calendar-proxy-write' :
|
||||
$type[$k] = 'Proxy-Write';
|
||||
break;
|
||||
}
|
||||
}
|
||||
$type = implode(', ', $type);
|
||||
}
|
||||
|
||||
// If no resourcetype was found, we attempt to use
|
||||
// the contenttype property
|
||||
if (!$type && isset($file[200]['{DAV:}getcontenttype'])) {
|
||||
$type = $file[200]['{DAV:}getcontenttype'];
|
||||
}
|
||||
if (!$type) $type = t('Unknown');
|
||||
|
||||
$size = isset($file[200]['{DAV:}getcontentlength']) ? (int)$file[200]['{DAV:}getcontentlength'] : '';
|
||||
$lastmodified = ((isset($file[200]['{DAV:}getlastmodified'])) ? $file[200]['{DAV:}getlastmodified']->getTime()->format('Y-m-d H:i:s') : '');
|
||||
|
||||
$fullPath = DAV\URLUtil::encodePath('/' . trim($this->server->getBaseUri() . ($path ? $path . '/' : '') . $name, '/'));
|
||||
|
||||
|
||||
$displayName = isset($file[200]['{DAV:}displayname']) ? $file[200]['{DAV:}displayname'] : $name;
|
||||
|
||||
$displayName = $this->escapeHTML($displayName);
|
||||
$type = $this->escapeHTML($type);
|
||||
|
||||
$icon = '';
|
||||
|
||||
if ($this->enableAssets) {
|
||||
$node = $this->server->tree->getNodeForPath(($path ? $path . '/' : '') . $name);
|
||||
foreach (array_reverse($this->iconMap) as $class=>$iconName) {
|
||||
if ($node instanceof $class) {
|
||||
$icon = '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl($iconName . $this->iconExtension) . '" alt="" width="24"></a>';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$parentHash = '';
|
||||
$owner = $this->auth->owner_id;
|
||||
$splitPath = explode('/', $fullPath);
|
||||
if (count($splitPath) > 3) {
|
||||
for ($i = 3; $i < count($splitPath); $i++) {
|
||||
$attachName = urldecode($splitPath[$i]);
|
||||
$attachHash = $this->findAttachHash($owner, $parentHash, $attachName);
|
||||
$parentHash = $attachHash;
|
||||
}
|
||||
}
|
||||
|
||||
$attachIcon = ""; // "<a href=\"attach/".$attachHash."\" title=\"".$displayName."\"><i class=\"icon-download\"></i></a>";
|
||||
|
||||
// put the array for this file together
|
||||
$ft['attachId'] = $this->findAttachIdByHash($attachHash);
|
||||
$ft['fileStorageUrl'] = substr($fullPath, 0, strpos($fullPath, "cloud/")) . "filestorage/" . $this->auth->getCurrentUser();
|
||||
$ft['icon'] = $icon;
|
||||
$ft['attachIcon'] = (($size) ? $attachIcon : '');
|
||||
// @todo Should this be an item value, not a global one?
|
||||
$ft['is_owner'] = $is_owner;
|
||||
$ft['fullPath'] = $fullPath;
|
||||
$ft['displayName'] = $displayName;
|
||||
$ft['type'] = $type;
|
||||
$ft['size'] = $size;
|
||||
$ft['sizeFormatted'] = userReadableSize($size);
|
||||
$ft['lastmodified'] = (($lastmodified) ? datetime_convert('UTC', date_default_timezone_get(), $lastmodified) : '');
|
||||
$ft['iconFromType'] = getIconFromType($type);
|
||||
|
||||
$f[] = $ft;
|
||||
}
|
||||
|
||||
$output = '';
|
||||
if ($this->enablePost) {
|
||||
$this->server->broadcastEvent('onHTMLActionsPanel', array($parent, &$output));
|
||||
}
|
||||
|
||||
$html .= replace_macros(get_markup_template('cloud.tpl'), array(
|
||||
'$header' => t('Files') . ": " . $this->escapeHTML($path) . "/",
|
||||
'$total' => t('Total'),
|
||||
'$actionspanel' => $output,
|
||||
'$shared' => t('Shared'),
|
||||
'$create' => t('Create'),
|
||||
'$upload' => t('Upload'),
|
||||
'$is_owner' => $is_owner,
|
||||
'$parentpath' => $parentpath,
|
||||
'$entries' => $f,
|
||||
'$name' => t('Name'),
|
||||
'$type' => t('Type'),
|
||||
'$size' => t('Size'),
|
||||
'$lastmod' => t('Last Modified'),
|
||||
'$parent' => t('parent'),
|
||||
'$edit' => t('Edit'),
|
||||
'$delete' => t('Delete'),
|
||||
'$nick' => $this->auth->getCurrentUser()
|
||||
));
|
||||
|
||||
$a = get_app();
|
||||
$a->page['content'] = $html;
|
||||
load_pdl($a);
|
||||
|
||||
$theme_info_file = "view/theme/" . current_theme() . "/php/theme.php";
|
||||
if (file_exists($theme_info_file)){
|
||||
require_once($theme_info_file);
|
||||
if (function_exists(str_replace('-', '_', current_theme()) . '_init')) {
|
||||
$func = str_replace('-', '_', current_theme()) . '_init';
|
||||
$func($a);
|
||||
}
|
||||
}
|
||||
construct_page($a);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a form to add new folders and upload files.
|
||||
*
|
||||
* @param \Sabre\DAV\INode $node
|
||||
* @param string &$output
|
||||
*/
|
||||
public function htmlActionsPanel(DAV\INode $node, &$output) {
|
||||
if (! $node instanceof DAV\ICollection)
|
||||
return;
|
||||
|
||||
// We also know fairly certain that if an object is a non-extended
|
||||
// SimpleCollection, we won't need to show the panel either.
|
||||
if (get_class($node) === 'Sabre\\DAV\\SimpleCollection')
|
||||
return;
|
||||
|
||||
// Storage and quota for the account (all channels of the owner of this directory)!
|
||||
$limit = service_class_fetch($owner, 'attach_upload_limit');
|
||||
$r = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d",
|
||||
intval($this->auth->channel_account_id)
|
||||
);
|
||||
$used = $r[0]['total'];
|
||||
if ($used) {
|
||||
$quotaDesc = t('You are using %1$s of your available file storage.');
|
||||
$quotaDesc = sprintf($quotaDesc,
|
||||
userReadableSize($used));
|
||||
}
|
||||
if ($limit && $used) {
|
||||
$quotaDesc = t('You are using %1$s of %2$s available file storage. (%3$s%)');
|
||||
$quotaDesc = sprintf($quotaDesc,
|
||||
userReadableSize($used),
|
||||
userReadableSize($limit),
|
||||
round($used / $limit, 1) * 100);
|
||||
}
|
||||
|
||||
// prepare quota for template
|
||||
$quota = array();
|
||||
$quota['used'] = $used;
|
||||
$quota['limit'] = $limit;
|
||||
$quota['desc'] = $quotaDesc;
|
||||
$quota['warning'] = ((($limit) && ((round($used / $limit, 1) * 100) >= 90)) ? t('WARNING:') : ''); // 10485760 bytes = 100MB
|
||||
|
||||
$output .= replace_macros(get_markup_template('cloud_actionspanel.tpl'), array(
|
||||
'$folder_header' => t('Create new folder'),
|
||||
'$folder_submit' => t('Create'),
|
||||
'$upload_header' => t('Upload file'),
|
||||
'$upload_submit' => t('Upload'),
|
||||
'$quota' => $quota
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method takes a path/name of an asset and turns it into url
|
||||
* suiteable for http access.
|
||||
*
|
||||
* @param string $assetName
|
||||
* @return string
|
||||
*/
|
||||
protected function getAssetUrl($assetName) {
|
||||
return z_root() . '/cloud/?sabreAction=asset&assetName=' . urlencode($assetName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the hash of an attachment.
|
||||
*
|
||||
* Given the owner, the parent folder and and attach name get the attachment
|
||||
* hash.
|
||||
*
|
||||
* @param int $owner
|
||||
* The owner_id
|
||||
* @param string $hash
|
||||
* The parent's folder hash
|
||||
* @param string $attachName
|
||||
* The name of the attachment
|
||||
* @return string
|
||||
*/
|
||||
|
||||
protected function findAttachHash($owner, $parentHash, $attachName) {
|
||||
$r = q("SELECT hash FROM attach WHERE uid = %d AND folder = '%s' AND filename = '%s' ORDER BY edited DESC LIMIT 1",
|
||||
intval($owner),
|
||||
dbesc($parentHash),
|
||||
dbesc($attachName)
|
||||
);
|
||||
$hash = "";
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
$hash = $rr['hash'];
|
||||
}
|
||||
}
|
||||
return $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an attachment's id for a given hash.
|
||||
*
|
||||
* This id is used to access the attachment in filestorage/
|
||||
*
|
||||
* @param string $attachHash
|
||||
* The hash of an attachment
|
||||
* @return string
|
||||
*/
|
||||
protected function findAttachIdByHash($attachHash) {
|
||||
$r = q("SELECT id FROM attach WHERE hash = '%s' ORDER BY edited DESC LIMIT 1",
|
||||
dbesc($attachHash)
|
||||
);
|
||||
$id = "";
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
$id = $rr['id'];
|
||||
}
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
}
|
536
sources/Zotlabs/Storage/Directory.php
Normal file
536
sources/Zotlabs/Storage/Directory.php
Normal file
|
@ -0,0 +1,536 @@
|
|||
<?php
|
||||
|
||||
namespace Zotlabs\Storage;
|
||||
|
||||
use Sabre\DAV;
|
||||
|
||||
/**
|
||||
* @brief RedDirectory class.
|
||||
*
|
||||
* A class that represents a directory.
|
||||
*
|
||||
* @extends \Sabre\DAV\Node
|
||||
* @implements \Sabre\DAV\ICollection
|
||||
* @implements \Sabre\DAV\IQuota
|
||||
*
|
||||
* @link http://github.com/friendica/red
|
||||
* @license http://opensource.org/licenses/mit-license.php The MIT License (MIT)
|
||||
*/
|
||||
class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
|
||||
|
||||
/**
|
||||
* @brief The path inside /cloud
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $red_path;
|
||||
private $folder_hash;
|
||||
/**
|
||||
* @brief The full path as seen in the browser.
|
||||
* /cloud + $red_path
|
||||
* @todo I think this is not used anywhere, we always strip '/cloud' and only use it in debug
|
||||
* @var string
|
||||
*/
|
||||
private $ext_path;
|
||||
private $root_dir = '';
|
||||
private $auth;
|
||||
/**
|
||||
* @brief The real path on the filesystem.
|
||||
* The actual path in store/ with the hashed names.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $os_path = '';
|
||||
|
||||
/**
|
||||
* @brief Sets up the directory node, expects a full path.
|
||||
*
|
||||
* @param string $ext_path a full path
|
||||
* @param RedBasicAuth &$auth_plugin
|
||||
*/
|
||||
public function __construct($ext_path, &$auth_plugin) {
|
||||
// $ext_path = urldecode($ext_path);
|
||||
logger('directory ' . $ext_path, LOGGER_DATA);
|
||||
$this->ext_path = $ext_path;
|
||||
// remove "/cloud" from the beginning of the path
|
||||
$modulename = get_app()->module;
|
||||
$this->red_path = ((strpos($ext_path, '/' . $modulename) === 0) ? substr($ext_path, strlen($modulename) + 1) : $ext_path);
|
||||
if (! $this->red_path) {
|
||||
$this->red_path = '/';
|
||||
}
|
||||
$this->auth = $auth_plugin;
|
||||
$this->folder_hash = '';
|
||||
$this->getDir();
|
||||
|
||||
if ($this->auth->browser) {
|
||||
$this->auth->browser->set_writeable();
|
||||
}
|
||||
}
|
||||
|
||||
private function log() {
|
||||
logger('ext_path ' . $this->ext_path, LOGGER_DATA);
|
||||
logger('os_path ' . $this->os_path, LOGGER_DATA);
|
||||
logger('red_path ' . $this->red_path, LOGGER_DATA);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an array with all the child nodes.
|
||||
*
|
||||
* @throw \Sabre\DAV\Exception\Forbidden
|
||||
* @return array \Sabre\DAV\INode[]
|
||||
*/
|
||||
public function getChildren() {
|
||||
logger('children for ' . $this->ext_path, LOGGER_DATA);
|
||||
$this->log();
|
||||
|
||||
if (get_config('system', 'block_public') && (! $this->auth->channel_id) && (! $this->auth->observer)) {
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
|
||||
if (($this->auth->owner_id) && (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'view_storage'))) {
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
|
||||
$contents = RedCollectionData($this->red_path, $this->auth);
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a child by name.
|
||||
*
|
||||
*
|
||||
* @throw \Sabre\DAV\Exception\Forbidden
|
||||
* @throw \Sabre\DAV\Exception\NotFound
|
||||
* @param string $name
|
||||
*/
|
||||
public function getChild($name) {
|
||||
logger($name, LOGGER_DATA);
|
||||
|
||||
if (get_config('system', 'block_public') && (! $this->auth->channel_id) && (! $this->auth->observer)) {
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
|
||||
if (($this->auth->owner_id) && (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'view_storage'))) {
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
|
||||
$modulename = get_app()->module;
|
||||
if ($this->red_path === '/' && $name === $modulename) {
|
||||
return new Directory('/' . $modulename, $this->auth);
|
||||
}
|
||||
|
||||
$x = RedFileData($this->ext_path . '/' . $name, $this->auth);
|
||||
if ($x) {
|
||||
return $x;
|
||||
}
|
||||
|
||||
throw new DAV\Exception\NotFound('The file with name: ' . $name . ' could not be found.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the name of the directory.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
//logger(basename($this->red_path), LOGGER_DATA);
|
||||
return (basename($this->red_path));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Renames the directory.
|
||||
*
|
||||
* @todo handle duplicate directory name
|
||||
*
|
||||
* @throw \Sabre\DAV\Exception\Forbidden
|
||||
* @param string $name The new name of the directory.
|
||||
* @return void
|
||||
*/
|
||||
public function setName($name) {
|
||||
logger('old name ' . basename($this->red_path) . ' -> ' . $name, LOGGER_DATA);
|
||||
|
||||
if ((! $name) || (! $this->auth->owner_id)) {
|
||||
logger('permission denied ' . $name);
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
|
||||
if (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage')) {
|
||||
logger('permission denied '. $name);
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
|
||||
list($parent_path, ) = DAV\URLUtil::splitPath($this->red_path);
|
||||
$new_path = $parent_path . '/' . $name;
|
||||
|
||||
$r = q("UPDATE attach SET filename = '%s' WHERE hash = '%s' AND uid = %d",
|
||||
dbesc($name),
|
||||
dbesc($this->folder_hash),
|
||||
intval($this->auth->owner_id)
|
||||
);
|
||||
|
||||
$this->red_path = $new_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a new file in the directory.
|
||||
*
|
||||
* Data will either be supplied as a stream resource, or in certain cases
|
||||
* as a string. Keep in mind that you may have to support either.
|
||||
*
|
||||
* After successful creation of the file, you may choose to return the ETag
|
||||
* of the new file here.
|
||||
*
|
||||
* @throw \Sabre\DAV\Exception\Forbidden
|
||||
* @param string $name Name of the file
|
||||
* @param resource|string $data Initial payload
|
||||
* @return null|string ETag
|
||||
*/
|
||||
public function createFile($name, $data = null) {
|
||||
logger($name, LOGGER_DEBUG);
|
||||
|
||||
if (! $this->auth->owner_id) {
|
||||
logger('permission denied ' . $name);
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
|
||||
if (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage')) {
|
||||
logger('permission denied ' . $name);
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
|
||||
$mimetype = z_mime_content_type($name);
|
||||
|
||||
$c = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1",
|
||||
intval($this->auth->owner_id)
|
||||
);
|
||||
|
||||
if (! $c) {
|
||||
logger('no channel');
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
|
||||
$filesize = 0;
|
||||
$hash = random_string();
|
||||
|
||||
$f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $hash;
|
||||
|
||||
$direct = null;
|
||||
|
||||
if($this->folder_hash) {
|
||||
$r = q("select * from attach where hash = '%s' and is_dir = 1 and uid = %d limit 1",
|
||||
dbesc($this->folder_hash),
|
||||
intval($c[0]['channel_id'])
|
||||
);
|
||||
if($r)
|
||||
$direct = $r[0];
|
||||
}
|
||||
|
||||
if(($direct) && (($direct['allow_cid']) || ($direct['allow_gid']) || ($direct['deny_cid']) || ($direct['deny_gid']))) {
|
||||
$allow_cid = $direct['allow_cid'];
|
||||
$allow_gid = $direct['allow_gid'];
|
||||
$deny_cid = $direct['deny_cid'];
|
||||
$deny_gid = $direct['deny_gid'];
|
||||
}
|
||||
else {
|
||||
$allow_cid = $c[0]['channel_allow_cid'];
|
||||
$allow_gid = $c[0]['channel_allow_gid'];
|
||||
$deny_cid = $c[0]['channel_deny_cid'];
|
||||
$deny_gid = $c[0]['channel_deny_gid'];
|
||||
}
|
||||
|
||||
$r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, folder, os_storage, filetype, filesize, revision, is_photo, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid )
|
||||
VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ",
|
||||
intval($c[0]['channel_account_id']),
|
||||
intval($c[0]['channel_id']),
|
||||
dbesc($hash),
|
||||
dbesc($this->auth->observer),
|
||||
dbesc($name),
|
||||
dbesc($this->folder_hash),
|
||||
intval(1),
|
||||
dbesc($mimetype),
|
||||
intval($filesize),
|
||||
intval(0),
|
||||
intval($is_photo),
|
||||
dbesc($f),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($allow_cid),
|
||||
dbesc($allow_gid),
|
||||
dbesc($deny_cid),
|
||||
dbesc($deny_gid)
|
||||
);
|
||||
|
||||
|
||||
|
||||
// returns the number of bytes that were written to the file, or FALSE on failure
|
||||
$size = file_put_contents($f, $data);
|
||||
// delete attach entry if file_put_contents() failed
|
||||
if ($size === false) {
|
||||
logger('file_put_contents() failed to ' . $f);
|
||||
attach_delete($c[0]['channel_id'], $hash);
|
||||
return;
|
||||
}
|
||||
|
||||
// returns now
|
||||
$edited = datetime_convert();
|
||||
|
||||
|
||||
|
||||
$is_photo = 0;
|
||||
$x = @getimagesize($f);
|
||||
logger('getimagesize: ' . print_r($x,true), LOGGER_DATA);
|
||||
if(($x) && ($x[2] === IMAGETYPE_GIF || $x[2] === IMAGETYPE_JPEG || $x[2] === IMAGETYPE_PNG)) {
|
||||
$is_photo = 1;
|
||||
}
|
||||
|
||||
|
||||
// updates entry with filesize and timestamp
|
||||
$d = q("UPDATE attach SET filesize = '%s', is_photo = %d, edited = '%s' WHERE hash = '%s' AND uid = %d",
|
||||
dbesc($size),
|
||||
intval($is_photo),
|
||||
dbesc($edited),
|
||||
dbesc($hash),
|
||||
intval($c[0]['channel_id'])
|
||||
);
|
||||
|
||||
// update the folder's lastmodified timestamp
|
||||
$e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d",
|
||||
dbesc($edited),
|
||||
dbesc($this->folder_hash),
|
||||
intval($c[0]['channel_id'])
|
||||
);
|
||||
|
||||
$maxfilesize = get_config('system', 'maxfilesize');
|
||||
if (($maxfilesize) && ($size > $maxfilesize)) {
|
||||
attach_delete($c[0]['channel_id'], $hash);
|
||||
return;
|
||||
}
|
||||
|
||||
// check against service class quota
|
||||
$limit = service_class_fetch($c[0]['channel_id'], 'attach_upload_limit');
|
||||
if ($limit !== false) {
|
||||
$x = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d ",
|
||||
intval($c[0]['channel_account_id'])
|
||||
);
|
||||
if (($x) && ($x[0]['total'] + $size > $limit)) {
|
||||
logger('service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . $limit);
|
||||
attach_delete($c[0]['channel_id'], $hash);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if($is_photo) {
|
||||
$album = '';
|
||||
if($this->folder_hash) {
|
||||
$f1 = q("select filename from attach WHERE hash = '%s' AND uid = %d",
|
||||
dbesc($this->folder_hash),
|
||||
intval($c[0]['channel_id'])
|
||||
);
|
||||
if($f1)
|
||||
$album = $f1[0]['filename'];
|
||||
}
|
||||
|
||||
require_once('include/photos.php');
|
||||
$args = array( 'resource_id' => $hash, 'album' => $album, 'os_path' => $f, 'filename' => $name, 'getimagesize' => $x, 'directory' => $direct);
|
||||
$p = photo_upload($c[0],get_app()->get_observer(),$args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a new subdirectory.
|
||||
*
|
||||
* @param string $name the directory to create
|
||||
* @return void
|
||||
*/
|
||||
public function createDirectory($name) {
|
||||
logger($name, LOGGER_DEBUG);
|
||||
|
||||
if ((! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) {
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
|
||||
$r = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1",
|
||||
intval($this->auth->owner_id)
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
$result = attach_mkdir($r[0], $this->auth->observer, array('filename' => $name, 'folder' => $this->folder_hash));
|
||||
if (! $result['success']) {
|
||||
logger('error ' . print_r($result, true), LOGGER_DEBUG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief delete directory
|
||||
*/
|
||||
|
||||
public function delete() {
|
||||
logger('delete file ' . basename($this->red_path), LOGGER_DEBUG);
|
||||
|
||||
if ((! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) {
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
|
||||
if ($this->auth->owner_id !== $this->auth->channel_id) {
|
||||
if (($this->auth->observer !== $this->data['creator']) || intval($this->data['is_dir'])) {
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
}
|
||||
|
||||
attach_delete($this->auth->owner_id, $this->folder_hash);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Checks if a child exists.
|
||||
*
|
||||
* @param string $name
|
||||
* The name to check if it exists.
|
||||
* @return boolean
|
||||
*/
|
||||
public function childExists($name) {
|
||||
// On /cloud we show a list of available channels.
|
||||
// @todo what happens if no channels are available?
|
||||
$modulename = get_app()->module;
|
||||
if ($this->red_path === '/' && $name === $modulename) {
|
||||
//logger('We are at ' $modulename . ' show a channel list', LOGGER_DEBUG);
|
||||
return true;
|
||||
}
|
||||
|
||||
$x = RedFileData($this->ext_path . '/' . $name, $this->auth, true);
|
||||
//logger('RedFileData returns: ' . print_r($x, true), LOGGER_DATA);
|
||||
if ($x)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo add description of what this function does.
|
||||
*
|
||||
* @throw \Sabre\DAV\Exception\NotFound
|
||||
* @return void
|
||||
*/
|
||||
function getDir() {
|
||||
|
||||
logger('GetDir: ' . $this->ext_path, LOGGER_DEBUG);
|
||||
$this->auth->log();
|
||||
$modulename = get_app()->module;
|
||||
|
||||
$file = $this->ext_path;
|
||||
|
||||
$x = strpos($file, '/' . $modulename);
|
||||
if ($x === 0) {
|
||||
$file = substr($file, strlen($modulename) + 1);
|
||||
}
|
||||
|
||||
if ((! $file) || ($file === '/')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$file = trim($file, '/');
|
||||
$path_arr = explode('/', $file);
|
||||
|
||||
if (! $path_arr)
|
||||
return;
|
||||
|
||||
logger('paths: ' . print_r($path_arr, true), LOGGER_DATA);
|
||||
|
||||
$channel_name = $path_arr[0];
|
||||
|
||||
$r = q("SELECT channel_id FROM channel WHERE channel_address = '%s' AND channel_removed = 0 LIMIT 1",
|
||||
dbesc($channel_name)
|
||||
);
|
||||
|
||||
if (! $r) {
|
||||
throw new DAV\Exception\NotFound('The file with name: ' . $channel_name . ' could not be found.');
|
||||
}
|
||||
|
||||
$channel_id = $r[0]['channel_id'];
|
||||
$this->auth->owner_id = $channel_id;
|
||||
$this->auth->owner_nick = $channel_name;
|
||||
|
||||
$path = '/' . $channel_name;
|
||||
$folder = '';
|
||||
$os_path = '';
|
||||
|
||||
for ($x = 1; $x < count($path_arr); $x++) {
|
||||
$r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0",
|
||||
dbesc($folder),
|
||||
dbesc($path_arr[$x]),
|
||||
intval($channel_id)
|
||||
);
|
||||
if ($r && intval($r[0]['is_dir'])) {
|
||||
$folder = $r[0]['hash'];
|
||||
if (strlen($os_path))
|
||||
$os_path .= '/';
|
||||
$os_path .= $folder;
|
||||
|
||||
$path = $path . '/' . $r[0]['filename'];
|
||||
}
|
||||
}
|
||||
$this->folder_hash = $folder;
|
||||
$this->os_path = $os_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the last modification time for the directory, as a UNIX
|
||||
* timestamp.
|
||||
*
|
||||
* It looks for the last edited file in the folder. If it is an empty folder
|
||||
* it returns the lastmodified time of the folder itself, to prevent zero
|
||||
* timestamps.
|
||||
*
|
||||
* @return int last modification time in UNIX timestamp
|
||||
*/
|
||||
public function getLastModified() {
|
||||
$r = q("SELECT edited FROM attach WHERE folder = '%s' AND uid = %d ORDER BY edited DESC LIMIT 1",
|
||||
dbesc($this->folder_hash),
|
||||
intval($this->auth->owner_id)
|
||||
);
|
||||
if (! $r) {
|
||||
$r = q("SELECT edited FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1",
|
||||
dbesc($this->folder_hash),
|
||||
intval($this->auth->owner_id)
|
||||
);
|
||||
if (! $r)
|
||||
return '';
|
||||
}
|
||||
return datetime_convert('UTC', 'UTC', $r[0]['edited'], 'U');
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return quota usage.
|
||||
*
|
||||
* @fixme Should guests relly see the used/free values from filesystem of the
|
||||
* complete store directory?
|
||||
*
|
||||
* @return array with used and free values in bytes.
|
||||
*/
|
||||
public function getQuotaInfo() {
|
||||
// values from the filesystem of the complete <i>store/</i> directory
|
||||
$limit = disk_total_space('store');
|
||||
$free = disk_free_space('store');
|
||||
|
||||
if ($this->auth->owner_id) {
|
||||
$c = q("select * from channel where channel_id = %d and channel_removed = 0 limit 1",
|
||||
intval($this->auth->owner_id)
|
||||
);
|
||||
|
||||
$ulimit = service_class_fetch($c[0]['channel_id'], 'attach_upload_limit');
|
||||
$limit = (($ulimit) ? $ulimit : $limit);
|
||||
|
||||
$x = q("select sum(filesize) as total from attach where aid = %d",
|
||||
intval($c[0]['channel_account_id'])
|
||||
);
|
||||
$free = (($x) ? $limit - $x[0]['total'] : 0);
|
||||
}
|
||||
|
||||
return array(
|
||||
$limit - $free,
|
||||
$free
|
||||
);
|
||||
}
|
||||
}
|
322
sources/Zotlabs/Storage/File.php
Normal file
322
sources/Zotlabs/Storage/File.php
Normal file
|
@ -0,0 +1,322 @@
|
|||
<?php
|
||||
|
||||
namespace Zotlabs\Storage;
|
||||
|
||||
use Sabre\DAV;
|
||||
|
||||
/**
|
||||
* @brief This class represents a file in DAV.
|
||||
*
|
||||
* It provides all functions to work with files in Red's cloud through DAV protocol.
|
||||
*
|
||||
* @extends \Sabre\DAV\Node
|
||||
* @implements \Sabre\DAV\IFile
|
||||
*
|
||||
* @link http://github.com/friendica/red
|
||||
* @license http://opensource.org/licenses/mit-license.php The MIT License (MIT)
|
||||
*/
|
||||
class File extends DAV\Node implements DAV\IFile {
|
||||
|
||||
/**
|
||||
* The file from attach table.
|
||||
*
|
||||
* @var array
|
||||
* data
|
||||
* flags
|
||||
* filename (string)
|
||||
* filetype (string)
|
||||
*/
|
||||
private $data;
|
||||
/**
|
||||
* @see \Sabre\DAV\Auth\Backend\BackendInterface
|
||||
* @var \RedMatrix\RedDAV\RedBasicAuth
|
||||
*/
|
||||
private $auth;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* Sets up the node, expects a full path name.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $data from attach table
|
||||
* @param &$auth
|
||||
*/
|
||||
public function __construct($name, $data, &$auth) {
|
||||
$this->name = $name;
|
||||
$this->data = $data;
|
||||
$this->auth = $auth;
|
||||
|
||||
logger(print_r($this->data, true), LOGGER_DATA);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the name of the file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
//logger(basename($this->name), LOGGER_DATA);
|
||||
return basename($this->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Renames the file.
|
||||
*
|
||||
* @throw Sabre\DAV\Exception\Forbidden
|
||||
* @param string $name The new name of the file.
|
||||
* @return void
|
||||
*/
|
||||
public function setName($newName) {
|
||||
logger('old name ' . basename($this->name) . ' -> ' . $newName, LOGGER_DATA);
|
||||
|
||||
if ((! $newName) || (! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) {
|
||||
logger('permission denied '. $newName);
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
|
||||
$newName = str_replace('/', '%2F', $newName);
|
||||
|
||||
$r = q("UPDATE attach SET filename = '%s' WHERE hash = '%s' AND id = %d",
|
||||
dbesc($newName),
|
||||
dbesc($this->data['hash']),
|
||||
intval($this->data['id'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates the data of the file.
|
||||
*
|
||||
* @param resource $data
|
||||
* @return void
|
||||
*/
|
||||
public function put($data) {
|
||||
logger('put file: ' . basename($this->name), LOGGER_DEBUG);
|
||||
$size = 0;
|
||||
|
||||
// @todo only 3 values are needed
|
||||
$c = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1",
|
||||
intval($this->auth->owner_id)
|
||||
);
|
||||
|
||||
$is_photo = false;
|
||||
$album = '';
|
||||
|
||||
$r = q("SELECT flags, folder, os_storage, filename, is_photo FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1",
|
||||
dbesc($this->data['hash']),
|
||||
intval($c[0]['channel_id'])
|
||||
);
|
||||
if ($r) {
|
||||
if (intval($r[0]['os_storage'])) {
|
||||
$d = q("select folder, data from attach where hash = '%s' and uid = %d limit 1",
|
||||
dbesc($this->data['hash']),
|
||||
intval($c[0]['channel_id'])
|
||||
);
|
||||
if($d) {
|
||||
if($d[0]['folder']) {
|
||||
$f1 = q("select * from attach where is_dir = 1 and hash = '%s' and uid = %d limit 1",
|
||||
dbesc($d[0]['folder']),
|
||||
intval($c[0]['channel_id'])
|
||||
);
|
||||
if($f1) {
|
||||
$album = $f1[0]['filename'];
|
||||
$direct = $f1[0];
|
||||
}
|
||||
}
|
||||
$fname = dbunescbin($d[0]['data']);
|
||||
if(strpos($fname,'store') === false)
|
||||
$f = 'store/' . $this->auth->owner_nick . '/' . $fname ;
|
||||
else
|
||||
$f = $fname;
|
||||
|
||||
// @todo check return value and set $size directly
|
||||
@file_put_contents($f, $data);
|
||||
$size = @filesize($f);
|
||||
logger('filename: ' . $f . ' size: ' . $size, LOGGER_DEBUG);
|
||||
}
|
||||
$gis = @getimagesize($f);
|
||||
logger('getimagesize: ' . print_r($gis,true), LOGGER_DATA);
|
||||
if(($gis) && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG)) {
|
||||
$is_photo = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// this shouldn't happen any more
|
||||
$r = q("UPDATE attach SET data = '%s' WHERE hash = '%s' AND uid = %d",
|
||||
dbescbin(stream_get_contents($data)),
|
||||
dbesc($this->data['hash']),
|
||||
intval($this->data['uid'])
|
||||
);
|
||||
$r = q("SELECT length(data) AS fsize FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1",
|
||||
dbesc($this->data['hash']),
|
||||
intval($this->data['uid'])
|
||||
);
|
||||
if ($r) {
|
||||
$size = $r[0]['fsize'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns now()
|
||||
$edited = datetime_convert();
|
||||
|
||||
$d = q("UPDATE attach SET filesize = '%s', is_photo = %d, edited = '%s' WHERE hash = '%s' AND uid = %d",
|
||||
dbesc($size),
|
||||
intval($is_photo),
|
||||
dbesc($edited),
|
||||
dbesc($this->data['hash']),
|
||||
intval($c[0]['channel_id'])
|
||||
);
|
||||
|
||||
if($is_photo) {
|
||||
require_once('include/photos.php');
|
||||
$args = array( 'resource_id' => $this->data['hash'], 'album' => $album, 'os_path' => $f, 'filename' => $r[0]['filename'], 'getimagesize' => $gis, 'directory' => $direct );
|
||||
$p = photo_upload($c[0],get_app()->get_observer(),$args);
|
||||
}
|
||||
|
||||
// update the folder's lastmodified timestamp
|
||||
$e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d",
|
||||
dbesc($edited),
|
||||
dbesc($r[0]['folder']),
|
||||
intval($c[0]['channel_id'])
|
||||
);
|
||||
|
||||
// @todo do we really want to remove the whole file if an update fails
|
||||
// because of maxfilesize or quota?
|
||||
// There is an Exception "InsufficientStorage" or "PaymentRequired" for
|
||||
// our service class from SabreDAV we could use.
|
||||
|
||||
$maxfilesize = get_config('system', 'maxfilesize');
|
||||
if (($maxfilesize) && ($size > $maxfilesize)) {
|
||||
attach_delete($c[0]['channel_id'], $this->data['hash']);
|
||||
return;
|
||||
}
|
||||
|
||||
$limit = service_class_fetch($c[0]['channel_id'], 'attach_upload_limit');
|
||||
if ($limit !== false) {
|
||||
$x = q("select sum(filesize) as total from attach where aid = %d ",
|
||||
intval($c[0]['channel_account_id'])
|
||||
);
|
||||
if (($x) && ($x[0]['total'] + $size > $limit)) {
|
||||
logger('service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . $limit);
|
||||
attach_delete($c[0]['channel_id'], $this->data['hash']);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the raw data.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get() {
|
||||
logger('get file ' . basename($this->name), LOGGER_DEBUG);
|
||||
logger('os_path: ' . $this->os_path, LOGGER_DATA);
|
||||
|
||||
$r = q("SELECT data, flags, os_storage, filename, filetype FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1",
|
||||
dbesc($this->data['hash']),
|
||||
intval($this->data['uid'])
|
||||
);
|
||||
if ($r) {
|
||||
// @todo this should be a global definition
|
||||
$unsafe_types = array('text/html', 'text/css', 'application/javascript');
|
||||
|
||||
if (in_array($r[0]['filetype'], $unsafe_types)) {
|
||||
header('Content-disposition: attachment; filename="' . $r[0]['filename'] . '"');
|
||||
header('Content-type: text/plain');
|
||||
}
|
||||
|
||||
if (intval($r[0]['os_storage'])) {
|
||||
$x = dbunescbin($r[0]['data']);
|
||||
if(strpos($x,'store') === false)
|
||||
$f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $x;
|
||||
else
|
||||
$f = $x;
|
||||
return fopen($f, 'rb');
|
||||
}
|
||||
return dbunescbin($r[0]['data']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the ETag for a file.
|
||||
*
|
||||
* An ETag is a unique identifier representing the current version of the file.
|
||||
* If the file changes, the ETag MUST change.
|
||||
* The ETag is an arbitrary string, but MUST be surrounded by double-quotes.
|
||||
*
|
||||
* Return null if the ETag can not effectively be determined.
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function getETag() {
|
||||
$ret = null;
|
||||
if ($this->data['hash']) {
|
||||
$ret = '"' . $this->data['hash'] . '"';
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the mime-type for a file.
|
||||
*
|
||||
* If null is returned, we'll assume application/octet-stream
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getContentType() {
|
||||
// @todo this should be a global definition.
|
||||
$unsafe_types = array('text/html', 'text/css', 'application/javascript');
|
||||
if (in_array($this->data['filetype'], $unsafe_types)) {
|
||||
return 'text/plain';
|
||||
}
|
||||
return $this->data['filetype'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the size of the node, in bytes.
|
||||
*
|
||||
* @return int
|
||||
* filesize in bytes
|
||||
*/
|
||||
public function getSize() {
|
||||
return $this->data['filesize'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the last modification time for the file, as a unix
|
||||
* timestamp.
|
||||
*
|
||||
* @return int last modification time in UNIX timestamp
|
||||
*/
|
||||
public function getLastModified() {
|
||||
return datetime_convert('UTC', 'UTC', $this->data['edited'], 'U');
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delete the file.
|
||||
*
|
||||
* This method checks the permissions and then calls attach_delete() function
|
||||
* to actually remove the file.
|
||||
*
|
||||
* @throw \Sabre\DAV\Exception\Forbidden
|
||||
*/
|
||||
public function delete() {
|
||||
logger('delete file ' . basename($this->name), LOGGER_DEBUG);
|
||||
|
||||
if ((! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) {
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
|
||||
if ($this->auth->owner_id !== $this->auth->channel_id) {
|
||||
if (($this->auth->observer !== $this->data['creator']) || intval($this->data['is_dir'])) {
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
}
|
||||
|
||||
attach_delete($this->auth->owner_id, $this->data['hash']);
|
||||
}
|
||||
}
|
66
sources/Zotlabs/Web/HttpMeta.php
Normal file
66
sources/Zotlabs/Web/HttpMeta.php
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
namespace Zotlabs\Web;
|
||||
|
||||
|
||||
class HttpMeta {
|
||||
|
||||
private $vars = null;
|
||||
private $og = null;
|
||||
|
||||
function __construct() {
|
||||
|
||||
$this->vars = array();
|
||||
$this->og = array();
|
||||
|
||||
}
|
||||
|
||||
function set($property,$value) {
|
||||
if(strpos($property,'og:') === 0)
|
||||
$this->og[$property] = $value;
|
||||
else
|
||||
$this->vars[$property] = $value;
|
||||
}
|
||||
|
||||
function check_required() {
|
||||
if(
|
||||
($this->og)
|
||||
&& array_key_exists('og:title',$this->og)
|
||||
&& array_key_exists('og:type', $this->og)
|
||||
&& array_key_exists('og:image',$this->og)
|
||||
&& array_key_exists('og:url', $this->og)
|
||||
)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function get_field($field) {
|
||||
if(strpos($field,'og:') === 0)
|
||||
$arr = $this->og;
|
||||
else
|
||||
$arr = $this->vars;
|
||||
|
||||
if($arr && array_key_exists($field,$arr) && $arr[$field])
|
||||
return $arr[$field];
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function get() {
|
||||
$o = '';
|
||||
if($this->vars) {
|
||||
foreach($this->vars as $k => $v) {
|
||||
$o .= '<meta property="' . $k . '" content="' . urlencode($v) . '" />' . "\r\n" ;
|
||||
}
|
||||
}
|
||||
if($this->check_required()) {
|
||||
foreach($this->og as $k => $v) {
|
||||
$o .= '<meta property="' . $k . '" content="' . urlencode($v) . '" />' . "\r\n" ;
|
||||
}
|
||||
}
|
||||
if($o)
|
||||
return "\r\n" . $o;
|
||||
return $o;
|
||||
}
|
||||
|
||||
}
|
199
sources/Zotlabs/Web/Router.php
Normal file
199
sources/Zotlabs/Web/Router.php
Normal file
|
@ -0,0 +1,199 @@
|
|||
<?php
|
||||
|
||||
namespace Zotlabs\Web;
|
||||
|
||||
|
||||
class Router {
|
||||
|
||||
function __construct(&$a) {
|
||||
|
||||
/**
|
||||
*
|
||||
* We have already parsed the server path into $a->argc and $a->argv
|
||||
*
|
||||
* $a->argv[0] is our module name. We will load the file mod/{$a->argv[0]}.php
|
||||
* and use it for handling our URL request.
|
||||
* The module file contains a few functions that we call in various circumstances
|
||||
* and in the following order:
|
||||
*
|
||||
* "module"_init
|
||||
* "module"_post (only called if there are $_POST variables)
|
||||
* "module"_content - the string return of this function contains our page body
|
||||
*
|
||||
* Modules which emit other serialisations besides HTML (XML,JSON, etc.) should do
|
||||
* so within the module init and/or post functions and then invoke killme() to terminate
|
||||
* further processing.
|
||||
*/
|
||||
|
||||
if(strlen($a->module)) {
|
||||
|
||||
/**
|
||||
*
|
||||
* We will always have a module name.
|
||||
* First see if we have a plugin which is masquerading as a module.
|
||||
*
|
||||
*/
|
||||
|
||||
if(is_array($a->plugins) && in_array($a->module,$a->plugins) && file_exists("addon/{$a->module}/{$a->module}.php")) {
|
||||
include_once("addon/{$a->module}/{$a->module}.php");
|
||||
if(function_exists($a->module . '_module'))
|
||||
$a->module_loaded = true;
|
||||
}
|
||||
|
||||
if((strpos($a->module,'admin') === 0) && (! is_site_admin())) {
|
||||
$a->module_loaded = false;
|
||||
notice( t('Permission denied.') . EOL);
|
||||
goaway(z_root());
|
||||
}
|
||||
|
||||
/**
|
||||
* If the site has a custom module to over-ride the standard module, use it.
|
||||
* Otherwise, look for the standard program module in the 'mod' directory
|
||||
*/
|
||||
|
||||
if(! $a->module_loaded) {
|
||||
if(file_exists("mod/site/{$a->module}.php")) {
|
||||
include_once("mod/site/{$a->module}.php");
|
||||
$a->module_loaded = true;
|
||||
}
|
||||
elseif(file_exists("mod/{$a->module}.php")) {
|
||||
include_once("mod/{$a->module}.php");
|
||||
$a->module_loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This provides a place for plugins to register module handlers which don't otherwise exist on the system.
|
||||
* If the plugin sets 'installed' to true we won't throw a 404 error for the specified module even if
|
||||
* there is no specific module file or matching plugin name.
|
||||
* The plugin should catch at least one of the module hooks for this URL.
|
||||
*/
|
||||
|
||||
$x = array('module' => $a->module, 'installed' => false);
|
||||
call_hooks('module_loaded', $x);
|
||||
if($x['installed'])
|
||||
$a->module_loaded = true;
|
||||
|
||||
/**
|
||||
* The URL provided does not resolve to a valid module.
|
||||
*
|
||||
* On Dreamhost sites, quite often things go wrong for no apparent reason and they send us to '/internal_error.html'.
|
||||
* We don't like doing this, but as it occasionally accounts for 10-20% or more of all site traffic -
|
||||
* we are going to trap this and redirect back to the requested page. As long as you don't have a critical error on your page
|
||||
* this will often succeed and eventually do the right thing.
|
||||
*
|
||||
* Otherwise we are going to emit a 404 not found.
|
||||
*/
|
||||
|
||||
if(! $a->module_loaded) {
|
||||
|
||||
// Stupid browser tried to pre-fetch our Javascript img template. Don't log the event or return anything - just quietly exit.
|
||||
if((x($_SERVER, 'QUERY_STRING')) && preg_match('/{[0-9]}/', $_SERVER['QUERY_STRING']) !== 0) {
|
||||
killme();
|
||||
}
|
||||
|
||||
if((x($_SERVER, 'QUERY_STRING')) && ($_SERVER['QUERY_STRING'] === 'q=internal_error.html') && $a->config['system']['dreamhost_error_hack']) {
|
||||
logger('index.php: dreamhost_error_hack invoked. Original URI =' . $_SERVER['REQUEST_URI']);
|
||||
goaway($a->get_baseurl() . $_SERVER['REQUEST_URI']);
|
||||
}
|
||||
|
||||
logger('index.php: page not found: ' . $_SERVER['REQUEST_URI'] . ' ADDRESS: ' . $_SERVER['REMOTE_ADDR'] . ' QUERY: ' . $_SERVER['QUERY_STRING'], LOGGER_DEBUG);
|
||||
header($_SERVER['SERVER_PROTOCOL'] . ' 404 ' . t('Not Found'));
|
||||
$tpl = get_markup_template('404.tpl');
|
||||
$a->page['content'] = replace_macros($tpl, array(
|
||||
'$message' => t('Page not found.')
|
||||
));
|
||||
|
||||
// pretend this is a module so it will initialise the theme
|
||||
$a->module = '404';
|
||||
$a->module_loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function Dispatch(&$a) {
|
||||
|
||||
/**
|
||||
* Call module functions
|
||||
*/
|
||||
|
||||
if($a->module_loaded) {
|
||||
$a->page['page_title'] = $a->module;
|
||||
$placeholder = '';
|
||||
|
||||
/**
|
||||
* No theme has been specified when calling the module_init functions
|
||||
* For this reason, please restrict the use of templates to those which
|
||||
* do not provide any presentation details - as themes will not be able
|
||||
* to over-ride them.
|
||||
*/
|
||||
|
||||
if(function_exists($a->module . '_init')) {
|
||||
$arr = array('init' => true, 'replace' => false);
|
||||
call_hooks($a->module . '_mod_init', $arr);
|
||||
if(! $arr['replace']) {
|
||||
$func = $a->module . '_init';
|
||||
$func($a);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do all theme initialiasion here before calling any additional module functions.
|
||||
* The module_init function may have changed the theme.
|
||||
* Additionally any page with a Comanche template may alter the theme.
|
||||
* So we'll check for those now.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* In case a page has overloaded a module, see if we already have a layout defined
|
||||
* otherwise, if a PDL file exists for this module, use it
|
||||
* The member may have also created a customised PDL that's stored in the config
|
||||
*/
|
||||
|
||||
load_pdl($a);
|
||||
|
||||
/**
|
||||
* load current theme info
|
||||
*/
|
||||
|
||||
$theme_info_file = 'view/theme/' . current_theme() . '/php/theme.php';
|
||||
if (file_exists($theme_info_file)){
|
||||
require_once($theme_info_file);
|
||||
}
|
||||
|
||||
if(function_exists(str_replace('-', '_', current_theme()) . '_init')) {
|
||||
$func = str_replace('-', '_', current_theme()) . '_init';
|
||||
$func($a);
|
||||
}
|
||||
elseif (x($a->theme_info, 'extends') && file_exists('view/theme/' . $a->theme_info['extends'] . '/php/theme.php')) {
|
||||
require_once('view/theme/' . $a->theme_info['extends'] . '/php/theme.php');
|
||||
if(function_exists(str_replace('-', '_', $a->theme_info['extends']) . '_init')) {
|
||||
$func = str_replace('-', '_', $a->theme_info['extends']) . '_init';
|
||||
$func($a);
|
||||
}
|
||||
}
|
||||
|
||||
if(($_SERVER['REQUEST_METHOD'] === 'POST') && (! $a->error)
|
||||
&& (function_exists($a->module . '_post'))
|
||||
&& (! x($_POST, 'auth-params'))) {
|
||||
call_hooks($a->module . '_mod_post', $_POST);
|
||||
$func = $a->module . '_post';
|
||||
$func($a);
|
||||
}
|
||||
|
||||
if((! $a->error) && (function_exists($a->module . '_content'))) {
|
||||
$arr = array('content' => $a->page['content'], 'replace' => false);
|
||||
call_hooks($a->module . '_mod_content', $arr);
|
||||
$a->page['content'] = $arr['content'];
|
||||
if(! $arr['replace']) {
|
||||
$func = $a->module . '_content';
|
||||
$arr = array('content' => $func($a));
|
||||
}
|
||||
call_hooks($a->module . '_mod_aftercontent', $arr);
|
||||
$a->page['content'] .= $arr['content'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
55
sources/Zotlabs/Zot/DReport.php
Normal file
55
sources/Zotlabs/Zot/DReport.php
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
namespace Zotlabs\Zot;
|
||||
|
||||
class DReport {
|
||||
|
||||
private $location;
|
||||
private $sender;
|
||||
private $recipient;
|
||||
private $message_id;
|
||||
private $status;
|
||||
private $date;
|
||||
|
||||
function __construct($location,$sender,$recipient,$message_id,$status = 'deliver') {
|
||||
$this->location = $location;
|
||||
$this->sender = $sender;
|
||||
$this->recipient = $recipient;
|
||||
$this->message_id = $message_id;
|
||||
$this->status = $status;
|
||||
$this->date = datetime_convert();
|
||||
}
|
||||
|
||||
function update($status) {
|
||||
$this->status = $status;
|
||||
$this->date = datetime_convert();
|
||||
}
|
||||
|
||||
function addto_recipient($name) {
|
||||
$this->recipient = $this->recipient . ' ' . $name;
|
||||
}
|
||||
|
||||
function addto_update($status) {
|
||||
$this->status = $this->status . ' ' . $status;
|
||||
}
|
||||
|
||||
|
||||
function set($arr) {
|
||||
$this->location = $arr['location'];
|
||||
$this->sender = $arr['sender'];
|
||||
$this->recipient = $arr['recipient'];
|
||||
$this->message_id = $arr['message_id'];
|
||||
$this->status = $arr['status'];
|
||||
$this->date = $arr['date'];
|
||||
}
|
||||
|
||||
function get() {
|
||||
return array(
|
||||
'location' => $this->location,
|
||||
'sender' => $this->sender,
|
||||
'recipient' => $this->recipient,
|
||||
'message_id' => $this->message_id,
|
||||
'status' => $this->status,
|
||||
'date' => $this->date
|
||||
);
|
||||
}
|
||||
}
|
|
@ -41,9 +41,10 @@ class Receiver {
|
|||
if(! $this->messagetype)
|
||||
$this->error = true;
|
||||
|
||||
if($this->data) {
|
||||
$this->sender = ((array_key_exists('sender',$this->data)) ? $this->data['sender'] : null);
|
||||
$this->recipients = ((array_key_exists('recipients',$this->data)) ? $this->data['recipients'] : null);
|
||||
|
||||
}
|
||||
|
||||
if($this->sender)
|
||||
$this->ValidateSender();
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
|
||||
namespace Zotlabs\Zot;
|
||||
|
||||
require_once('Zotlabs/Zot/IHandler.php');
|
||||
|
||||
|
||||
class ZotHandler implements IHandler {
|
||||
|
||||
function Ping() {
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
/**
|
||||
* Name: bookmarker
|
||||
* Description: replace #^ with bookmark icon
|
||||
* Version: 1.0
|
||||
* Description: Replace #^ with a bookmark icon. Font awesome is used for Redbasic and derived themes. A neutral dark grey PNG file is used for other themes.
|
||||
* Version: 1.1
|
||||
* Author: Mike Macgirvin <mike@zothub.com>
|
||||
* Maintainer: Mike Macgirvin <mike@macgirvin.com>
|
||||
*
|
||||
|
@ -28,14 +28,16 @@ function bookmarker_prepare_body(&$a,&$b) {
|
|||
if(! strpos($b['html'],'bookmark-identifier'))
|
||||
return;
|
||||
|
||||
if(! function_exists('redbasic_init'))
|
||||
return;
|
||||
if(function_exists('redbasic_init') || get_app()->theme_info['extends'] == 'redbasic')
|
||||
$bookmarkicon = '<i class="icon-bookmark"></i>';
|
||||
else
|
||||
$bookmarkicon = '<img src="addon/bookmarker/bookmarker.png" width="19px" height="20px" alt="#^" />';
|
||||
|
||||
$id = $b['item']['id'];
|
||||
if(local_channel())
|
||||
$link = '<a class="fakelink" onclick="itemBookmark(' . $id . '); return false;" title="' . t('Save Bookmarks') . '" href="#"><i class="icon-bookmark"></i></a> ';
|
||||
$link = '<a class="fakelink" onclick="itemBookmark(' . $id . '); return false;" title="' . t('Save Bookmarks') . '" href="#">'. $bookmarkicon . '</a> ';
|
||||
else
|
||||
$link = '<i class="icon-bookmark"></i></a> ';
|
||||
$link = $bookmarkicon . '</a> ';
|
||||
|
||||
$b['html'] = str_replace('<span class="bookmark-identifier">#^</span>',$link,$b['html']);
|
||||
|
||||
|
|
BIN
sources/addons/bookmarker/bookmarker.png
Normal file
BIN
sources/addons/bookmarker/bookmarker.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 314 B |
|
@ -362,8 +362,10 @@ function diaspora_process_outbound(&$a, &$arr) {
|
|||
}
|
||||
elseif($arr['top_level_post']) {
|
||||
$qi = diaspora_send_status($target_item,$arr['channel'],$contact);
|
||||
if($qi)
|
||||
$arr['queued'][] = $qi;
|
||||
if($qi) {
|
||||
foreach($qi as $q)
|
||||
$arr['queued'][] = $q;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -394,8 +396,10 @@ function diaspora_process_outbound(&$a, &$arr) {
|
|||
if(perm_is_allowed($arr['channel'],'','view_stream')) {
|
||||
logger('delivery: diaspora status: ' . $loc);
|
||||
$qi = diaspora_send_status($target_item,$arr['channel'],$contact,true);
|
||||
if($qi)
|
||||
$arr['queued'][] = $qi;
|
||||
if($qi) {
|
||||
foreach($qi as $q)
|
||||
$arr['queued'][] = $q;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -889,7 +893,7 @@ function diaspora_request($importer,$xml) {
|
|||
// End FIXME
|
||||
|
||||
|
||||
$role = get_pconfig($channel['channel_id'],'system','permissions_role');
|
||||
$role = get_pconfig($importer['channel_id'],'system','permissions_role');
|
||||
if($role) {
|
||||
$x = get_role_perms($role);
|
||||
if($x['perms_auto'])
|
||||
|
@ -938,7 +942,6 @@ function diaspora_request($importer,$xml) {
|
|||
'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'],
|
||||
));
|
||||
|
||||
|
||||
if($default_perms) {
|
||||
// Send back a sharing notification to them
|
||||
$x = diaspora_share($importer,$new_connection[0]);
|
||||
|
@ -957,6 +960,11 @@ function diaspora_request($importer,$xml) {
|
|||
unset($clone['abook_account']);
|
||||
unset($clone['abook_channel']);
|
||||
|
||||
$abconfig = load_abconfig($importer['channel_hash'],$clone['abook_xchan']);
|
||||
|
||||
if($abconfig)
|
||||
$clone['abconfig'] = $abconfig;
|
||||
|
||||
build_sync_packet($importer['channel_id'], array('abook' => array($clone)));
|
||||
|
||||
}
|
||||
|
@ -2695,12 +2703,14 @@ function diaspora_send_status($item,$owner,$contact,$public_batch = false) {
|
|||
|
||||
$slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey'],$public_batch)));
|
||||
|
||||
$qi = diaspora_queue($owner,$contact,$slap,$public_batch,$item['mid']);
|
||||
$qi = array(diaspora_queue($owner,$contact,$slap,$public_batch,$item['mid']));
|
||||
|
||||
// logger('diaspora_send_status: guid: '.$item['mid'].' result '.$return_code, LOGGER_DEBUG);
|
||||
|
||||
if(count($images)) {
|
||||
diaspora_send_images($item,$owner,$contact,$images,$public_batch,$item['mid']);
|
||||
$qim = diaspora_send_images($item,$owner,$contact,$images,$public_batch,$item['mid']);
|
||||
if($qim)
|
||||
$qi = array_merge($qi,$qim);
|
||||
}
|
||||
|
||||
return $qi;
|
||||
|
@ -2761,6 +2771,8 @@ function diaspora_send_images($item,$owner,$contact,$images,$public_batch = fals
|
|||
return;
|
||||
$mysite = substr($a->get_baseurl(),strpos($a->get_baseurl(),'://') + 3) . '/photo';
|
||||
|
||||
$qi = array();
|
||||
|
||||
$tpl = get_markup_template('diaspora_photo.tpl','addon/diaspora');
|
||||
foreach($images as $image) {
|
||||
if(! stristr($image['path'],$mysite))
|
||||
|
@ -2785,13 +2797,14 @@ function diaspora_send_images($item,$owner,$contact,$images,$public_batch = fals
|
|||
'$created_at' => xmlify(datetime_convert('UTC','UTC',$r[0]['created'],'Y-m-d H:i:s \U\T\C'))
|
||||
));
|
||||
|
||||
|
||||
logger('diaspora_send_photo: base message: ' . $msg, LOGGER_DATA);
|
||||
$slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey'],$public_batch)));
|
||||
|
||||
return(diaspora_queue($owner,$contact,$slap,$public_batch,$item['mid']));
|
||||
$qi[] = diaspora_queue($owner,$contact,$slap,$public_batch,$item['mid']);
|
||||
}
|
||||
|
||||
return $qi;
|
||||
|
||||
}
|
||||
|
||||
function diaspora_send_followup($item,$owner,$contact,$public_batch = false) {
|
||||
|
@ -2858,7 +2871,7 @@ function diaspora_send_followup($item,$owner,$contact,$public_batch = false) {
|
|||
// sign it
|
||||
|
||||
if($like)
|
||||
$signed_text = $item['mid'] . ';' . $target_type . ';' . $parent['mid'] . ';' . $positive . ';' . $myaddr;
|
||||
$signed_text = $positive . ';' . $item['mid'] . ';' . $target_type . ';' . $parent['mid'] . ';' . $myaddr;
|
||||
else
|
||||
$signed_text = $item['mid'] . ';' . $parent['mid'] . ';' . $text . ';' . $myaddr;
|
||||
|
||||
|
@ -3445,8 +3458,6 @@ function diaspora_feature_settings_post(&$a,&$b) {
|
|||
|
||||
function diaspora_feature_settings(&$a,&$s) {
|
||||
$dspr_allowed = get_pconfig(local_channel(),'system','diaspora_allowed');
|
||||
if($dspr_allowed === false)
|
||||
$dspr_allowed = get_config('diaspora','allowed');
|
||||
$pubcomments = get_pconfig(local_channel(),'system','diaspora_public_comments');
|
||||
if($pubcomments === false)
|
||||
$pubcomments = 1;
|
||||
|
|
87
sources/addons/diaspora/lang/C/messages.po
Normal file
87
sources/addons/diaspora/lang/C/messages.po
Normal file
|
@ -0,0 +1,87 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C)
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
#
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-02-05 00:26+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: p.php:46 diaspora.php:2679 diaspora.php:2690
|
||||
msgid "$projectname"
|
||||
msgstr ""
|
||||
|
||||
#: diaspora.php:2277
|
||||
msgid "photo"
|
||||
msgstr ""
|
||||
|
||||
#: diaspora.php:2277
|
||||
msgid "status"
|
||||
msgstr ""
|
||||
|
||||
#: diaspora.php:2306
|
||||
#, php-format
|
||||
msgid "%1$s likes %2$s's %3$s"
|
||||
msgstr ""
|
||||
|
||||
#: diaspora.php:2639 diaspora.php:2651
|
||||
msgid "Please choose"
|
||||
msgstr ""
|
||||
|
||||
#: diaspora.php:2641
|
||||
msgid "Agree"
|
||||
msgstr ""
|
||||
|
||||
#: diaspora.php:2643
|
||||
msgid "Disagree"
|
||||
msgstr ""
|
||||
|
||||
#: diaspora.php:2645
|
||||
msgid "Abstain"
|
||||
msgstr ""
|
||||
|
||||
#: diaspora.php:2653
|
||||
msgid "I will attend"
|
||||
msgstr ""
|
||||
|
||||
#: diaspora.php:2655
|
||||
msgid "I will not attend"
|
||||
msgstr ""
|
||||
|
||||
#: diaspora.php:2657
|
||||
msgid "I may attend"
|
||||
msgstr ""
|
||||
|
||||
#: diaspora.php:3441
|
||||
msgid "Diaspora Protocol Settings updated."
|
||||
msgstr ""
|
||||
|
||||
#: diaspora.php:3456
|
||||
msgid "Enable the (experimental) Diaspora protocol for this channel"
|
||||
msgstr ""
|
||||
|
||||
#: diaspora.php:3460
|
||||
msgid "Allow any Diaspora member to comment on your public posts"
|
||||
msgstr ""
|
||||
|
||||
#: diaspora.php:3464
|
||||
msgid "Prevent your hashtags from being redirected to other sites"
|
||||
msgstr ""
|
||||
|
||||
#: diaspora.php:3469
|
||||
msgid "Diaspora Protocol Settings"
|
||||
msgstr ""
|
||||
|
||||
#: diaspora.php:3469
|
||||
msgid "Submit"
|
||||
msgstr ""
|
20
sources/addons/diaspora/lang/nl/strings.php
Normal file
20
sources/addons/diaspora/lang/nl/strings.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
;
|
||||
$a->strings["\$projectname"] = "\$projectname";
|
||||
$a->strings["photo"] = "foto";
|
||||
$a->strings["status"] = "status";
|
||||
$a->strings["%1\$s likes %2\$s's %3\$s"] = "%1\$s vindt %2\$s's %3\$s leuk";
|
||||
$a->strings["Please choose"] = "Maak een keuze";
|
||||
$a->strings["Agree"] = "Eens";
|
||||
$a->strings["Disagree"] = "Oneens";
|
||||
$a->strings["Abstain"] = "Onthouding";
|
||||
$a->strings["I will attend"] = "Aanwezig";
|
||||
$a->strings["I will not attend"] = "Niet aanwezig";
|
||||
$a->strings["I may attend"] = "Mogelijk aanwezig";
|
||||
$a->strings["Diaspora Protocol Settings updated."] = "Diaspora-protocol-instellingen bijgewerkt.";
|
||||
$a->strings["Enable the (experimental) Diaspora protocol for this channel"] = "Het (experimentele) Diaspora-protocol voor dit kanaal inschakelen";
|
||||
$a->strings["Allow any Diaspora member to comment on your public posts"] = "Geef elk Diaspora-lid toestemming om op jouw openbare berichten te reageren";
|
||||
$a->strings["Prevent your hashtags from being redirected to other sites"] = "Voorkom dat jouw hashtags naar andere websites worden doorverwezen";
|
||||
$a->strings["Diaspora Protocol Settings"] = "Diaspora-protocol (compatibiliteit, incl Friendica)";
|
||||
$a->strings["Submit"] = "Opslaan";
|
11
sources/addons/diaspora/view/tpl/diaspora_comment.tpl
Normal file
11
sources/addons/diaspora/view/tpl/diaspora_comment.tpl
Normal file
|
@ -0,0 +1,11 @@
|
|||
<XML>
|
||||
<post>
|
||||
<comment>
|
||||
<guid>{{$guid}}</guid>
|
||||
<parent_guid>{{$parent_guid}}</parent_guid>
|
||||
<text>{{$body}}</text>
|
||||
<diaspora_handle>{{$handle}}</diaspora_handle>
|
||||
<author_signature>{{$authorsig}}</author_signature>
|
||||
</comment>
|
||||
</post>
|
||||
</XML>
|
12
sources/addons/diaspora/view/tpl/diaspora_comment_relay.tpl
Normal file
12
sources/addons/diaspora/view/tpl/diaspora_comment_relay.tpl
Normal file
|
@ -0,0 +1,12 @@
|
|||
<XML>
|
||||
<post>
|
||||
<comment>
|
||||
<guid>{{$guid}}</guid>
|
||||
<parent_guid>{{$parent_guid}}</parent_guid>
|
||||
<text>{{$body}}</text>
|
||||
<diaspora_handle>{{$handle}}</diaspora_handle>
|
||||
<parent_author_signature>{{$parentsig}}</parent_author_signature>
|
||||
<author_signature>{{$authorsig}}</author_signature>
|
||||
</comment>
|
||||
</post>
|
||||
</XML>
|
17
sources/addons/diaspora/view/tpl/diaspora_consensus.tpl
Normal file
17
sources/addons/diaspora/view/tpl/diaspora_consensus.tpl
Normal file
|
@ -0,0 +1,17 @@
|
|||
<poll>
|
||||
<guid>{{$guid_q}}</guid>
|
||||
<question>{{$question}}</question>
|
||||
<poll_answer>
|
||||
<guid>{{$guid_y}}</guid>
|
||||
<answer>{{$agree}}</answer>
|
||||
</poll_answer>
|
||||
<poll_answer>
|
||||
<guid>{{$guid_n}}</guid>
|
||||
<answer>{{$disagree}}</answer>
|
||||
</poll_answer>
|
||||
<poll_answer>
|
||||
<guid>{{$guid_a}}</guid>
|
||||
<answer>{{$abstain}}</answer>
|
||||
</poll_answer>
|
||||
</poll>
|
||||
|
29
sources/addons/diaspora/view/tpl/diaspora_conversation.tpl
Normal file
29
sources/addons/diaspora/view/tpl/diaspora_conversation.tpl
Normal file
|
@ -0,0 +1,29 @@
|
|||
<XML>
|
||||
<post>
|
||||
<conversation>
|
||||
<guid>{{$conv.guid}}</guid>
|
||||
<subject>{{$conv.subject}}</subject>
|
||||
<created_at>{{$conv.created_at}}</created_at>
|
||||
|
||||
{{foreach $conv.messages as $msg}}
|
||||
|
||||
<message>
|
||||
<guid>{{$msg.guid}}</guid>
|
||||
<parent_guid>{{$msg.parent_guid}}</parent_guid>
|
||||
{{if $msg.parent_author_signature}}
|
||||
<parent_author_signature>{{$msg.parent_author_signature}}</parent_author_signature>
|
||||
{{/if}}
|
||||
<author_signature>{{$msg.author_signature}}</author_signature>
|
||||
<text>{{$msg.text}}</text>
|
||||
<created_at>{{$msg.created_at}}</created_at>
|
||||
<diaspora_handle>{{$msg.diaspora_handle}}</diaspora_handle>
|
||||
<conversation_guid>{{$msg.conversation_guid}}</conversation_guid>
|
||||
</message>
|
||||
|
||||
{{/foreach}}
|
||||
|
||||
<diaspora_handle>{{$conv.diaspora_handle}}</diaspora_handle>
|
||||
<participant_handles>{{$conv.participant_handles}}</participant_handles>
|
||||
</conversation>
|
||||
</post>
|
||||
</XML>
|
12
sources/addons/diaspora/view/tpl/diaspora_like.tpl
Normal file
12
sources/addons/diaspora/view/tpl/diaspora_like.tpl
Normal file
|
@ -0,0 +1,12 @@
|
|||
<XML>
|
||||
<post>
|
||||
<like>
|
||||
<positive>{{$positive}}</positive>
|
||||
<guid>{{$guid}}</guid>
|
||||
<target_type>{{$target_type}}</target_type>
|
||||
<parent_guid>{{$parent_guid}}</parent_guid>
|
||||
<diaspora_handle>{{$handle}}</diaspora_handle>
|
||||
<author_signature>{{$authorsig}}</author_signature>
|
||||
</like>
|
||||
</post>
|
||||
</XML>
|
13
sources/addons/diaspora/view/tpl/diaspora_like_relay.tpl
Normal file
13
sources/addons/diaspora/view/tpl/diaspora_like_relay.tpl
Normal file
|
@ -0,0 +1,13 @@
|
|||
<XML>
|
||||
<post>
|
||||
<like>
|
||||
<positive>{{$positive}}</positive>
|
||||
<guid>{{$guid}}</guid>
|
||||
<target_type>{{$target_type}}</target_type>
|
||||
<parent_guid>{{$parent_guid}}</parent_guid>
|
||||
<diaspora_handle>{{$handle}}</diaspora_handle>
|
||||
<parent_author_signature>{{$parentsig}}</parent_author_signature>
|
||||
<author_signature>{{$authorsig}}</author_signature>
|
||||
</like>
|
||||
</post>
|
||||
</XML>
|
16
sources/addons/diaspora/view/tpl/diaspora_message.tpl
Normal file
16
sources/addons/diaspora/view/tpl/diaspora_message.tpl
Normal file
|
@ -0,0 +1,16 @@
|
|||
<XML>
|
||||
<post>
|
||||
<message>
|
||||
<guid>{{$msg.guid}}</guid>
|
||||
<parent_guid>{{$msg.parent_guid}}</parent_guid>
|
||||
{{if $msg.parent_author_signature}}
|
||||
<parent_author_signature>{{$msg.parent_author_signature}}</parent_author_signature>
|
||||
{{/if}}
|
||||
<author_signature>{{$msg.author_signature}}</author_signature>
|
||||
<text>{{$msg.text}}</text>
|
||||
<created_at>{{$msg.created_at}}</created_at>
|
||||
<diaspora_handle>{{$msg.diaspora_handle}}</diaspora_handle>
|
||||
<conversation_guid>{{$msg.conversation_guid}}</conversation_guid>
|
||||
</message>
|
||||
</post>
|
||||
</XML>
|
13
sources/addons/diaspora/view/tpl/diaspora_photo.tpl
Normal file
13
sources/addons/diaspora/view/tpl/diaspora_photo.tpl
Normal file
|
@ -0,0 +1,13 @@
|
|||
<XML>
|
||||
<post>
|
||||
<photo>
|
||||
<guid>{{$guid}}</guid>
|
||||
<diaspora_handle>{{$handle}}</diaspora_handle>
|
||||
<public>{{$public}}</public>
|
||||
<created_at>{{$created_at}}</created_at>
|
||||
<remote_photo_path>{{$path}}</remote_photo_path>
|
||||
<remote_photo_name>{{$filename}}</remote_photo_name>
|
||||
<status_message_guid>{{$msg_guid}}</status_message_guid>
|
||||
</photo>
|
||||
</post>
|
||||
</XML>
|
13
sources/addons/diaspora/view/tpl/diaspora_post.tpl
Normal file
13
sources/addons/diaspora/view/tpl/diaspora_post.tpl
Normal file
|
@ -0,0 +1,13 @@
|
|||
<XML>
|
||||
<post>
|
||||
<status_message>
|
||||
<raw_message>{{$body}}</raw_message>
|
||||
<guid>{{$guid}}</guid>
|
||||
<diaspora_handle>{{$handle}}</diaspora_handle>
|
||||
{{$poll}}
|
||||
<public>{{$public}}</public>
|
||||
<created_at>{{$created}}</created_at>
|
||||
<provider_display_name>{{$provider}}</provider_display_name>
|
||||
</status_message>
|
||||
</post>
|
||||
</XML>
|
17
sources/addons/diaspora/view/tpl/diaspora_profile.tpl
Normal file
17
sources/addons/diaspora/view/tpl/diaspora_profile.tpl
Normal file
|
@ -0,0 +1,17 @@
|
|||
<XML>
|
||||
<post><profile>
|
||||
<diaspora_handle>{{$handle}}</diaspora_handle>
|
||||
<first_name>{{$first}}</first_name>
|
||||
<last_name>{{$last}}</last_name>
|
||||
<image_url>{{$large}}</image_url>
|
||||
<image_url_medium>{{$medium}}</image_url_medium>
|
||||
<image_url_small>{{$small}}</image_url_small>
|
||||
{{if $dob}}<birthday>{{$dob}}</birthday>{{/if}}
|
||||
<gender>{{$gender}}</gender>
|
||||
<bio>{{$about}}</bio>
|
||||
<location>{{$location}}</location>
|
||||
<searchable>{{$searchable}}</searchable>
|
||||
<nsfw>{{$nsfw}}</nsfw>
|
||||
<tag_string>{{$tags}}</tag_string>
|
||||
</profile></post>
|
||||
</XML>
|
|
@ -0,0 +1,10 @@
|
|||
<XML>
|
||||
<post>
|
||||
<relayable_retraction>
|
||||
<target_type>{{$type}}</target_type>
|
||||
<target_guid>{{$guid}}</target_guid>
|
||||
<target_author_signature>{{$signature}}</target_author_signature>
|
||||
<sender_handle>{{$handle}}</sender_handle>
|
||||
</relayable_retraction>
|
||||
</post>
|
||||
</XML>
|
|
@ -0,0 +1,11 @@
|
|||
<XML>
|
||||
<post>
|
||||
<relayable_retraction>
|
||||
<parent_author_signature>{{$parentsig}}</parent_author_signature>
|
||||
<target_guid>{{$guid}}</target_guid>
|
||||
<target_type>{{$target_type}}</target_type>
|
||||
<sender_handle>{{$handle}}</sender_handle>
|
||||
<target_author_signature>{{$authorsig}}</target_author_signature>
|
||||
</relayable_retraction>
|
||||
</post>
|
||||
</XML>
|
13
sources/addons/diaspora/view/tpl/diaspora_reshare.tpl
Normal file
13
sources/addons/diaspora/view/tpl/diaspora_reshare.tpl
Normal file
|
@ -0,0 +1,13 @@
|
|||
<XML>
|
||||
<post>
|
||||
<reshare>
|
||||
<root_diaspora_id>{{$root_handle}}</root_diaspora_id>
|
||||
<root_guid>{{$root_guid}}</root_guid>
|
||||
<guid>{{$guid}}</guid>
|
||||
<diaspora_handle>{{$handle}}</diaspora_handle>
|
||||
<public>{{$public}}</public>
|
||||
<created_at>{{$created}}</created_at>
|
||||
<provider_display_name>{{$provider}}</provider_display_name>
|
||||
</reshare>
|
||||
</post>
|
||||
</XML>
|
9
sources/addons/diaspora/view/tpl/diaspora_retract.tpl
Normal file
9
sources/addons/diaspora/view/tpl/diaspora_retract.tpl
Normal file
|
@ -0,0 +1,9 @@
|
|||
<XML>
|
||||
<post>
|
||||
<retraction>
|
||||
<post_guid>{{$guid}}</post_guid>
|
||||
<diaspora_handle>{{$handle}}</diaspora_handle>
|
||||
<type>{{$type}}</type>
|
||||
</retraction>
|
||||
</post>
|
||||
</XML>
|
8
sources/addons/diaspora/view/tpl/diaspora_share.tpl
Normal file
8
sources/addons/diaspora/view/tpl/diaspora_share.tpl
Normal file
|
@ -0,0 +1,8 @@
|
|||
<XML>
|
||||
<post>
|
||||
<request>
|
||||
<sender_handle>{{$sender}}</sender_handle>
|
||||
<recipient_handle>{{$recipient}}</recipient_handle>
|
||||
</request>
|
||||
</post>
|
||||
</XML>
|
10
sources/addons/diaspora/view/tpl/diaspora_signed_retract.tpl
Normal file
10
sources/addons/diaspora/view/tpl/diaspora_signed_retract.tpl
Normal file
|
@ -0,0 +1,10 @@
|
|||
<XML>
|
||||
<post>
|
||||
<signed_retraction>
|
||||
<target_guid>{{$guid}}</target_guid>
|
||||
<target_type>{{$type}}</target_type>
|
||||
<sender_handle>{{$handle}}</sender_handle>
|
||||
<target_author_signature>{{$signature}}</target_author_signature>
|
||||
</signed_retraction>
|
||||
</post>
|
||||
</XML>
|
57
sources/addons/diaspora/view/tpl/diaspora_vcard.tpl
Normal file
57
sources/addons/diaspora/view/tpl/diaspora_vcard.tpl
Normal file
|
@ -0,0 +1,57 @@
|
|||
<div style="display:none;">
|
||||
<dl class='entity_nickname'>
|
||||
<dt>Nickname</dt>
|
||||
<dd>
|
||||
<a class="nickname url uid" href="{{$diaspora.podloc}}/" rel="me">{{$diaspora.fullname}}</a>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class='entity_fn'>
|
||||
<dt>Full name</dt>
|
||||
<dd>
|
||||
<span class='fn'>{{$diaspora.fullname}}</span>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl class='entity_given_name'>
|
||||
<dt>First name</dt>
|
||||
<dd>
|
||||
<span class='given_name'>{{$diaspora.firstname}}</span>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class='entity_family_name'>
|
||||
<dt>Family name</dt>
|
||||
<dd>
|
||||
<span class='family_name'>{{$diaspora.lastname}}</span>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="entity_url">
|
||||
<dt>URL</dt>
|
||||
<dd>
|
||||
<a class="url" href="{{$diaspora.podloc}}/" id="pod_location" rel="me">{{$diaspora.podloc}}/</a>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="entity_photo">
|
||||
<dt>Photo</dt>
|
||||
<dd>
|
||||
<img class="photo avatar" height="300" width="300" src="{{$diaspora.photo300}}">
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="entity_photo_medium">
|
||||
<dt>Photo</dt>
|
||||
<dd>
|
||||
<img class="photo avatar" height="100" width="100" src="{{$diaspora.photo100}}">
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="entity_photo_small">
|
||||
<dt>Photo</dt>
|
||||
<dd>
|
||||
<img class="photo avatar" height="50" width="50" src="{{$diaspora.photo50}}">
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="entity_searchable">
|
||||
<dt>Searchable</dt>
|
||||
<dd>
|
||||
<span class="searchable">{{$diaspora.searchable}}</span>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
|
@ -6,6 +6,7 @@
|
|||
* Version: 0.1
|
||||
* Author: Michael Vogel <heluecht@pirati.ca>
|
||||
* Maintainer: none
|
||||
* MaxVersion: 1.0
|
||||
*/
|
||||
|
||||
function diaspost_load() {
|
||||
|
|
BIN
sources/addons/gnusoc/gnusoc-32.png
Normal file
BIN
sources/addons/gnusoc/gnusoc-32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
111
sources/addons/gnusoc/gnusoc.php
Normal file
111
sources/addons/gnusoc/gnusoc.php
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* Name: GNU-Social Protocol
|
||||
* Description: GNU-Social Protocol (Experimental, Not-finished, Unsupported)
|
||||
* Version: 1.0
|
||||
* Author: Mike Macgirvin
|
||||
* Maintainer: none
|
||||
* Requires: pubsubhubbub
|
||||
*/
|
||||
|
||||
|
||||
require_once('include/crypto.php');
|
||||
require_once('include/items.php');
|
||||
require_once('include/bb2diaspora.php');
|
||||
require_once('include/contact_selectors.php');
|
||||
require_once('include/queue_fn.php');
|
||||
require_once('include/salmon.php');
|
||||
|
||||
|
||||
function gnusoc_load() {
|
||||
register_hook('module_loaded', 'addon/gnusoc/gnusoc.php', 'gnusoc_load_module');
|
||||
register_hook('webfinger', 'addon/gnusoc/gnusoc.php', 'gnusoc_webfinger');
|
||||
register_hook('personal_xrd', 'addon/gnusoc/gnusoc.php', 'gnusoc_personal_xrd');
|
||||
register_hook('follow_allow', 'addon/gnusoc/gnusoc.php', 'gnusoc_follow_allow');
|
||||
register_hook('feature_settings_post', 'addon/gnusoc/gnusoc.php', 'gnusoc_feature_settings_post');
|
||||
register_hook('feature_settings', 'addon/gnusoc/gnusoc.php', 'gnusoc_feature_settings');
|
||||
|
||||
|
||||
// register_hook('notifier_hub', 'addon/gnusoc/gnusoc.php', 'gnusoc_process_outbound');
|
||||
// register_hook('permissions_create', 'addon/gnusoc/gnusoc.php', 'gnusoc_permissions_create');
|
||||
// register_hook('permissions_update', 'addon/gnusoc/gnusoc.php', 'gnusoc_permissions_update');
|
||||
|
||||
}
|
||||
|
||||
function gnusoc_unload() {
|
||||
unregister_hook('module_loaded', 'addon/gnusoc/gnusoc.php', 'gnusoc_load_module');
|
||||
unregister_hook('webfinger', 'addon/gnusoc/gnusoc.php', 'gnusoc_webfinger');
|
||||
unregister_hook('personal_xrd', 'addon/gnusoc/gnusoc.php', 'gnusoc_personal_xrd');
|
||||
unregister_hook('follow_allow', 'addon/gnusoc/gnusoc.php', 'gnusoc_follow_allow');
|
||||
unregister_hook('feature_settings_post', 'addon/gnusoc/gnusoc.php', 'gnusoc_feature_settings_post');
|
||||
unregister_hook('feature_settings', 'addon/gnusoc/gnusoc.php', 'gnusoc_feature_settings');
|
||||
|
||||
}
|
||||
|
||||
// @fixme - subscribe to hub(s) on follow
|
||||
|
||||
|
||||
function gnusoc_load_module(&$a, &$b) {
|
||||
if($b['module'] === 'salmon') {
|
||||
require_once('addon/gnusoc/salmon.php');
|
||||
$b['installed'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function gnusoc_webfinger(&$a,&$b) {
|
||||
$b['result']['links'][] = array('rel' => 'salmon', 'href' => z_root() . '/salmon/' . $b['channel']['channel_address']);
|
||||
}
|
||||
|
||||
function gnusoc_personal_xrd(&$a,&$b) {
|
||||
$b['xml'] = str_replace('</XRD>',
|
||||
'<Link rel="salmon" href="' . z_root() . '/salmon/' . $b['user']['channel_address'] . '" />' . "\r\n" . '</XRD>', $b['xml']);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function gnusoc_follow_allow(&$a, &$b) {
|
||||
|
||||
if($b['xchan']['xchan_network'] !== 'gnusoc')
|
||||
return;
|
||||
|
||||
$allowed = get_pconfig($b['channel_id'],'system','gnusoc_allowed');
|
||||
if($allowed === false)
|
||||
$allowed = 1;
|
||||
$b['allowed'] = $allowed;
|
||||
$b['singleton'] = 1; // this network does not support channel clones
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function gnusoc_feature_settings_post(&$a,&$b) {
|
||||
|
||||
if($_POST['gnusoc-submit']) {
|
||||
set_pconfig(local_channel(),'system','gnusoc_allowed',intval($_POST['gnusoc_allowed']));
|
||||
info( t('GNU-Social Protocol Settings updated.') . EOL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function gnusoc_feature_settings(&$a,&$s) {
|
||||
$gnusoc_allowed = get_pconfig(local_channel(),'system','gnusoc_allowed');
|
||||
if($gnusoc_allowed === false)
|
||||
$gnus_allowed = get_config('gnusoc','allowed');
|
||||
|
||||
$sc .= replace_macros(get_markup_template('field_checkbox.tpl'), array(
|
||||
'$field' => array('gnusoc_allowed', t('Enable the (experimental) GNU-Social protocol for this channel'), $gnusoc_allowed, '', $yes_no),
|
||||
));
|
||||
|
||||
$s .= replace_macros(get_markup_template('generic_addon_settings.tpl'), array(
|
||||
'$addon' => array('gnusoc', '<img src="addon/gnusoc/gnusoc-32.png" style="width:auto; height:1em; margin:-3px 5px 0px 0px;">' . t('GNU-Social Protocol Settings'), '', t('Submit')),
|
||||
'$content' => $sc
|
||||
));
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
387
sources/addons/gnusoc/salmon.php
Normal file
387
sources/addons/gnusoc/salmon.php
Normal file
|
@ -0,0 +1,387 @@
|
|||
<?php
|
||||
|
||||
require_once('include/salmon.php');
|
||||
require_once('include/crypto.php');
|
||||
require_once('include/items.php');
|
||||
require_once('include/follow.php');
|
||||
require_once('include/Contact.php');
|
||||
|
||||
function salmon_return($val) {
|
||||
|
||||
if($val >= 400)
|
||||
$err = 'Error';
|
||||
if($val >= 200 && $val < 300)
|
||||
$err = 'OK';
|
||||
|
||||
logger('mod-salmon returns ' . $val);
|
||||
header($_SERVER["SERVER_PROTOCOL"] . ' ' . $val . ' ' . $err);
|
||||
killme();
|
||||
|
||||
}
|
||||
|
||||
function salmon_post(&$a) {
|
||||
|
||||
$xml = file_get_contents('php://input');
|
||||
|
||||
logger('mod-salmon: new salmon ' . $xml, LOGGER_DATA);
|
||||
|
||||
$nick = ((argc() > 1) ? trim(argv(1)) : '');
|
||||
// $mentions = (($a->argc > 2 && $a->argv[2] === 'mention') ? true : false);
|
||||
|
||||
|
||||
$importer = channelx_by_nick($nick);
|
||||
|
||||
if(! $importer)
|
||||
http_status_exit(500);
|
||||
|
||||
// @fixme check that this channel has the GNU-Social protocol enabled
|
||||
|
||||
|
||||
// parse the xml
|
||||
|
||||
$dom = simplexml_load_string($xml,'SimpleXMLElement',0,NAMESPACE_SALMON_ME);
|
||||
|
||||
// figure out where in the DOM tree our data is hiding
|
||||
|
||||
if($dom->provenance->data)
|
||||
$base = $dom->provenance;
|
||||
elseif($dom->env->data)
|
||||
$base = $dom->env;
|
||||
elseif($dom->data)
|
||||
$base = $dom;
|
||||
|
||||
if(! $base) {
|
||||
logger('mod-salmon: unable to locate salmon data in xml ');
|
||||
http_status_exit(400);
|
||||
}
|
||||
|
||||
logger('data: ' . $xml, LOGGER_DATA);
|
||||
|
||||
// Stash the signature away for now. We have to find their key or it won't be good for anything.
|
||||
|
||||
|
||||
$signature = base64url_decode($base->sig);
|
||||
|
||||
// unpack the data
|
||||
|
||||
// strip whitespace so our data element will return to one big base64 blob
|
||||
$data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$base->data);
|
||||
|
||||
|
||||
// stash away some other stuff for later
|
||||
|
||||
$type = $base->data[0]->attributes()->type[0];
|
||||
$keyhash = $base->sig[0]->attributes()->keyhash[0];
|
||||
$encoding = $base->encoding;
|
||||
$alg = $base->alg;
|
||||
|
||||
// Salmon magic signatures have evolved and there is no way of knowing ahead of time which
|
||||
// flavour we have. We'll try and verify it regardless.
|
||||
|
||||
$stnet_signed_data = $data;
|
||||
|
||||
$signed_data = $data . '.' . base64url_encode($type) . '.' . base64url_encode($encoding) . '.' . base64url_encode($alg);
|
||||
|
||||
$compliant_format = str_replace('=','',$signed_data);
|
||||
|
||||
|
||||
// decode the data
|
||||
$data = base64url_decode($data);
|
||||
|
||||
logger('decoded: ' . $data, LOGGER_DATA);
|
||||
|
||||
// GNU-Social doesn't send a legal Atom feed over salmon, only an Atom entry. Unfortunately
|
||||
// our parser is a bit strict about compliance so we'll insert just enough of a feed
|
||||
// tag to trick it into believing it's a compliant feed.
|
||||
|
||||
if(! strstr($data,'<feed')) {
|
||||
$data = str_replace('<entry ','<feed xmlns="http://www.w3.org/2005/Atom"><entry ',$data);
|
||||
$data .= '</feed>';
|
||||
}
|
||||
|
||||
$datarray = process_salmon_feed($data,$importer);
|
||||
|
||||
$author_link = $datarray['author']['author_link'];
|
||||
|
||||
if(! $author_link) {
|
||||
logger('mod-salmon: Could not retrieve author URI.');
|
||||
http_status_exit(400);
|
||||
}
|
||||
|
||||
$r = q("select xchan_pubkey from xchan where xchan_guid = '%s' limit 1",
|
||||
dbesc($author_link)
|
||||
);
|
||||
|
||||
if($r) {
|
||||
$pubkey = $r[0]['xchan_pubkey'];
|
||||
}
|
||||
else {
|
||||
|
||||
// Once we have the author URI, go to the web and try to find their public key
|
||||
|
||||
logger('mod-salmon: Fetching key for ' . $author_link);
|
||||
|
||||
$key = get_salmon_key($author_link,$keyhash);
|
||||
|
||||
if(! $key) {
|
||||
logger('mod-salmon: Could not retrieve author key.');
|
||||
http_status_exit(400);
|
||||
}
|
||||
|
||||
$key_info = explode('.',$key);
|
||||
|
||||
$m = base64url_decode($key_info[1]);
|
||||
$e = base64url_decode($key_info[2]);
|
||||
|
||||
logger('mod-salmon: key details: ' . print_r($key_info,true), LOGGER_DEBUG);
|
||||
|
||||
$pubkey = metopem($m,$e);
|
||||
}
|
||||
|
||||
// We should have everything we need now. Let's see if it verifies.
|
||||
|
||||
$verify = rsa_verify($compliant_format,$signature,$pubkey);
|
||||
|
||||
if(! $verify) {
|
||||
logger('mod-salmon: message did not verify using protocol. Trying padding hack.');
|
||||
$verify = rsa_verify($signed_data,$signature,$pubkey);
|
||||
}
|
||||
|
||||
if(! $verify) {
|
||||
logger('mod-salmon: message did not verify using padding. Trying old statusnet hack.');
|
||||
$verify = rsa_verify($stnet_signed_data,$signature,$pubkey);
|
||||
}
|
||||
|
||||
if(! $verify) {
|
||||
logger('mod-salmon: Message did not verify. Discarding.');
|
||||
http_status_exit(400);
|
||||
}
|
||||
|
||||
logger('mod-salmon: Message verified.');
|
||||
|
||||
|
||||
/* lookup the author */
|
||||
|
||||
if(! $datarray['author']['author_link'])
|
||||
logger('unable to probe - no author identifier');
|
||||
http_status_exit(400);
|
||||
}
|
||||
|
||||
$r = q("select * from xchan where xchan_guid = '%s' limit 1",
|
||||
dbesc($datarray['author']['author_link'])
|
||||
);
|
||||
if(! $r) {
|
||||
if(discover_by_webbie($datarray['author']['author_link'])) {
|
||||
$r = q("select xchan_hash from xchan where xchan_guid = '%s' limit 1",
|
||||
dbesc($datarray['author']['author_link'])
|
||||
);
|
||||
if(! $r) {
|
||||
logger('discovery failed');
|
||||
http_status_exit(400);
|
||||
}
|
||||
}
|
||||
|
||||
$xchan = $r[0];
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* If we reached this point, the message is good. Now let's figure out if the author is allowed to send us stuff.
|
||||
*
|
||||
*/
|
||||
|
||||
// First check for and process follow activity
|
||||
|
||||
if(activity_match($datarray['verb'],ACTIVITY_FOLLOW) && $datarray['obj_type'] === ACTIVITY_OBJ_PERSON) {
|
||||
|
||||
$r = q("select * from abook where abook_channel = %d and abook_hash = '%s' limit 1",
|
||||
intval($importer['channel_id']),
|
||||
dbesc($xchan['xchan_hash'])
|
||||
);
|
||||
|
||||
if($r) {
|
||||
$contact = $r[0];
|
||||
$newperms = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK|PERMS_W_STREAM|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT|PERMS_R_STORAGE|PERMS_R_PAGES;
|
||||
|
||||
$abook_instance = $contact['abook_instance'];
|
||||
if($abook_instance)
|
||||
$abook_instance .= ',';
|
||||
$abook_instance .= z_root();
|
||||
|
||||
|
||||
$r = q("update abook set abook_their_perms = %d, abook_instance = '%s' where abook_id = %d and abook_channel = %d",
|
||||
intval($newperms),
|
||||
dbesc($abook_instance),
|
||||
intval($contact['abook_id']),
|
||||
intval($importer['channel_id'])
|
||||
);
|
||||
}
|
||||
else {
|
||||
$role = get_pconfig($importer['channel_id'],'system','permissions_role');
|
||||
if($role) {
|
||||
$x = get_role_perms($role);
|
||||
if($x['perms_auto'])
|
||||
$default_perms = $x['perms_accept'];
|
||||
}
|
||||
if(! $default_perms)
|
||||
$default_perms = intval(get_pconfig($importer['channel_id'],'system','autoperms'));
|
||||
|
||||
$their_perms = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK|PERMS_W_STREAM|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT|PERMS_R_STORAGE|PERMS_R_PAGES;
|
||||
|
||||
|
||||
$closeness = get_pconfig($importer['channel_id'],'system','new_abook_closeness');
|
||||
if($closeness === false)
|
||||
$closeness = 80;
|
||||
|
||||
|
||||
$r = q("insert into abook ( abook_account, abook_channel, abook_xchan, abook_my_perms, abook_their_perms, abook_closeness, abook_created, abook_updated, abook_connected, abook_dob, abook_pending, abook_instance ) values ( %d, %d, '%s', %d, %d, %d, '%s', '%s', '%s', '%s', %d, '%s' )",
|
||||
intval($importer['channel_account_id']),
|
||||
intval($importer['channel_id']),
|
||||
dbesc($contact['xchan_hash']),
|
||||
intval($default_perms),
|
||||
intval($their_perms),
|
||||
intval($closeness),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc(NULL_DATE),
|
||||
intval(($default_perms) ? 0 : 1),
|
||||
dbesc(z_root())
|
||||
);
|
||||
if($r) {
|
||||
logger("New GNU-Social follower received for {$importer['channel_name']}");
|
||||
|
||||
$new_connection = q("select * from abook left join xchan on abook_xchan = xchan_hash left join hubloc on hubloc_hash = xchan_hash where abook_channel = %d and abook_xchan = '%s' order by abook_created desc limit 1",
|
||||
intval($importer['channel_id']),
|
||||
dbesc($xchan['xchan_hash'])
|
||||
);
|
||||
|
||||
if($new_connection) {
|
||||
require_once('include/enotify.php');
|
||||
notification(array(
|
||||
'type' => NOTIFY_INTRO,
|
||||
'from_xchan' => $xchan['xchan_hash'],
|
||||
'to_xchan' => $importer['channel_hash'],
|
||||
'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'],
|
||||
));
|
||||
|
||||
if($default_perms) {
|
||||
// @fixme!!!
|
||||
// Send back a sharing notification to them
|
||||
$x = gnusoc_follow($importer,$new_connection[0]);
|
||||
if($x)
|
||||
proc_run('php','include/deliver.php',$x);
|
||||
|
||||
}
|
||||
|
||||
$clone = array();
|
||||
foreach($new_connection[0] as $k => $v) {
|
||||
if(strpos($k,'abook_') === 0) {
|
||||
$clone[$k] = $v;
|
||||
}
|
||||
}
|
||||
unset($clone['abook_id']);
|
||||
unset($clone['abook_account']);
|
||||
unset($clone['abook_channel']);
|
||||
|
||||
$abconfig = load_abconfig($importer['channel_hash'],$clone['abook_xchan']);
|
||||
|
||||
if($abconfig)
|
||||
$clone['abconfig'] = $abconfig;
|
||||
|
||||
build_sync_packet($importer['channel_id'], array('abook' => array($clone)));
|
||||
|
||||
}
|
||||
|
||||
http_status_exit(200);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//
|
||||
// ... fixme
|
||||
|
||||
|
||||
// Otherwise check general permissions
|
||||
|
||||
if(! perm_is_allowed($importer['channel_id'],$xchan['xchan_hash'],'send_stream')) {
|
||||
|
||||
// check for and process ostatus autofriend
|
||||
|
||||
|
||||
// ... fixme
|
||||
|
||||
|
||||
|
||||
// otherwise
|
||||
|
||||
logger('mod-salmon: Ignoring this author.');
|
||||
http_status_exit(202);
|
||||
// NOTREACHED
|
||||
}
|
||||
|
||||
unset($datarray['author']);
|
||||
|
||||
$parent_item = null;
|
||||
if($datarray['parent_mid']) {
|
||||
$r = q("select * from item where mid = '%s' and uid = %d limit 1",
|
||||
dbesc($datarray['parent_mid']),
|
||||
intval($importer['channel_id'])
|
||||
);
|
||||
if(! $r) {
|
||||
logger('mod-salmon: parent item not found.');
|
||||
http_status_exit(202);
|
||||
}
|
||||
$parent_item = $r[0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if(! $datarray['author_xchan'])
|
||||
$datarray['author_xchan'] = $xchan['xchan_hash'];
|
||||
|
||||
$datarray['owner_xchan'] = (($parent_item) ? $parent_item['owner_xchan'] : $xchan['xchan_hash']);
|
||||
|
||||
|
||||
|
||||
$r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1",
|
||||
dbesc($datarray['mid']),
|
||||
intval($importer['channel_id'])
|
||||
);
|
||||
|
||||
|
||||
// Update content if 'updated' changes
|
||||
// currently a no-op @fixme
|
||||
|
||||
if($r) {
|
||||
if((x($datarray,'edited') !== false) && (datetime_convert('UTC','UTC',$datarray['edited']) !== $r[0]['edited'])) {
|
||||
// do not accept (ignore) an earlier edit than one we currently have.
|
||||
if(datetime_convert('UTC','UTC',$datarray['edited']) > $r[0]['edited'])
|
||||
update_feed_item($importer['channel_id'],$datarray);
|
||||
}
|
||||
http_status_exit(200);
|
||||
}
|
||||
|
||||
if(! $datarray['parent_mid'])
|
||||
$datarray['parent_mid'] = $datarray['mid'];
|
||||
|
||||
$datarray['aid'] = $importer['channel_account_id'];
|
||||
$datarray['uid'] = $importer['channel_id'];
|
||||
|
||||
logger('consume_feed: ' . print_r($datarray,true),LOGGER_DATA);
|
||||
|
||||
$xx = item_store($datarray);
|
||||
$r = $xx['item_id'];
|
||||
|
||||
// if this is a reply, do a relay?
|
||||
|
||||
http_status_exit(200);
|
||||
}
|
||||
|
||||
|
||||
function gnusoc_follow($importer,$xchan) {
|
||||
|
||||
|
||||
|
||||
}
|
80
sources/addons/hubwall/hubwall.php
Normal file
80
sources/addons/hubwall/hubwall.php
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Name: Hubwall
|
||||
* Description: Send admin email message to all account holders
|
||||
* Version: 1.0
|
||||
* Author: Mike Macgirvin
|
||||
* Maintainer: none
|
||||
*/
|
||||
|
||||
require_once('include/enotify.php');
|
||||
|
||||
function hubwall_module() {}
|
||||
|
||||
|
||||
|
||||
function hubwall_post(&$a) {
|
||||
if(! is_site_admin())
|
||||
return;
|
||||
|
||||
$text = trim($_REQUEST['text']);
|
||||
if(! $text)
|
||||
return;
|
||||
|
||||
$sender_name = t('Hub Administrator');
|
||||
$sender_email = 'sys@' . $a->get_hostname();
|
||||
|
||||
$subject = $_REQUEST['subject'];
|
||||
|
||||
|
||||
$textversion = strip_tags(html_entity_decode(bbcode(stripslashes(str_replace(array("\\r", "\\n"),array( "", "\n"), $text))),ENT_QUOTES,'UTF-8'));
|
||||
|
||||
$htmlversion = bbcode(stripslashes(str_replace(array("\\r","\\n"), array("","<br />\n"),$text)));
|
||||
|
||||
$sql_extra = ((intval($_REQUEST['test'])) ? sprintf(" and account_email = '%s' ", get_config('system','admin_email')) : '');
|
||||
|
||||
|
||||
$recips = q("select account_email from account where account_flags = %d $sql_extra",
|
||||
intval(ACCOUNT_OK)
|
||||
);
|
||||
|
||||
if(! $recips) {
|
||||
notice( t('No recipients found.') . EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach($recips as $recip) {
|
||||
|
||||
|
||||
enotify::send(array(
|
||||
'fromName' => $sender_name,
|
||||
'fromEmail' => $sender_email,
|
||||
'replyTo' => $sender_email,
|
||||
'toEmail' => $recip['account_email'],
|
||||
'messageSubject' => $subject,
|
||||
'htmlVersion' => $htmlversion,
|
||||
'textVersion' => $textversion
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function hubwall_content(&$a) {
|
||||
if(! is_site_admin())
|
||||
return;
|
||||
|
||||
$title = t('Send email to all hub members.');
|
||||
|
||||
$o = replace_macros(get_markup_template('hubwall_form.tpl','addon/hubwall/'),array(
|
||||
'$title' => $title,
|
||||
'$text' => htmlspecialchars($_REQUEST['text']),
|
||||
'$subject' => array('subject',t('Message subject'),$_REQUEST['subject'],''),
|
||||
'$test' => array('test',t('Test mode (only send to hub administrator)'), 0,''),
|
||||
'$submit' => t('Submit')
|
||||
));
|
||||
|
||||
return $o;
|
||||
|
||||
}
|
12
sources/addons/hubwall/view/tpl/hubwall_form.tpl
Normal file
12
sources/addons/hubwall/view/tpl/hubwall_form.tpl
Normal file
|
@ -0,0 +1,12 @@
|
|||
<h3>{{$title}}</h3>
|
||||
|
||||
<form action="hubwall" method="post">
|
||||
|
||||
{{include file="field_checkbox.tpl" field=$test}}
|
||||
{{include file="field_input.tpl" field=$subject}}
|
||||
|
||||
<textarea name="text" style="width:100%; height:150px;">{{$text}}</textarea>
|
||||
<br />
|
||||
<input type="submit" name="submit" value="{{$submit}}" />
|
||||
</form>
|
||||
|
9
sources/addons/ijpost/lang/nl/strings.php
Normal file
9
sources/addons/ijpost/lang/nl/strings.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
$a->strings["Post to Insanejournal"] = "Doorplaatsen naar InsaneJournal";
|
||||
$a->strings["InsaneJournal Post Settings"] = "InsaneJournal (berichten doorplaatsen)";
|
||||
$a->strings["Enable InsaneJournal Post Plugin"] = "Doorplaatsen naar InsaneJournal inschakelen";
|
||||
$a->strings["InsaneJournal username"] = "Gebruikersnaam InsaneJournal";
|
||||
$a->strings["InsaneJournal password"] = "Wachtwoord InsaneJournal";
|
||||
$a->strings["Post to InsaneJournal by default"] = "Berichten standaard naar InsaneJournal doorplaatsen";
|
||||
$a->strings["Submit"] = "Opslaan";
|
11
sources/addons/js_upload/lang/nl/strings.php
Normal file
11
sources/addons/js_upload/lang/nl/strings.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
$a->strings["Upload a file"] = "Bestand uploaden";
|
||||
$a->strings["Drop files here to upload"] = "Sleep bestanden hier naartoe om te uploaden";
|
||||
$a->strings["Cancel"] = "Annuleren";
|
||||
$a->strings["Failed"] = "Mislukt";
|
||||
$a->strings["No files were uploaded."] = "Er zijn geen bestanden geüpload.";
|
||||
$a->strings["Uploaded file is empty"] = "Geüpload bestand is leeg";
|
||||
$a->strings["Image exceeds size limit of "] = "Bestandsgrootte afbeelding overschrijdt limiet van ";
|
||||
$a->strings["File has an invalid extension, it should be one of "] = "Het bestand heeft een ongeldige bestandsextensie, geldig zijn ";
|
||||
$a->strings["Upload was cancelled, or server error encountered"] = "Uploaden is geannuleerd of er is sprake van een serverfout";
|
45
sources/addons/keepout/keepout.php
Normal file
45
sources/addons/keepout/keepout.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Name: Keep Out
|
||||
* Description: Block public completely, IMPORTANT: off grid use ONLY
|
||||
* Version: 1.0
|
||||
* Author: Macgirvin
|
||||
* Maintainer: none
|
||||
* MinVersion: 1.1.4
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
function keepout_urls() {
|
||||
return array(
|
||||
'blocks','bookmarks','channel','chat','cloud','connections','connedit','cover_photo','directory','dirsearch','display','editblock','editlayout','editpost','editwebpage','events','feed','filestorage','hcard','hostxrd','layouts','mail','manage','menu','mitem','network','online','page','pconfig','pdledit','photos','poco','profile','public','search','siteinfo','siteinfo_json','thing','viewsrc','webpages','wfinger','xchan','xpoco','xrd','zcard','zotfeed');
|
||||
}
|
||||
|
||||
function keepout_load() {
|
||||
foreach(keepout_urls() as $x) {
|
||||
register_hook($x . '_mod_init', 'addon/keepout/keepout.php', 'keepout_mod_init');
|
||||
register_hook($x . '_mod_content', 'addon/keepout/keepout.php', 'keepout_mod_content');
|
||||
}
|
||||
}
|
||||
|
||||
function keepout_unload() {
|
||||
foreach(keepout_urls() as $x) {
|
||||
unregister_hook($x . '_mod_init', 'addon/keepout/keepout.php', 'keepout_mod_init');
|
||||
unregister_hook($x . '_mod_content', 'addon/keepout/keepout.php', 'keepout_mod_content');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function keepout_mod_init(&$a,&$b) {
|
||||
if((get_config('system','block_public')) && (! get_account_id()) && (! remote_channel())) {
|
||||
notice( t('Permission denied.') . EOL);
|
||||
$b['replace'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function keepout_mod_content(&$a,&$b) {
|
||||
if((get_config('system','block_public')) && (! get_account_id()) && (! remote_channel()))
|
||||
$b['replace'] = true;
|
||||
}
|
9
sources/addons/libertree/lang/nl/strings.php
Normal file
9
sources/addons/libertree/lang/nl/strings.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
$a->strings["Post to Libertree"] = "Doorplaatsen naar Libertree";
|
||||
$a->strings["Libertree Post Settings"] = "Libertree (berichten doorplaatsen)";
|
||||
$a->strings["Enable Libertree Post Plugin"] = "Doorplaatsen naar Libertree inschakelen";
|
||||
$a->strings["Libertree API token"] = "API-token Libertree";
|
||||
$a->strings["Libertree site URL"] = "Website-URL Libertree";
|
||||
$a->strings["Post to Libertree by default"] = "Berichten standaard naar Libertree doorplaatsen";
|
||||
$a->strings["Submit"] = "Opslaan";
|
9
sources/addons/ljpost/lang/nl/strings.php
Normal file
9
sources/addons/ljpost/lang/nl/strings.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
$a->strings["Post to LiveJournal"] = "Doorplaatsen naar LiveJournal";
|
||||
$a->strings["LiveJournal Post Settings"] = "LiveJournal (berichten doorplaatsen)";
|
||||
$a->strings["Enable LiveJournal Post Plugin"] = "Doorplaatsen naar LiveJournal inschakelen";
|
||||
$a->strings["LiveJournal username"] = "Gebruikersnaam LiveJournal";
|
||||
$a->strings["LiveJournal password"] = "Wachtwoord LiveJournal";
|
||||
$a->strings["Post to LiveJournal by default"] = "Berichten standaard naar LiveJournal doorplaatsen";
|
||||
$a->strings["Submit"] = "Opslaan";
|
340
sources/addons/metatag/LICENSE
Normal file
340
sources/addons/metatag/LICENSE
Normal file
|
@ -0,0 +1,340 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{description}
|
||||
Copyright (C) {year} {fullname}
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
{signature of Ty Coon}, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
|
1
sources/addons/metatag/README.md
Normal file
1
sources/addons/metatag/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
# release 1.2
|
22
sources/addons/metatag/install.txt
Normal file
22
sources/addons/metatag/install.txt
Normal file
|
@ -0,0 +1,22 @@
|
|||
Example of configuration in .htconfig.php
|
||||
Uncomment hreflang and setup your on Language Code if you like to get index in teh search motors by Language
|
||||
|
||||
///////////////META TAGS CONFIGURATION HOME BASE////////////////////////////////
|
||||
//$a->config['metatag']['hreflang'] = '<link rel="alternate" href="https://blablanet.com/" hreflang="en" />';
|
||||
$a->config['metatag']['description'] = '<meta name="description" content="My Social NETWORK NAME Some description here." />
|
||||
';
|
||||
$a->config['metatag']['robots'] = '<meta name="robots" content="index" />';
|
||||
$a->config['metatag']['keywords'] = '<meta name="keywords" content="social, network, networking, service, friends, family, vpn, blogs, photos, videos, files, directory, encryption" />';
|
||||
//////Registration Description
|
||||
$a->config['metatag']['descriptionR'] = '<meta name="description" content="Register in My Social NETWORK NAME Some description here.." />';
|
||||
//////Login Description
|
||||
$a->config['metatag']['descriptionL'] = '<meta name="description" content="Login in My Social NETWORK NAME Some description here.." />';
|
||||
/////Directory Description
|
||||
$a->config['metatag']['descriptionD'] = '<meta name="description" content="Here My Social NETWORK NAME Some description here.." />';
|
||||
////Directory PUBLIC
|
||||
$a->config['metatag']['descriptionP'] = '<meta name=" The latest Public Sites." />';
|
||||
///Directory APPS
|
||||
$a->config['metatag']['descriptionA'] = '<meta name="description" content=" Apps, utils and extras for enjoy." />';
|
||||
////Latest News Yu can use that for any of your Aplications
|
||||
$a->config['metatag']['descriptionN'] = '<meta name=" My Social NETWORK NAME Some description here.." />';
|
||||
|
144
sources/addons/metatag/metatag.php
Normal file
144
sources/addons/metatag/metatag.php
Normal file
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Name: SEO MetaTags by Blablanet
|
||||
* Description: Inserts metatag in every page.
|
||||
* Version: 1.2
|
||||
* Author: Jacob Maldonado <https://blablanet.com>
|
||||
*
|
||||
*/
|
||||
/* Seo Meta Tags Plugin for Hubzilla
|
||||
*
|
||||
* Author: Jacob Maldonado
|
||||
*
|
||||
*
|
||||
*
|
||||
* Configuration:
|
||||
* Use hreflang only if you like to be target only from users with a specific language
|
||||
* The Search Engines will use hreflang language target for show in the search please Setup
|
||||
* Your own SEO the words include here are only a Example
|
||||
* Pleaase read Install for the lines in your .htconfig.php file
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
function metatag_install() {
|
||||
register_hook('page_content_top', 'addon/metatag/metatag.php', 'metatag_fetch');
|
||||
}
|
||||
|
||||
|
||||
function metatag_uninstall() {
|
||||
unregister_hook('page_content_top', 'addon/metatag/metatag.php', 'metatag_fetch');
|
||||
}
|
||||
|
||||
|
||||
function metatag_fetch($a) {
|
||||
$robots = get_config('metatag','robots');
|
||||
$hreflang = get_config('metatag','hreflang');
|
||||
$description = get_config('metatag','description');
|
||||
$keywords = get_config('metatag','keywords');
|
||||
|
||||
$descriptionR = get_config('metatag','descriptionR');
|
||||
$descriptionL = get_config('metatag','descriptionL');
|
||||
$descriptionP = get_config('metatag','descriptionP');
|
||||
$descriptionA = get_config('metatag','descriptionA');
|
||||
$descriptionD = get_config('metatag','descriptionD');
|
||||
$descriptionN = get_config('metatag','descriptionN');
|
||||
|
||||
$url = $_SERVER['REQUEST_URI'];
|
||||
switch($url){
|
||||
case "/";
|
||||
$a->page['htmlhead'] .= "$hreflang" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$robots" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$description" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$keywords" . "\r\n";
|
||||
break;
|
||||
|
||||
case "/&JS=1";
|
||||
$a->page['htmlhead'] .= "$hreflang" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$robots" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$description" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$keywords" . "\r\n";
|
||||
break;
|
||||
|
||||
case "/register";
|
||||
$a->page['htmlhead'] .= "$hreflang" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$robots" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$descriptionR" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$keywords" . "\r\n";
|
||||
break;
|
||||
|
||||
case "/register&JS=1";
|
||||
$a->page['htmlhead'] .= "$hreflang" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$robots" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$descriptionR" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$keywords" . "\r\n";
|
||||
break;
|
||||
|
||||
case "/login&JS=1";
|
||||
$a->page['htmlhead'] .= "$hreflang" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$robots" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$descriptionL" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$keywords" . "\r\n";
|
||||
break;
|
||||
|
||||
case "/login";
|
||||
$a->page['htmlhead'] .= "$hreflang" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$robots" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$descriptionL" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$keywords" . "\r\n";
|
||||
break;
|
||||
|
||||
case "/pubsites";
|
||||
$a->page['htmlhead'] .= "$hreflang" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$robots" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$descriptionP" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$keywords" . "\r\n";
|
||||
break;
|
||||
|
||||
case "/pubsub&JS=1";
|
||||
$a->page['htmlhead'] .= "$hreflang" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$robots" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$descriptionP" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$keywords" . "\r\n";
|
||||
break;
|
||||
|
||||
|
||||
case "/apps";
|
||||
$a->page['htmlhead'] .= "$hreflang" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$robots" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$descriptionA" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$keywords" . "\r\n";
|
||||
break;
|
||||
|
||||
case "/apps&JS=1";
|
||||
$a->page['htmlhead'] .= "$hreflang" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$robots" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$descriptionA" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$keywords" . "\r\n";
|
||||
break;
|
||||
|
||||
case "/directory";
|
||||
$a->page['htmlhead'] .= "$hreflang" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$robots" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$descriptionD" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$keywords" . "\r\n";
|
||||
break;
|
||||
|
||||
case "/directory&JS=1";
|
||||
$a->page['htmlhead'] .= "$hreflang" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$robots" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$descriptionD" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$keywords" . "\r\n";
|
||||
break;
|
||||
|
||||
case "/news";
|
||||
$a->page['htmlhead'] .= "$hreflang" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$robots" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$descriptionN" . "\r\n";
|
||||
$a->page['htmlhead'] .= "$keywords" . "\r\n";
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
98
sources/addons/msgfooter/msgfooter.php
Executable file
98
sources/addons/msgfooter/msgfooter.php
Executable file
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
/**
|
||||
* Name: Msg Footer
|
||||
* Description: Provide legal or other text at the bottom of posts
|
||||
* Version: 1.0
|
||||
* Author: Mike Macgirvin
|
||||
* Maintainer: none
|
||||
*/
|
||||
|
||||
|
||||
function msgfooter_load() {
|
||||
|
||||
/**
|
||||
*
|
||||
* Our demo plugin will attach in three places.
|
||||
* The first is just prior to storing a local post.
|
||||
*
|
||||
*/
|
||||
|
||||
register_hook('post_local', 'addon/msgfooter/msgfooter.php', 'msgfooter_post_hook');
|
||||
logger("loaded msgfooter");
|
||||
}
|
||||
|
||||
|
||||
function msgfooter_unload() {
|
||||
|
||||
/**
|
||||
*
|
||||
* unload unregisters any hooks created with register_hook
|
||||
* during load. It may also delete configuration settings
|
||||
* and any other cleanup.
|
||||
*
|
||||
*/
|
||||
|
||||
unregister_hook('post_local', 'addon/msgfooter/msgfooter.php', 'msgfooter_post_hook');
|
||||
|
||||
logger("removed msgfooter");
|
||||
}
|
||||
|
||||
|
||||
function msgfooter_plugin_admin(&$a,&$o) {
|
||||
|
||||
$t = get_markup_template("admin.tpl", "addon/msgfooter/");
|
||||
|
||||
$o = replace_macros($t, array(
|
||||
'$submit' => t('Save Settings'),
|
||||
'$msgfooter_text' => array('msgfooter_text', t('text to include in all outgoing posts from this site'), get_config('msgfooter', 'msgfooter_text'), '')
|
||||
));
|
||||
}
|
||||
|
||||
function msgfooter_plugin_admin_post(&$a){
|
||||
$msgfooter_text = ((x($_POST,'msgfooter_text')) ? trim($_POST['msgfooter_text']) : '');
|
||||
set_config('msgfooter','msgfooter_text',$msgfooter_text);
|
||||
info( t('Settings updated.'). EOL );
|
||||
}
|
||||
|
||||
|
||||
function msgfooter_post_hook($a, &$item) {
|
||||
|
||||
/**
|
||||
*
|
||||
* An item was posted on the local system.
|
||||
* We are going to look for specific items:
|
||||
* - A status post by a profile owner
|
||||
* - The profile owner must have allowed our plugin
|
||||
*
|
||||
*/
|
||||
|
||||
logger('msgfooter invoked');
|
||||
|
||||
if(! local_channel()) /* non-zero if this is a logged in user of this system */
|
||||
return;
|
||||
|
||||
if(local_channel() != $item['uid']) /* Does this person own the post? */
|
||||
return;
|
||||
|
||||
if($item['item_type'])
|
||||
return;
|
||||
|
||||
if($item['parent']) /* If the item has a parent, this is a comment or something else, not a status post. */
|
||||
return;
|
||||
|
||||
/* Retrieve our config setting */
|
||||
|
||||
$footer = get_config('msgfooter', 'msgfooter_text');
|
||||
|
||||
if(! $footer)
|
||||
return;
|
||||
|
||||
|
||||
$item['body'] .= '[footer]' . $footer . '[/footer]';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
2
sources/addons/msgfooter/view/tpl/admin.tpl
Normal file
2
sources/addons/msgfooter/view/tpl/admin.tpl
Normal file
|
@ -0,0 +1,2 @@
|
|||
{{include file="field_textarea.tpl" field=$msgfooter_text}}
|
||||
<div class="submit"><input type="submit" name="page_site" value="{{$submit}}" /></div>
|
26
sources/addons/noembed/noembed.php
Normal file
26
sources/addons/noembed/noembed.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Name: Noembed
|
||||
* Description: Use noembed.com as an addition to Hubzilla's native oembed functionality
|
||||
* Version: 1.0
|
||||
* Author: Jeroen van Riet Paap <jeroenpraat@hubzilla.nl>, Mike Macgirvin <mike@zothub.com>
|
||||
* Maintainer: Jeroen van Riet Paap <jeroenpraat@hubzilla.nl>
|
||||
*
|
||||
*/
|
||||
|
||||
function noembed_load() {
|
||||
register_hook('oembed_probe','addon/noembed/noembed.php','noembed_oembed_probe');
|
||||
}
|
||||
|
||||
function noembed_unload() {
|
||||
unregister_hook('oembed_probe','addon/noembed/noembed.php','noembed_oembed_probe');
|
||||
}
|
||||
|
||||
function noembed_oembed_probe(&$a,&$b) {
|
||||
// try noembed service
|
||||
$ourl = 'https://noembed.com/embed?url=' . urlencode($b['url']);
|
||||
$result = z_fetch_url($ourl);
|
||||
if($result['success'])
|
||||
$b['embed'] = $result['body'];
|
||||
}
|
11
sources/addons/nsfw/lang/nl/strings.php
Normal file
11
sources/addons/nsfw/lang/nl/strings.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
$a->strings["Not Safe For Work Settings"] = "Not Safe For Work (inhoudsfilter)";
|
||||
$a->strings["General Purpose Content Filter"] = "Voor alles te gebruiken inhoudsfilter";
|
||||
$a->strings["This plugin looks in posts for the words/text you specify below, and collapses any content containing those keywords so it is not displayed at inappropriate times, such as sexual innuendo that may be improper in a work setting. It is polite and recommended to tag any content containing nudity with #NSFW. This filter can also match any other word/text you specify, and can thereby be used as a general purpose content filter."] = "Deze plug-in controleert berichten op woorden die je hieronder kunt opgeven en klapt berichten in die deze woorden bevatten, zodat die berichten niet worden weergegeven op ongeschikte momenten. Denk hierbij aan berichten met erotische afbeeldingen, die waarschijnlijk niet geschikt zijn binnen (bijvoorbeeld) een werkomgeving. Het is beleefd en het wordt aangeraden om zulke berichten met #NSFW te taggen. Dit filter kan ook gebruikt worden met andere woorden en is dus voor alles inzetbaar.";
|
||||
$a->strings["Enable Content filter"] = "Inhoudsfilter inschakelen";
|
||||
$a->strings["Comma separated list of keywords to hide"] = "Door komma's gescheiden lijst met woorden die gefilterd moeten worden.";
|
||||
$a->strings["Submit"] = "Opslaan";
|
||||
$a->strings["Use /expression/ to provide regular expressions"] = "Gebruik /expressie/ voor reguliere expressies";
|
||||
$a->strings["NSFW Settings saved."] = "NSFW-instellingen opgeslagen.";
|
||||
$a->strings["%s - Click to open/close"] = "%s - Klik om te openen of te sluiten";
|
8
sources/addons/openstreetmap/lang/nl/strings.php
Normal file
8
sources/addons/openstreetmap/lang/nl/strings.php
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
$a->strings["Submit"] = "Opslaan";
|
||||
$a->strings["Tile Server URL"] = "URL tile-server";
|
||||
$a->strings["A list of <a href=\"http://wiki.openstreetmap.org/wiki/TMS\" target=\"_blank\">public tile servers</a>"] = "Een lijst met <a href=\"http://wiki.openstreetmap.org/wiki/TMS\" target=\"_blank\">openbare tile-servers</a>";
|
||||
$a->strings["Default zoom"] = "Standaard zoomniveau";
|
||||
$a->strings["The default zoom level. (1:world, 18:highest)"] = "Het standaard zoomniveau. Van 1 (wereld) t/m 18 (maximaal).";
|
||||
$a->strings["Settings updated."] = "Instellingen bijgewerkt.";
|
8
sources/addons/pageheader/README
Executable file
8
sources/addons/pageheader/README
Executable file
|
@ -0,0 +1,8 @@
|
|||
Page Header
|
||||
|
||||
For server admins only.
|
||||
Displays a text message for system announcements'
|
||||
The message is entered in the admin account at settings, Plugin settings.
|
||||
|
||||
If you want to use HTML in the pageheader, create a file called pageheader.html
|
||||
in the document root of your friendica instance and add the html there.
|
30
sources/addons/pageheader/lang/C/messages.po
Normal file
30
sources/addons/pageheader/lang/C/messages.po
Normal file
|
@ -0,0 +1,30 @@
|
|||
# ADDON pageheader
|
||||
# Copyright (C)
|
||||
# This file is distributed under the same license as the Friendica pageheader addon package.
|
||||
#
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-02-27 05:01-0500\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: pageheader.php:50
|
||||
msgid "\"pageheader\" Settings"
|
||||
msgstr ""
|
||||
|
||||
#: pageheader.php:55
|
||||
msgid "Submit"
|
||||
msgstr ""
|
||||
|
||||
#: pageheader.php:68
|
||||
msgid "pageheader Settings saved."
|
||||
msgstr ""
|
5
sources/addons/pageheader/lang/ca/strings.php
Normal file
5
sources/addons/pageheader/lang/ca/strings.php
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
$a->strings["\"pageheader\" Settings"] = "Configuració de la capçalera de pàgina.";
|
||||
$a->strings["Submit"] = "Enviar";
|
||||
$a->strings["pageheader Settings saved."] = "guardada la configuració de la capçalera de pàgina.";
|
32
sources/addons/pageheader/lang/cs/messages.po
Normal file
32
sources/addons/pageheader/lang/cs/messages.po
Normal file
|
@ -0,0 +1,32 @@
|
|||
# ADDON pageheader
|
||||
# Copyright (C)
|
||||
# This file is distributed under the same license as the Friendica pageheader addon package.
|
||||
#
|
||||
#
|
||||
# Translators:
|
||||
# Michal Šupler <msupler@gmail.com>, 2014-2015
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: friendica\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-02-27 05:01-0500\n"
|
||||
"PO-Revision-Date: 2015-02-11 19:38+0000\n"
|
||||
"Last-Translator: Michal Šupler <msupler@gmail.com>\n"
|
||||
"Language-Team: Czech (http://www.transifex.com/projects/p/friendica/language/cs/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: cs\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
||||
|
||||
#: pageheader.php:50
|
||||
msgid "\"pageheader\" Settings"
|
||||
msgstr "Nastavení záhlaví stránky"
|
||||
|
||||
#: pageheader.php:55
|
||||
msgid "Submit"
|
||||
msgstr "Odeslat"
|
||||
|
||||
#: pageheader.php:68
|
||||
msgid "pageheader Settings saved."
|
||||
msgstr "Nastavení záhlaví stránky uloženo."
|
10
sources/addons/pageheader/lang/cs/strings.php
Normal file
10
sources/addons/pageheader/lang/cs/strings.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
if(! function_exists("string_plural_select_cs")) {
|
||||
function string_plural_select_cs($n){
|
||||
return ($n==1) ? 0 : ($n>=2 && $n<=4) ? 1 : 2;;
|
||||
}}
|
||||
;
|
||||
$a->strings["\"pageheader\" Settings"] = "Nastavení záhlaví stránky";
|
||||
$a->strings["Submit"] = "Odeslat";
|
||||
$a->strings["pageheader Settings saved."] = "Nastavení záhlaví stránky uloženo.";
|
33
sources/addons/pageheader/lang/de/messages.po
Normal file
33
sources/addons/pageheader/lang/de/messages.po
Normal file
|
@ -0,0 +1,33 @@
|
|||
# ADDON pageheader
|
||||
# Copyright (C)
|
||||
# This file is distributed under the same license as the Friendica pageheader addon package.
|
||||
#
|
||||
#
|
||||
# Translators:
|
||||
# Abrax <webmaster@a-zwenkau.de>, 2014
|
||||
# bavatar <tobias.diekershoff@gmx.net>, 2014
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: friendica\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-02-27 05:01-0500\n"
|
||||
"PO-Revision-Date: 2014-10-15 12:32+0000\n"
|
||||
"Last-Translator: Abrax <webmaster@a-zwenkau.de>\n"
|
||||
"Language-Team: German (http://www.transifex.com/projects/p/friendica/language/de/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: de\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: pageheader.php:50
|
||||
msgid "\"pageheader\" Settings"
|
||||
msgstr "\"pageheader\"-Einstellungen"
|
||||
|
||||
#: pageheader.php:55
|
||||
msgid "Submit"
|
||||
msgstr "Senden"
|
||||
|
||||
#: pageheader.php:68
|
||||
msgid "pageheader Settings saved."
|
||||
msgstr "pageheader-Einstellungen gespeichert."
|
10
sources/addons/pageheader/lang/de/strings.php
Normal file
10
sources/addons/pageheader/lang/de/strings.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
if(! function_exists("string_plural_select_de")) {
|
||||
function string_plural_select_de($n){
|
||||
return ($n != 1);;
|
||||
}}
|
||||
;
|
||||
$a->strings["\"pageheader\" Settings"] = "\"pageheader\"-Einstellungen";
|
||||
$a->strings["Submit"] = "Senden";
|
||||
$a->strings["pageheader Settings saved."] = "pageheader-Einstellungen gespeichert.";
|
5
sources/addons/pageheader/lang/eo/strings.php
Normal file
5
sources/addons/pageheader/lang/eo/strings.php
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
$a->strings["\"pageheader\" Settings"] = "\"pageheader\" Agordoj";
|
||||
$a->strings["Submit"] = "Sendi";
|
||||
$a->strings["pageheader Settings saved."] = "Konservis Agordojn de pageheader.";
|
5
sources/addons/pageheader/lang/es/strings.php
Normal file
5
sources/addons/pageheader/lang/es/strings.php
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
$a->strings["\"pageheader\" Settings"] = "Configuración de cabecera";
|
||||
$a->strings["Submit"] = "Envíar";
|
||||
$a->strings["pageheader Settings saved."] = "Configuración de cabecera de página guardada.";
|
5
sources/addons/pageheader/lang/fr/strings.php
Normal file
5
sources/addons/pageheader/lang/fr/strings.php
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
$a->strings["\"pageheader\" Settings"] = "Réglages de pageheader";
|
||||
$a->strings["Submit"] = "Envoyer";
|
||||
$a->strings["pageheader Settings saved."] = "Réglages pageheader sauvés.";
|
5
sources/addons/pageheader/lang/is/strings.php
Normal file
5
sources/addons/pageheader/lang/is/strings.php
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
$a->strings["\"pageheader\" Settings"] = "Stillingar \"pageheader\"";
|
||||
$a->strings["Submit"] = "Senda inn";
|
||||
$a->strings["pageheader Settings saved."] = "Stillingar pageheader vistaðar.";
|
32
sources/addons/pageheader/lang/it/messages.po
Normal file
32
sources/addons/pageheader/lang/it/messages.po
Normal file
|
@ -0,0 +1,32 @@
|
|||
# ADDON pageheader
|
||||
# Copyright (C)
|
||||
# This file is distributed under the same license as the Friendica pageheader addon package.
|
||||
#
|
||||
#
|
||||
# Translators:
|
||||
# fabrixxm <fabrix.xm@gmail.com>, 2014
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: friendica\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-02-27 05:01-0500\n"
|
||||
"PO-Revision-Date: 2014-10-15 09:00+0000\n"
|
||||
"Last-Translator: fabrixxm <fabrix.xm@gmail.com>\n"
|
||||
"Language-Team: Italian (http://www.transifex.com/projects/p/friendica/language/it/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: it\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: pageheader.php:50
|
||||
msgid "\"pageheader\" Settings"
|
||||
msgstr "Impostazioni \"Intestazione pagina\""
|
||||
|
||||
#: pageheader.php:55
|
||||
msgid "Submit"
|
||||
msgstr ""
|
||||
|
||||
#: pageheader.php:68
|
||||
msgid "pageheader Settings saved."
|
||||
msgstr "Impostazioni \"Intestazione pagina\" salvate."
|
10
sources/addons/pageheader/lang/it/strings.php
Normal file
10
sources/addons/pageheader/lang/it/strings.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
if(! function_exists("string_plural_select_it")) {
|
||||
function string_plural_select_it($n){
|
||||
return ($n != 1);;
|
||||
}}
|
||||
;
|
||||
$a->strings["\"pageheader\" Settings"] = "Impostazioni \"Intestazione pagina\"";
|
||||
$a->strings["Submit"] = "";
|
||||
$a->strings["pageheader Settings saved."] = "Impostazioni \"Intestazione pagina\" salvate.";
|
5
sources/addons/pageheader/lang/nb-no/strings.php
Normal file
5
sources/addons/pageheader/lang/nb-no/strings.php
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
$a->strings["\"pageheader\" Settings"] = "";
|
||||
$a->strings["Submit"] = "Lagre";
|
||||
$a->strings["pageheader Settings saved."] = "";
|
11
sources/addons/pageheader/lang/nl/strings.php
Normal file
11
sources/addons/pageheader/lang/nl/strings.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
if(! function_exists("string_plural_select_de")) {
|
||||
function string_plural_select_de($n){
|
||||
return ($n != 1);;
|
||||
}}
|
||||
;
|
||||
$a->strings["Pageheader Settings"] = "Pageheader-instellingen";
|
||||
$a->strings["Message to display on every page on this server"] = "Bericht om weer te geven op elke pagina van deze hub";
|
||||
$a->strings["Submit"] = "Opslaan";
|
||||
$a->strings["pageheader Settings saved."] = "Pageheader-instellingen opgeslagen.";
|
5
sources/addons/pageheader/lang/pl/strings.php
Normal file
5
sources/addons/pageheader/lang/pl/strings.php
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
$a->strings["\"pageheader\" Settings"] = "";
|
||||
$a->strings["Submit"] = "Potwierdź";
|
||||
$a->strings["pageheader Settings saved."] = "";
|
5
sources/addons/pageheader/lang/pt-br/strings.php
Normal file
5
sources/addons/pageheader/lang/pt-br/strings.php
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
$a->strings["\"pageheader\" Settings"] = "Configurações do \"pageheader\"";
|
||||
$a->strings["Submit"] = "Enviar";
|
||||
$a->strings["pageheader Settings saved."] = "Configurações do pageheader armazenadas.";
|
32
sources/addons/pageheader/lang/ro/messages.po
Normal file
32
sources/addons/pageheader/lang/ro/messages.po
Normal file
|
@ -0,0 +1,32 @@
|
|||
# ADDON pageheader
|
||||
# Copyright (C)
|
||||
# This file is distributed under the same license as the Friendica pageheader addon package.
|
||||
#
|
||||
#
|
||||
# Translators:
|
||||
# Doru DEACONU <dumitrudeaconu@yahoo.com>, 2014
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: friendica\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-02-27 05:01-0500\n"
|
||||
"PO-Revision-Date: 2014-11-27 14:16+0000\n"
|
||||
"Last-Translator: Doru DEACONU <dumitrudeaconu@yahoo.com>\n"
|
||||
"Language-Team: Romanian (Romania) (http://www.transifex.com/projects/p/friendica/language/ro_RO/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ro_RO\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));\n"
|
||||
|
||||
#: pageheader.php:50
|
||||
msgid "\"pageheader\" Settings"
|
||||
msgstr "Configurări \"Pageheader\""
|
||||
|
||||
#: pageheader.php:55
|
||||
msgid "Submit"
|
||||
msgstr "Trimite"
|
||||
|
||||
#: pageheader.php:68
|
||||
msgid "pageheader Settings saved."
|
||||
msgstr "Configurările antetului de pagină au fost salvate."
|
10
sources/addons/pageheader/lang/ro/strings.php
Normal file
10
sources/addons/pageheader/lang/ro/strings.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
if(! function_exists("string_plural_select_ro")) {
|
||||
function string_plural_select_ro($n){
|
||||
return ($n==1?0:((($n%100>19)||(($n%100==0)&&($n!=0)))?2:1));;
|
||||
}}
|
||||
;
|
||||
$a->strings["\"pageheader\" Settings"] = "Configurări \"Pageheader\"";
|
||||
$a->strings["Submit"] = "Trimite";
|
||||
$a->strings["pageheader Settings saved."] = "Configurările antetului de pagină au fost salvate.";
|
5
sources/addons/pageheader/lang/ru/strings.php
Normal file
5
sources/addons/pageheader/lang/ru/strings.php
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
$a->strings["\"pageheader\" Settings"] = "";
|
||||
$a->strings["Submit"] = "Подтвердить";
|
||||
$a->strings["pageheader Settings saved."] = "";
|
3
sources/addons/pageheader/lang/sv/strings.php
Normal file
3
sources/addons/pageheader/lang/sv/strings.php
Normal file
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
|
||||
$a->strings["Submit"] = "Spara";
|
5
sources/addons/pageheader/lang/zh-cn/strings.php
Normal file
5
sources/addons/pageheader/lang/zh-cn/strings.php
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
$a->strings["\"pageheader\" Settings"] = "\"pageheader";
|
||||
$a->strings["Submit"] = "提交";
|
||||
$a->strings["pageheader Settings saved."] = "pageHeader配置保存了。";
|
9
sources/addons/pageheader/pageheader.css
Executable file
9
sources/addons/pageheader/pageheader.css
Executable file
|
@ -0,0 +1,9 @@
|
|||
.pageheader {
|
||||
padding: 21px 10px;
|
||||
color: #31708f;
|
||||
background-color: #d9edf7;
|
||||
border: 1px solid #bce8f1;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 4px;
|
||||
}
|
83
sources/addons/pageheader/pageheader.php
Executable file
83
sources/addons/pageheader/pageheader.php
Executable file
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* Name: Page Header
|
||||
* Description: Inserts a page header
|
||||
* Version: 1.1
|
||||
* Author: Keith Fernie <http://friendika.me4.it/profile/keith>
|
||||
* Hauke Altmann <https://snarl.de/profile/tugelblend>
|
||||
*
|
||||
*/
|
||||
|
||||
function pageheader_load() {
|
||||
register_hook('page_content_top', 'addon/pageheader/pageheader.php', 'pageheader_fetch');
|
||||
register_hook('feature_settings', 'addon/pageheader/pageheader.php', 'pageheader_addon_settings');
|
||||
register_hook('feature_settings_post', 'addon/pageheader/pageheader.php', 'pageheader_addon_settings_post');
|
||||
|
||||
}
|
||||
|
||||
|
||||
function pageheader_unload() {
|
||||
unregister_hook('page_content_top', 'addon/pageheader/pageheader.php', 'pageheader_fetch');
|
||||
unregister_hook('feature_settings', 'addon/pageheader/pageheader.php', 'pageheader_addon_settings');
|
||||
unregister_hook('feature_settings_post', 'addon/pageheader/pageheader.php', 'pageheader_addon_settings_post');
|
||||
|
||||
// hook moved, uninstall the old one if still there.
|
||||
unregister_hook('page_header', 'addon/pageheader/pageheader.php', 'pageheader_fetch');
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function pageheader_addon_settings(&$a,&$s) {
|
||||
|
||||
|
||||
if(! is_site_admin())
|
||||
return;
|
||||
|
||||
$words = get_config('pageheader','text');
|
||||
if(! $words)
|
||||
$words = '';
|
||||
|
||||
$sc .= '<div class="settings-block">';
|
||||
$sc .= '<div id="pageheader-wrapper">';
|
||||
$sc .= '<label id="pageheader-label" for="pageheader-words">' . t('Message to display on every page on this server') . ' </label>';
|
||||
$sc .= '<textarea class="form-control form-group" id="pageheader-words" type="text" name="pageheader-words">' . $words . '</textarea>';
|
||||
$sc .= '</div><div class="clear"></div>';
|
||||
|
||||
$s .= replace_macros(get_markup_template('generic_addon_settings.tpl'), array(
|
||||
'$addon' => array('pageheader', t('Pageheader Settings'), '', t('Submit')),
|
||||
'$content' => $sc
|
||||
));
|
||||
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
function pageheader_addon_settings_post(&$a,&$b) {
|
||||
|
||||
if(! is_site_admin())
|
||||
return;
|
||||
|
||||
if($_POST['pageheader-submit']) {
|
||||
set_config('pageheader','text',trim(strip_tags($_POST['pageheader-words'])));
|
||||
info( t('pageheader Settings saved.') . EOL);
|
||||
}
|
||||
}
|
||||
|
||||
function pageheader_fetch($a,&$b) {
|
||||
|
||||
if(file_exists('pageheader.html')){
|
||||
$s = file_get_contents('pageheader.html');
|
||||
} else {
|
||||
$s = get_config('pageheader', 'text');
|
||||
$a->page['htmlhead'] .= '<link rel="stylesheet" type="text/css" href="' . $a->get_baseurl() . '/addon/pageheader/pageheader.css' . '" media="all" />' . "\r\n";
|
||||
}
|
||||
|
||||
if($s)
|
||||
$b .= '<div class="pageheader">' . $s . '</div>';
|
||||
}
|
113
sources/addons/pubsubhubbub/pubsub.php
Normal file
113
sources/addons/pubsubhubbub/pubsub.php
Normal file
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
|
||||
require_once('include/Contact.php');
|
||||
|
||||
function pubsub_init(&$a) {
|
||||
|
||||
$nick = ((argc() > 1) ? escape_tags(trim(argv(1))) : '');
|
||||
$contact_id = ((argc() > 2) ? intval(argv(2)) : 0 );
|
||||
|
||||
if($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
|
||||
$hub_mode = ((x($_GET,'hub_mode')) ? notags(trim($_GET['hub_mode'])) : '');
|
||||
$hub_topic = ((x($_GET,'hub_topic')) ? notags(trim($_GET['hub_topic'])) : '');
|
||||
$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);
|
||||
|
||||
$channel = channelx_by_nick($nick);
|
||||
if(! $channel)
|
||||
http_status_exit(404,'not found.');
|
||||
|
||||
$connections = abook_connections($channel['channel_id'], ' and abook_id = ' . $contact_id);
|
||||
if($connections)
|
||||
$xchan = $connections[0];
|
||||
else {
|
||||
logger('connection ' . $contact_id . ' not found.');
|
||||
http_status_exit(404,'not found.');
|
||||
}
|
||||
|
||||
if($hub_verify) {
|
||||
$verify = get_abconfig($channel['channel_hash'],$xchan['xchan_hash'],'pubsubhubbub','verify_token');
|
||||
if($verify != $hub_verify) {
|
||||
logger('hub verification failed.');
|
||||
http_status_exit(404,'not found.');
|
||||
}
|
||||
}
|
||||
|
||||
$feed_url = z_root() . '/feed/' . $channel['channel_address'];
|
||||
|
||||
if($hub_topic) {
|
||||
if(! link_compare($hub_topic,$feed_url)) {
|
||||
logger('hub topic ' . $hub_topic . ' != ' . $feed_url);
|
||||
// should abort but let's humour them.
|
||||
}
|
||||
}
|
||||
|
||||
$contact = $r[0];
|
||||
|
||||
// We must initiate an unsubscribe request with a verify_token.
|
||||
// Don't allow outsiders to unsubscribe us.
|
||||
|
||||
if($hub_mode === 'unsubscribe') {
|
||||
if(! strlen($hub_verify)) {
|
||||
logger('pubsub: bogus unsubscribe');
|
||||
http_status_exit(403,'permission denied.');
|
||||
}
|
||||
logger('pubsub: unsubscribe success');
|
||||
}
|
||||
|
||||
if($hub_mode) {
|
||||
set_abconfig($channel['channel_hash'],$xchan['xchan_hash'],'pubsubhubbub','subscribed',intval($subscribe));
|
||||
}
|
||||
|
||||
header($_SERVER["SERVER_PROTOCOL"] . ' 200 ' . 'OK');
|
||||
echo $hub_challenge;
|
||||
killme();
|
||||
}
|
||||
}
|
||||
|
||||
function pubsub_post(&$a) {
|
||||
|
||||
$xml = file_get_contents('php://input');
|
||||
|
||||
logger('pubsub: feed arrived from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $a->cmd );
|
||||
logger('pubsub: user-agent: ' . $_SERVER['HTTP_USER_AGENT'] );
|
||||
logger('pubsub: data: ' . $xml, LOGGER_DATA);
|
||||
|
||||
|
||||
$nick = ((argc() > 1) ? escape_tags(trim(argv(1))) : '');
|
||||
$contact_id = ((argc() > 2) ? intval(argv(2)) : 0 );
|
||||
|
||||
$channel = channelx_by_nick($nick);
|
||||
if(! $channel)
|
||||
http_status_exit(200,'OK');
|
||||
|
||||
$connections = abook_connections($channel['channel_id'], ' and abook_id = ' . $contact_id);
|
||||
if($connections)
|
||||
$xchan = $connections[0];
|
||||
else {
|
||||
logger('connection ' . $contact_id . ' not found.');
|
||||
http_status_exit(200,'OK');
|
||||
}
|
||||
|
||||
if(! perm_is_allowed($channel['channel_id'],$xchan['xchan_hash'],'send_stream')) {
|
||||
logger('permission denied.');
|
||||
http_status_exit(200,'OK');
|
||||
}
|
||||
|
||||
consume_feed($xml,$channel,$xchan,1);
|
||||
consume_feed($xml,$channel,$xchan,2);
|
||||
|
||||
http_status_exit(200,'OK');
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
317
sources/addons/pubsubhubbub/pubsubhubbub.php
Normal file
317
sources/addons/pubsubhubbub/pubsubhubbub.php
Normal file
|
@ -0,0 +1,317 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Name: PubSubHubBub
|
||||
* Description: Add PuSH capability to channel feeds - based loosely on Friendica PuSH module by Mats Sjöberg
|
||||
* Version: 1.0
|
||||
* Author: Mike Macgirvin
|
||||
* Maintainer: none
|
||||
* MinVersion: 1.2.2
|
||||
*/
|
||||
|
||||
require_once('include/Contact.php');
|
||||
|
||||
|
||||
function pubsubhubbub_install() {
|
||||
$r = q("CREATE TABLE IF NOT EXISTS `push_subscriber` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`callback_url` varchar(255) NOT NULL DEFAULT '',
|
||||
`topic` varchar(255) NOT NULL DEFAULT '',
|
||||
`last_update` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`secret` varchar(255) NOT NULL DEFAULT '',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8");
|
||||
if($r) {
|
||||
q("alter table push_subscriber add index ( callback_url ) ");
|
||||
q("alter table push_subscriber add index ( topic ) ");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function pubsubhubbub_uninstall() {
|
||||
$r = q("drop table push_subscriber");
|
||||
}
|
||||
|
||||
|
||||
function pubsubhubbub_load() {
|
||||
register_hook('notifier_process','addon/pubsubhubbub/pubsubhubbub.php','push_notifier_process');
|
||||
register_hook('queue_deliver','addon/pubsubhubbub/pubsubhubbub.php','push_queue_deliver');
|
||||
register_hook('atom_feed','addon/pubsubhubbub/pubsubhubbub.php','push_atom_feed');
|
||||
register_hook('module_loaded', 'addon/pubsubhubbub/pubsubhubbub.php','push_module_loaded');
|
||||
|
||||
}
|
||||
|
||||
function pubsubhubbub_unload() {
|
||||
unregister_hook('notifier_process','addon/pubsubhubbub/pubsubhubbub.php','push_notifier_process');
|
||||
unregister_hook('queue_deliver','addon/pubsubhubbub/pubsubhubbub.php','push_queue_deliver');
|
||||
unregister_hook('atom_feed','addon/pubsubhubbub/pubsubhubbub.php','push_atom_feed');
|
||||
unregister_hook('module_loaded', 'addon/pubsubhubbub/pubsubhubbub.php','push_module_loaded');
|
||||
}
|
||||
|
||||
|
||||
function push_atom_feed(&$a,&$b) {
|
||||
$b = str_replace('</generator>','</generator>' . "\r\n" . ' <link href="' . z_root() . '/pubsubhubbub' . '" rel="hub" />',$b);
|
||||
}
|
||||
|
||||
|
||||
function push_module_loaded(&$a,&$b) {
|
||||
if($b['module'] === 'pubsub') {
|
||||
require_once('addon/pubsubhubbub/pubsub.php');
|
||||
$b['installed'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function push_notifier_process(&$a,&$b) {
|
||||
|
||||
if(! $b['normal_mode'])
|
||||
return;
|
||||
|
||||
if($b['private'])
|
||||
return;
|
||||
|
||||
// find push_subscribers following this $owner
|
||||
|
||||
$channel = $b['channel'];
|
||||
|
||||
$r = q("select * from push_subscriber where topic = '%s'",
|
||||
dbesc(z_root() . '/feed/' . $channel['channel_address'])
|
||||
);
|
||||
if(! $r)
|
||||
return;
|
||||
|
||||
|
||||
foreach($r as $rr) {
|
||||
|
||||
$feed = get_feed_for($channel,'',array('begin' => $rr['last_update']));
|
||||
|
||||
$hmac_sig = hash_hmac("sha1", $feed, $rr['secret']);
|
||||
|
||||
$slap = array('sig' => $hmac_sig, 'topic' => $rr['topic'], 'body' => $feed);
|
||||
|
||||
// Check for public post and create atom wrapper and stick in queue
|
||||
|
||||
// also need queue driver for 'push' since we need to set some extra headers
|
||||
|
||||
$hash = random_string();
|
||||
queue_insert(array(
|
||||
'hash' => $hash,
|
||||
'account_id' => $channel['channel_account_id'],
|
||||
'channel_id' => $channel['channel_id'],
|
||||
'driver' => 'push',
|
||||
'posturl' => $rr['callback_url'],
|
||||
'notify' => '',
|
||||
'msg' => json_encode($slap)
|
||||
));
|
||||
$b['queued'][] = $hash;
|
||||
}
|
||||
}
|
||||
|
||||
function push_queue_deliver(&$a,&$b) {
|
||||
|
||||
$outq = $b['outq'];
|
||||
if($outq['outq_driver'] !== 'push')
|
||||
return;
|
||||
|
||||
$b['handled'] = true;
|
||||
|
||||
$m = json_decode($outq['outq_msg'],true);
|
||||
|
||||
if($m) {
|
||||
$headers = array("Content-type: application/atom+xml",
|
||||
sprintf("Link: <%s>;rel=hub,<%s>;rel=self",z_root() . '/pubsubhubbub',$m['topic']),
|
||||
"X-Hub-Signature: sha1=" . $m['sig']);
|
||||
|
||||
$counter = 0;
|
||||
$result = z_post_url($outq['outq_posturl'], $m['body'], $counter, array('headers' => $headers, 'novalidate' => true));
|
||||
if($result['success'] && $result['return_code'] < 300) {
|
||||
logger('push_deliver: queue post success to ' . $outq['outq_posturl'], LOGGER_DEBUG);
|
||||
if($b['base']) {
|
||||
q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ",
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($b['base'])
|
||||
);
|
||||
}
|
||||
q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s' limit 1",
|
||||
dbesc('accepted for delivery'),
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($outq['outq_hash'])
|
||||
);
|
||||
q("update push_subscriber set last_update = '%s' where callback_url = '%s' and topic = '%s'",
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($outq['outq_posturl']),
|
||||
dbesc($m['topic'])
|
||||
);
|
||||
|
||||
remove_queue_item($outq['outq_hash']);
|
||||
}
|
||||
else {
|
||||
logger('push_deliver: queue post returned ' . $result['return_code']
|
||||
. ' from ' . $outq['outq_posturl'],LOGGER_DEBUG);
|
||||
update_queue_item($outq['outq_posturl']);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function pubsubhubbub_module() {};
|
||||
|
||||
|
||||
function push_post_var($name) {
|
||||
return (x($_REQUEST, $name)) ? notags(trim($_REQUEST[$name])) : '';
|
||||
}
|
||||
|
||||
function pubsubhubbub_init(&$a) {
|
||||
// PuSH subscription must be considered "public" so just block it
|
||||
// if public access isn't enabled.
|
||||
if (get_config('system', 'block_public')) {
|
||||
http_status_exit(403);
|
||||
}
|
||||
|
||||
// Subscription request from subscriber
|
||||
// https://pubsubhubbub.googlecode.com/git/pubsubhubbub-core-0.4.html#anchor4
|
||||
// Example from GNU Social:
|
||||
// [hub_mode] => subscribe
|
||||
// [hub_callback] => http://status.local/main/push/callback/1
|
||||
// [hub_verify] => sync
|
||||
// [hub_verify_token] => af11...
|
||||
// [hub_secret] => af11...
|
||||
// [hub_topic] => http://friendica.local/dfrn_poll/sazius
|
||||
|
||||
if($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$hub_mode = push_post_var('hub_mode');
|
||||
$hub_callback = push_post_var('hub_callback');
|
||||
$hub_verify = push_post_var('hub_verify');
|
||||
$hub_verify_token = push_post_var('hub_verify_token');
|
||||
$hub_secret = push_post_var('hub_secret');
|
||||
$hub_topic = push_post_var('hub_topic');
|
||||
|
||||
// check for valid hub_mode
|
||||
if ($hub_mode === 'subscribe') {
|
||||
$subscribe = 1;
|
||||
} else if ($hub_mode === 'unsubscribe') {
|
||||
$subscribe = 0;
|
||||
} else {
|
||||
logger("pubsubhubbub: invalid hub_mode=$hub_mode, ignoring.");
|
||||
http_status_exit(404);
|
||||
}
|
||||
|
||||
logger("pubsubhubbub: $hub_mode request from " . $_SERVER['REMOTE_ADDR']);
|
||||
|
||||
// get the nick name from the topic, a bit hacky but needed
|
||||
$nick = substr(strrchr($hub_topic, "/"), 1);
|
||||
|
||||
if (!$nick) {
|
||||
logger('pubsubhubbub: bad hub_topic=$hub_topic, ignoring.');
|
||||
http_status_exit(404);
|
||||
}
|
||||
|
||||
// fetch user from database given the nickname
|
||||
$owner = channelx_by_nick($nick);
|
||||
|
||||
if(! $owner) {
|
||||
logger('pubsubhubbub: local account not found: ' . $nick);
|
||||
http_status_exit(404);
|
||||
}
|
||||
|
||||
if(! perm_is_allowed($owner['channel_id'],'','view_stream')) {
|
||||
logger('pubsubhubbub: local channel ' . $nick .
|
||||
'has chosen to hide wall, ignoring.');
|
||||
http_status_exit(403);
|
||||
}
|
||||
|
||||
// sanity check that topic URLs are the same
|
||||
if(! link_compare($hub_topic, z_root() . '/feed/' . $nick)) {
|
||||
logger('pubsubhubbub: not a valid hub topic ' . $hub_topic );
|
||||
http_status_exit(404);
|
||||
}
|
||||
|
||||
// do subscriber verification according to the PuSH protocol
|
||||
$hub_challenge = random_string(40);
|
||||
$params = 'hub.mode=' .
|
||||
($subscribe == 1 ? 'subscribe' : 'unsubscribe') .
|
||||
'&hub.topic=' . urlencode($hub_topic) .
|
||||
'&hub.challenge=' . $hub_challenge .
|
||||
'&hub.lease_seconds=604800' .
|
||||
'&hub.verify_token=' . $hub_verify_token;
|
||||
|
||||
// lease time is hard coded to one week (in seconds)
|
||||
// we don't actually enforce the lease time because GNU
|
||||
// Social/StatusNet doesn't honour it (yet)
|
||||
|
||||
$x = z_fetch_url($hub_callback . "?" . $params);
|
||||
if(! $x['success']) {
|
||||
logger("pubsubhubbub: subscriber verification at $hub_callback ".
|
||||
"returned $ret, ignoring.");
|
||||
http_status_exit(404);
|
||||
}
|
||||
|
||||
// check that the correct hub_challenge code was echoed back
|
||||
if (trim($x['body']) !== $hub_challenge) {
|
||||
logger("pubsubhubbub: subscriber did not echo back ".
|
||||
"hub.challenge, ignoring.");
|
||||
logger("\"$hub_challenge\" != \"".trim($x['body'])."\"");
|
||||
http_status_exit(404);
|
||||
}
|
||||
|
||||
// fetch the old subscription if it exists
|
||||
$orig = q("SELECT * FROM `push_subscriber` WHERE `callback_url` = '%s'",
|
||||
dbesc($hub_callback));
|
||||
|
||||
// delete old subscription if it exists
|
||||
q("DELETE FROM push_subscriber WHERE callback_url = '%s' and topic = '%s'",
|
||||
dbesc($hub_callback),
|
||||
dbesc($hub_topic)
|
||||
);
|
||||
|
||||
if($subscribe) {
|
||||
$last_update = datetime_convert('UTC','UTC','now','Y-m-d H:i:s');
|
||||
|
||||
// if we are just updating an old subscription, keep the
|
||||
// old values for last_update
|
||||
|
||||
if ($orig) {
|
||||
$last_update = $orig[0]['last_update'];
|
||||
}
|
||||
|
||||
// subscribe means adding the row to the table
|
||||
q("INSERT INTO push_subscriber ( callback_url, topic, last_update, secret) values ('%s', '%s', '%s', '%s') ",
|
||||
dbesc($hub_callback),
|
||||
dbesc($hub_topic),
|
||||
dbesc($last_update),
|
||||
dbesc($hub_secret)
|
||||
);
|
||||
logger("pubsubhubbub: successfully subscribed [$hub_callback].");
|
||||
}
|
||||
else {
|
||||
logger("pubsubhubbub: successfully unsubscribed [$hub_callback].");
|
||||
// we do nothing here, since the row was already deleted
|
||||
}
|
||||
http_status_exit(202);
|
||||
}
|
||||
|
||||
killme();
|
||||
}
|
||||
|
||||
|
||||
function pubsubhubbub_subscribe($url,$channel,$xchan,$hubmode = 'subscribe') {
|
||||
|
||||
$push_url = z_root() . '/pubsub/' . $channel['channel_address'] . '/' . $xchan['abook_id'];
|
||||
|
||||
$verify = get_abconfig($channel['channel_hash'],$xchan['xchan_hash'],'pubsubhubbub','verify_token');
|
||||
if(! $verify)
|
||||
$verify = set_abconfig($channel['channel_hash'],$xchan['xchan_hash'],'pubsubhubbub','verify_token',random_string(16));
|
||||
|
||||
$params= 'hub.mode=' . $hubmode . '&hub.callback=' . urlencode($push_url) . '&hub.topic=' . urlencode($contact['poll']) . '&hub.verify=async&hub.verify_token=' . $verify;
|
||||
|
||||
logger('subscribe_to_hub: ' . $hubmode . ' ' . $xchan['xchan_name'] . ' to hub ' . $url . ' endpoint: ' . $push_url . ' with verifier ' . $verify);
|
||||
|
||||
|
||||
$x = z_post_url($url,$params);
|
||||
|
||||
logger('subscribe_to_hub: returns: ' . $x['return_code'], LOGGER_DEBUG);
|
||||
|
||||
return;
|
||||
|
||||
}
|
|
@ -160,9 +160,9 @@ function show_button($a, &$b) {
|
|||
*
|
||||
*/
|
||||
if (! $nobutton and ! $deactivated) {
|
||||
$b = "<div id=\"profile-smiley-wrapper\" >\n";
|
||||
//$b .= "\t<img src=\"" . $a->get_baseurl() . "/addon/smileybutton/icon.gif\" onclick=\"toggle_smileybutton()\" alt=\"smiley\">\n";
|
||||
$b .= "\t<i id=\"profile-smiley-button\" class=\"icon-smile jot-icons\" onclick=\"toggle_smileybutton()\"></i>\n";
|
||||
$b .= "<div id=\"profile-smiley-wrapper\" >\n";
|
||||
//$b .= "\t<img src=\"" . $a->get_baseurl() . "/addon/smileybutton/icon.gif\" onclick=\"toggle_smileybutton(); return false;\" alt=\"smiley\">\n";
|
||||
$b .= "\t<button class=\"btn btn-default btn-sm\" onclick=\"toggle_smileybutton(); return false;\"><i id=\"profile-smiley-button\" class=\"icon-smile jot-icons\" ></i></button>\n";
|
||||
$b .= "\t</div>\n";
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,8 @@ function statistics_json_init() {
|
|||
|
||||
$statistics = array(
|
||||
"name" => get_config('system','sitename'),
|
||||
"network" => get_platform_name(),
|
||||
"version" => get_project_version(),
|
||||
"network" => Zotlabs\Project\System::get_platform_name(),
|
||||
"version" => Zotlabs\Project\System::get_project_version(),
|
||||
"registrations_open" => (get_config('system','register_policy') != 0),
|
||||
"total_users" => get_config('statistics_json','total_users'),
|
||||
"active_users_halfyear" => get_config('statistics_json','active_users_halfyear'),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# ADDON statusnet
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C)
|
||||
# This file is distributed under the same license as the Friendica statusnet addon package.
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
#
|
||||
#
|
||||
#, fuzzy
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-02-27 05:01-0500\n"
|
||||
"POT-Creation-Date: 2016-02-04 23:14+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -17,161 +17,164 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: statusnet.php:138
|
||||
msgid "Post to StatusNet"
|
||||
#: statusnet.php:143
|
||||
msgid "Post to GNU social"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:181
|
||||
#: statusnet.php:195
|
||||
msgid ""
|
||||
"Please contact your site administrator.<br />The provided API URL is not "
|
||||
"valid."
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:210
|
||||
msgid "We could not contact the StatusNet API with the Path you entered."
|
||||
#: statusnet.php:232
|
||||
msgid "We could not contact the GNU social API with the Path you entered."
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:240
|
||||
msgid "StatusNet settings updated."
|
||||
#: statusnet.php:266
|
||||
msgid "GNU social settings updated."
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:271
|
||||
msgid "StatusNet Posting Settings"
|
||||
#: statusnet.php:310
|
||||
msgid "Globally Available GNU social OAuthKeys"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:285
|
||||
msgid "Globally Available StatusNet OAuthKeys"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:286
|
||||
#: statusnet.php:312
|
||||
msgid ""
|
||||
"There are preconfigured OAuth key pairs for some StatusNet servers "
|
||||
"available. If you are useing one of them, please use these credentials. If "
|
||||
"not feel free to connect to any other StatusNet instance (see below)."
|
||||
"There are preconfigured OAuth key pairs for some GNU social servers "
|
||||
"available. If you are using one of them, please use these credentials.<br /"
|
||||
">If not feel free to connect to any other GNU social instance (see below)."
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:292 statusnet.php:309 statusnet.php:335 statusnet.php:342
|
||||
#: statusnet.php:379 statusnet.php:761
|
||||
#: statusnet.php:322 statusnet.php:380 statusnet.php:432 statusnet.php:897
|
||||
msgid "Submit"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:294
|
||||
#: statusnet.php:327
|
||||
msgid "Provide your own OAuth Credentials"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:295
|
||||
#: statusnet.php:329
|
||||
msgid ""
|
||||
"No consumer key pair for StatusNet found. Register your Friendica Account as "
|
||||
"an desktop client on your StatusNet account, copy the consumer key pair here "
|
||||
"and enter the API base root.<br />Before you register your own OAuth key "
|
||||
"pair ask the administrator if there is already a key pair for this Friendica "
|
||||
"installation at your favorited StatusNet installation."
|
||||
"No consumer key pair for GNU social found. Register your Hubzilla Account as "
|
||||
"an desktop client on your GNU social account, copy the consumer key pair "
|
||||
"here and enter the API base root.<br />Before you register your own OAuth "
|
||||
"key pair ask the administrator if there is already a key pair for this "
|
||||
"Hubzilla installation at your favourite GNU social installation."
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:297
|
||||
#: statusnet.php:333
|
||||
msgid "OAuth Consumer Key"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:300
|
||||
#: statusnet.php:337
|
||||
msgid "OAuth Consumer Secret"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:303
|
||||
msgid "Base API Path (remember the trailing /)"
|
||||
#: statusnet.php:341
|
||||
msgid "Base API Path"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:306
|
||||
msgid "StatusNet application name"
|
||||
#: statusnet.php:341
|
||||
msgid "Remember the trailing /"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:327
|
||||
#: statusnet.php:345
|
||||
msgid "GNU social application name"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:368
|
||||
msgid ""
|
||||
"To connect to your StatusNet account click the button below to get a "
|
||||
"security code from StatusNet which you have to copy into the input box below "
|
||||
"and submit the form. Only your <strong>public</strong> posts will be posted "
|
||||
"to StatusNet."
|
||||
"To connect to your GNU social account click the button below to get a "
|
||||
"security code from GNU social which you have to copy into the input box "
|
||||
"below and submit the form. Only your <strong>public</strong> posts will be "
|
||||
"posted to GNU social."
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:328
|
||||
msgid "Log in with StatusNet"
|
||||
#: statusnet.php:370
|
||||
msgid "Log in with GNU social"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:330
|
||||
msgid "Copy the security code from StatusNet here"
|
||||
#: statusnet.php:373
|
||||
msgid "Copy the security code from GNU social here"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:336
|
||||
#: statusnet.php:383
|
||||
msgid "Cancel Connection Process"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:338
|
||||
msgid "Current StatusNet API is"
|
||||
#: statusnet.php:385
|
||||
msgid "Current GNU social API is"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:339
|
||||
msgid "Cancel StatusNet Connection"
|
||||
#: statusnet.php:389
|
||||
msgid "Cancel GNU social Connection"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:350
|
||||
#: statusnet.php:389 statusnet.php:411 statusnet.php:415 statusnet.php:424
|
||||
msgid "No"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:389 statusnet.php:411 statusnet.php:415 statusnet.php:424
|
||||
msgid "Yes"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:401
|
||||
msgid "Currently connected to: "
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:351
|
||||
msgid ""
|
||||
"If enabled all your <strong>public</strong> postings can be posted to the "
|
||||
"associated StatusNet account. You can choose to do so by default (here) or "
|
||||
"for every posting separately in the posting options when writing the entry."
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:353
|
||||
#: statusnet.php:406
|
||||
msgid ""
|
||||
"<strong>Note</strong>: Due your privacy settings (<em>Hide your profile "
|
||||
"details from unknown viewers?</em>) the link potentially included in public "
|
||||
"postings relayed to StatusNet will lead the visitor to a blank page "
|
||||
"postings relayed to GNU social will lead the visitor to a blank page "
|
||||
"informing the visitor that the access to your profile has been restricted."
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:356
|
||||
msgid "Allow posting to StatusNet"
|
||||
#: statusnet.php:411
|
||||
msgid "Allow posting to GNU social"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:359
|
||||
msgid "Send public postings to StatusNet by default"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:363
|
||||
#: statusnet.php:411
|
||||
msgid ""
|
||||
"Mirror all posts from statusnet that are no replies or repeated messages"
|
||||
"If enabled your public postings can be posted to the associated GNU-social "
|
||||
"account"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:367
|
||||
msgid "Shortening method that optimizes the post"
|
||||
#: statusnet.php:415
|
||||
msgid "Post to GNU social by default"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:371
|
||||
msgid "Send linked #-tags and @-names to StatusNet"
|
||||
#: statusnet.php:415
|
||||
msgid ""
|
||||
"If enabled your public postings will be posted to the associated GNU-social "
|
||||
"account by default"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:376
|
||||
#: statusnet.php:424
|
||||
msgid "Clear OAuth configuration"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:752
|
||||
#: statusnet.php:432
|
||||
msgid "GNU social Post Settings"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:888
|
||||
msgid "Site name"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:753
|
||||
#: statusnet.php:889
|
||||
msgid "API URL"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:754
|
||||
#: statusnet.php:890
|
||||
msgid "Consumer Secret"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:755
|
||||
#: statusnet.php:891
|
||||
msgid "Consumer Key"
|
||||
msgstr ""
|
||||
|
||||
#: statusnet.php:756
|
||||
#: statusnet.php:892
|
||||
msgid "Application name"
|
||||
msgstr ""
|
||||
|
|
36
sources/addons/statusnet/lang/nl/strings.php
Normal file
36
sources/addons/statusnet/lang/nl/strings.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
;
|
||||
$a->strings["Post to GNU social"] = "Doorplaatsen naar GNU social";
|
||||
$a->strings["Please contact your site administrator.<br />The provided API URL is not valid."] = "Neem contact op met jouw hubbeheerder.<br />De verstrekte API-URL is ongeldig.";
|
||||
$a->strings["We could not contact the GNU social API with the Path you entered."] = "Wij konden de GNU social-API niet bereiken door middel van het ingevulde pad.";
|
||||
$a->strings["GNU social settings updated."] = "GNU social-instellingen bijgewerkt.";
|
||||
$a->strings["Globally Available GNU social OAuthKeys"] = "Voor de hele hub te gebruiken GNU social OAuthkeys.";
|
||||
$a->strings["There are preconfigured OAuth key pairs for some GNU social servers available. If you are using one of them, please use these credentials.<br />If not feel free to connect to any other GNU social instance (see below)."] = "Er zijn op deze hub enkele voorgeconfigureerde OAuthkey-paren voor GNU social servers beschikbaar. Wanneer je een van deze servers gebruikt, gebruik dan deze voorgeconfigureerde gegevens.<br />Wanneer dit niet het geval is, maak dan gerust met een andere GNU social-server verbinding (zie hieronder).";
|
||||
$a->strings["Submit"] = "Opslaan";
|
||||
$a->strings["Provide your own OAuth Credentials"] = "Verstrek jouw eigen OAuth-gegevens";
|
||||
$a->strings["No consumer key pair for GNU social found. Register your Hubzilla Account as an desktop client on your GNU social account, copy the consumer key pair here and enter the API base root.<br />Before you register your own OAuth key pair ask the administrator if there is already a key pair for this Hubzilla installation at your favourite GNU social installation."] = "Geen consumerkey voor GNU social gevonden. Registreer jouw Hubzilla-account als een desktopclient in jouw GNU-social-account, kopieer en plak hier de consumerkey en de consumersecret, en vul de API-base-root in.<br />Voordat je jouw eigen OAuthkey-paar registreert, vraag dan eerst aan jouw hubbeheerder of er al een key-paar voor deze hub op jouw favoriete GNU social-server bestaat.";
|
||||
$a->strings["OAuth Consumer Key"] = "OAuth-consumerkey";
|
||||
$a->strings["OAuth Consumer Secret"] = "Oauth-consumersecret";
|
||||
$a->strings["Base API Path"] = "Base API-pad";
|
||||
$a->strings["Remember the trailing /"] = "Vergeet niet de afsluitende /";
|
||||
$a->strings["GNU social application name"] = "Naam GNU social-applicatie";
|
||||
$a->strings["To connect to your GNU social account click the button below to get a security code from GNU social which you have to copy into the input box below and submit the form. Only your <strong>public</strong> posts will be posted to GNU social."] = "Om jouw GNU social-account te koppelen klik je op de knop hieronder. Je krijgt dan een veiligheidscode van GNU social die je kan kopiëren en dan hieronder in het invulveld kan plakken. Vervolgens klik je op Opslaan. Alleen jouw <strong>openbare</strong> berichten kunnen worden doorgeplaatst naar GNU social.";
|
||||
$a->strings["Log in with GNU social"] = "Op GNU social inloggen";
|
||||
$a->strings["Copy the security code from GNU social here"] = "Plak de veiligheidscode van GNU social hier";
|
||||
$a->strings["Cancel Connection Process"] = "Annuleer het koppelingsproces";
|
||||
$a->strings["Current GNU social API is"] = "De huidige GNU social-API is";
|
||||
$a->strings["Cancel GNU social Connection"] = "Annuleer de GNU social-koppeling";
|
||||
$a->strings["No"] = "Nee";
|
||||
$a->strings["Yes"] = "Ja";
|
||||
$a->strings["Currently connected to: "] = "Momenteel gekoppeld aan: ";
|
||||
$a->strings["If enabled your public postings can be posted to the associated GNU-social account"] = "Wanneer dit is ingeschakeld kunnen jouw openbare berichten op het gekoppelde Twitter-account worden geplaatst";
|
||||
$a->strings["Post to GNU social by default"] = "Berichten standaard naar GNU social doorplaatsen";
|
||||
$a->strings["If enabled your public postings will be posted to the associated GNU-social account by default"] = "Wanneer dit is ingeschakeld worden al jouw openbare berichten standaard op het gekoppelde GNU social-account geplaatst";
|
||||
$a->strings["Clear OAuth configuration"] = "OAuth-configuratie wissen";
|
||||
$a->strings["GNU social Post Settings"] = "GNU social (berichten doorplaatsen)";
|
||||
$a->strings["Site name"] = "Naam server";
|
||||
$a->strings["API URL"] = "API-URL";
|
||||
$a->strings["Consumer Secret"] = "Consumersecret";
|
||||
$a->strings["Consumer Key"] = "Consumerkey";
|
||||
$a->strings["Application name"] = "Naam applicatie";
|
|
@ -552,6 +552,8 @@ function statusnet_shortenmsg($b, $max_char) {
|
|||
while (strpos($msg, " ") !== false)
|
||||
$msg = str_replace(" ", " ", $msg);
|
||||
|
||||
$msg = str_replace('#^http','http', $msg);
|
||||
|
||||
$origmsg = $msg;
|
||||
|
||||
// Removing URLs
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
if(! function_exists("string_plural_select_ca")) {
|
||||
function string_plural_select_de($n){
|
||||
function string_plural_select_ca($n){
|
||||
return ($n != 1);;
|
||||
}}
|
||||
;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
if(! function_exists("string_plural_select_es")) {
|
||||
function string_plural_select_nl($n){
|
||||
function string_plural_select_es($n){
|
||||
return ($n != 1);;
|
||||
}}
|
||||
;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
if(! function_exists("string_plural_select_fr")) {
|
||||
function string_plural_select_nl($n){
|
||||
function string_plural_select_fr($n){
|
||||
return ($n != 1);;
|
||||
}}
|
||||
;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
if(! function_exists("string_plural_select_it")) {
|
||||
function string_plural_select_nl($n){
|
||||
function string_plural_select_it($n){
|
||||
return ($n != 1);;
|
||||
}}
|
||||
;
|
||||
|
|
|
@ -6,7 +6,7 @@ function string_plural_select_nl($n){
|
|||
}}
|
||||
;
|
||||
$a->strings["Comma separated profile URLS to block"] = "Door komma's gescheiden profiel-URL's die geblokkeerd moeten worden";
|
||||
$a->strings["\"Superblock\" Settings"] = "\"Superblock\"-instellingen";
|
||||
$a->strings["\"Superblock\" Settings"] = "Superblock (kanalen volledig blokkeren)";
|
||||
$a->strings["Submit"] = "Opslaan";
|
||||
$a->strings["SUPERBLOCK Settings saved."] = "Superblock-instellingen opgeslagen.";
|
||||
$a->strings["Block Completely"] = "Volledig blokkeren";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
if(! function_exists("string_plural_select_pt-br")) {
|
||||
function string_plural_select_nl($n){
|
||||
if(! function_exists("string_plural_select_pt_br")) {
|
||||
function string_plural_select_pt_br($n){
|
||||
return ($n != 1);;
|
||||
}}
|
||||
;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
if(! function_exists("string_plural_select_ru")) {
|
||||
function string_plural_select_nl($n){
|
||||
function string_plural_select_ru($n){
|
||||
return ($n != 1);;
|
||||
}}
|
||||
;
|
||||
|
|
11
sources/addons/testdrive/lang/nl/strings.php
Normal file
11
sources/addons/testdrive/lang/nl/strings.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
if(! function_exists("string_plural_select_de")) {
|
||||
function string_plural_select_de($n){
|
||||
return ($n != 1);;
|
||||
}}
|
||||
;
|
||||
$a->strings["Administrator"] = "Beheerder";
|
||||
$a->strings["Your account on %s will expire in a few days."] = "Jouw account op %s verloopt in een paar dagen.";
|
||||
$a->strings["Your $Productname test account is about to expire."] = "Jouw $Productname-testaccount is bijna verlopen.";
|
||||
$a->strings["Hi %1\$s,\n\nYour test account on %2\$s will expire in less than five days. We hope you enjoyed this test drive and use this opportunity to find or install a permanent hub and migrate your account to it. A list of public hubs is available at https://zothub.com/pubsites - and for more information on setting up your own $Projectname hub please see the project website at https://github.com/redmatrix/$projectname."] = "Hallo %1\$s,\n\njouw testaccount op %2\$s verloopt in minder dan vijf dagen. Wij hopen dat je hebt genoten van deze testrit en van deze gelegenheid gebruikt maakt om een permanente hub te vinden, waar je dit account naar toe kunt verhuizen. Je vind op https://zothub.com/pubsites een lijst met openbare hubs - en voor meer informatie over hoe jezelf een $Projectname-hub kunt inrichten verwijzen we je naar https://github.com/redmatrix/$projectname.";
|
23
sources/addons/twitter/lang/nl/strings.php
Normal file
23
sources/addons/twitter/lang/nl/strings.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
$a->strings["Post to Twitter"] = "Doorplaatsen naar Twitter";
|
||||
$a->strings["Twitter settings updated."] = "Twitter-instellingen bijgewerkt.";
|
||||
$a->strings["Twitter Post Settings"] = "Twitter (berichten doorplaatsen)";
|
||||
$a->strings["No consumer key pair for Twitter found. Please contact your site administrator."] = "Geen consumerkeys voor Twitter gevonden. Neem contact op met jouw hubbeheerder.";
|
||||
$a->strings["At this Hubzilla instance the Twitter plugin was enabled but you have not yet connected your account to your Twitter account. To do so click the button below to get a PIN from Twitter which you have to copy into the input box below and submit the form. Only your <strong>public</strong> posts will be posted to Twitter."] = "De Twitter-plugin is op deze Hubzilla-hub ingeschakeld, maar je hebt nog niet jouw Hubzilla-kanaal met jouw Twitter-account gekoppeld. Om dit te doen klik je op de knop hieronder om een PIN-code van Twitter te krijgen. Deze dien je te kopiëren en in het invoegveld beneden te plakken. Vervolgens klik je op Opslaan. Alleen jouw <strong>openbare</strong> berichten kunnen op Twitter worden geplaatst.";
|
||||
$a->strings["Log in with Twitter"] = "Op Twitter inloggen";
|
||||
$a->strings["Copy the PIN from Twitter here"] = "Plak of type de PIN-code hier";
|
||||
$a->strings["Submit"] = "Opslaan";
|
||||
$a->strings["Currently connected to: "] = "Momenteel gekoppeld aan: ";
|
||||
$a->strings["Allow posting to Twitter"] = "Berichten op Twitter plaatsen";
|
||||
$a->strings["If enabled your public postings can be posted to the associated Twitter account"] = "Wanneer dit is ingeschakeld kunnen jouw <strong>openbare</strong> berichten op het gekoppelde Twitter-account worden geplaatst";
|
||||
$a->strings["No"] = "Nee";
|
||||
$a->strings["Yes"] = "Ja";
|
||||
$a->strings["Send public postings to Twitter by default"] = "Plaats berichten standaard op Twitter";
|
||||
$a->strings["If enabled your public postings will be posted to the associated Twitter account by default"] = "Wanneer dit is ingeschakeld worden al jouw <strong>openbare</strong> berichten standaard op het gekoppelde Twitter-account geplaatst";
|
||||
$a->strings["Clear OAuth configuration"] = "OAuth-configuratie wissen";
|
||||
$a->strings["Settings updated."] = "Instellingen bijgewerkt.";
|
||||
$a->strings["Submit Settings"] = "Instellingen opslaan";
|
||||
$a->strings["Consumer Key"] = "Consumerkey";
|
||||
$a->strings["Consumer Secret"] = "Consumersecret";
|
||||
$a->strings["Name of the Twitter Application"] = "Naam van Twitter-applicatie";
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue