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

This commit is contained in:
AndyHee 2017-12-07 11:28:50 +07:00
commit 6d3ced6389
113 changed files with 2936 additions and 2580 deletions

View file

@ -36,7 +36,6 @@ require_once 'include/text.php';
require_once 'include/datetime.php'; require_once 'include/datetime.php';
require_once 'include/pgettext.php'; require_once 'include/pgettext.php';
require_once 'include/nav.php'; require_once 'include/nav.php';
require_once 'include/features.php';
require_once 'include/identity.php'; require_once 'include/identity.php';
require_once 'update.php'; require_once 'update.php';
require_once 'include/dbstructure.php'; require_once 'include/dbstructure.php';
@ -45,7 +44,7 @@ define('FRIENDICA_PLATFORM', 'Friendica');
define('FRIENDICA_CODENAME', 'Asparagus'); define('FRIENDICA_CODENAME', 'Asparagus');
define('FRIENDICA_VERSION', '3.6-dev'); define('FRIENDICA_VERSION', '3.6-dev');
define('DFRN_PROTOCOL_VERSION', '2.23'); define('DFRN_PROTOCOL_VERSION', '2.23');
define('DB_UPDATE_VERSION', 1235); define('DB_UPDATE_VERSION', 1236);
/** /**
* @brief Constant with a HTML line break. * @brief Constant with a HTML line break.
@ -254,25 +253,24 @@ define('PROTOCOL_SPLITTED_CONV', 6);
* @{ * @{
*/ */
define('NETWORK_DFRN', 'dfrn'); // Friendica, Mistpark, other DFRN implementations define('NETWORK_DFRN', 'dfrn'); // Friendica, Mistpark, other DFRN implementations
define('NETWORK_ZOT', 'zot!'); // Zot! define('NETWORK_ZOT', 'zot!'); // Zot! - Currently unsupported
define('NETWORK_OSTATUS', 'stat'); // status.net, identi.ca, GNU-social, other OStatus implementations define('NETWORK_OSTATUS', 'stat'); // GNU-social, Pleroma, Mastodon, other OStatus implementations
define('NETWORK_FEED', 'feed'); // RSS/Atom feeds with no known "post/notify" protocol define('NETWORK_FEED', 'feed'); // RSS/Atom feeds with no known "post/notify" protocol
define('NETWORK_DIASPORA', 'dspr'); // Diaspora define('NETWORK_DIASPORA', 'dspr'); // Diaspora
define('NETWORK_MAIL', 'mail'); // IMAP/POP define('NETWORK_MAIL', 'mail'); // IMAP/POP
define('NETWORK_MAIL2', 'mai2'); // extended IMAP/POP
define('NETWORK_FACEBOOK', 'face'); // Facebook API define('NETWORK_FACEBOOK', 'face'); // Facebook API
define('NETWORK_LINKEDIN', 'lnkd'); // LinkedIn define('NETWORK_LINKEDIN', 'lnkd'); // LinkedIn
define('NETWORK_XMPP', 'xmpp'); // XMPP define('NETWORK_XMPP', 'xmpp'); // XMPP - Currently unsupported
define('NETWORK_MYSPACE', 'mysp'); // MySpace define('NETWORK_MYSPACE', 'mysp'); // MySpace - Currently unsupported
define('NETWORK_GPLUS', 'goog'); // Google+ define('NETWORK_GPLUS', 'goog'); // Google+
define('NETWORK_PUMPIO', 'pump'); // pump.io define('NETWORK_PUMPIO', 'pump'); // pump.io
define('NETWORK_TWITTER', 'twit'); // Twitter define('NETWORK_TWITTER', 'twit'); // Twitter
define('NETWORK_DIASPORA2', 'dspc'); // Diaspora connector define('NETWORK_DIASPORA2', 'dspc'); // Diaspora connector
define('NETWORK_STATUSNET', 'stac'); // Statusnet connector define('NETWORK_STATUSNET', 'stac'); // Statusnet connector
define('NETWORK_APPNET', 'apdn'); // app.net define('NETWORK_APPNET', 'apdn'); // app.net - Dead protocol
define('NETWORK_NEWS', 'nntp'); // Network News Transfer Protocol define('NETWORK_NEWS', 'nntp'); // Network News Transfer Protocol - Currently unsupported
define('NETWORK_ICALENDAR', 'ical'); // iCalendar define('NETWORK_ICALENDAR', 'ical'); // iCalendar - Currently unsupported
define('NETWORK_PNUT', 'pnut'); // pnut.io define('NETWORK_PNUT', 'pnut'); // pnut.io - Currently unsupported
define('NETWORK_PHANTOM', 'unkn'); // Place holder define('NETWORK_PHANTOM', 'unkn'); // Place holder
/** /**
* @} * @}
@ -290,7 +288,6 @@ $netgroup_ids = array(
NETWORK_FEED => (-4), NETWORK_FEED => (-4),
NETWORK_DIASPORA => (-5), NETWORK_DIASPORA => (-5),
NETWORK_MAIL => (-6), NETWORK_MAIL => (-6),
NETWORK_MAIL2 => (-7),
NETWORK_FACEBOOK => (-8), NETWORK_FACEBOOK => (-8),
NETWORK_LINKEDIN => (-9), NETWORK_LINKEDIN => (-9),
NETWORK_XMPP => (-10), NETWORK_XMPP => (-10),
@ -689,7 +686,7 @@ function update_db(App $a)
// Compare the current structure with the defined structure // Compare the current structure with the defined structure
$t = Config::get('database', 'dbupdate_' . DB_UPDATE_VERSION); $t = Config::get('database', 'dbupdate_' . DB_UPDATE_VERSION);
if ($t !== false) { if (!is_null($t)) {
return; return;
} }
@ -745,7 +742,7 @@ function run_update_function($x)
// delete the config entry to try again. // delete the config entry to try again.
$t = Config::get('database', 'update_' . $x); $t = Config::get('database', 'update_' . $x);
if ($t !== false) { if (!is_null($t)) {
return false; return false;
} }
Config::set('database', 'update_' . $x, time()); Config::set('database', 'update_' . $x, time());

View file

@ -1,6 +1,6 @@
-- ------------------------------------------ -- ------------------------------------------
-- Friendica 3.6-dev (Asparagus) -- Friendica 3.6-dev (Asparagus)
-- DB_UPDATE_VERSION 1235 -- DB_UPDATE_VERSION 1236
-- ------------------------------------------ -- ------------------------------------------
@ -216,7 +216,8 @@ CREATE TABLE IF NOT EXISTS `conversation` (
`source` mediumtext, `source` mediumtext,
`received` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', `received` datetime NOT NULL DEFAULT '0001-01-01 00:00:00',
PRIMARY KEY(`item-uri`), PRIMARY KEY(`item-uri`),
INDEX `conversation-uri` (`conversation-uri`) INDEX `conversation-uri` (`conversation-uri`),
INDEX `received` (`received`)
) DEFAULT COLLATE utf8mb4_general_ci; ) DEFAULT COLLATE utf8mb4_general_ci;
-- --
@ -273,29 +274,6 @@ CREATE TABLE IF NOT EXISTS `fcontact` (
UNIQUE INDEX `url` (`url`(190)) UNIQUE INDEX `url` (`url`(190))
) DEFAULT COLLATE utf8mb4_general_ci; ) DEFAULT COLLATE utf8mb4_general_ci;
--
-- TABLE ffinder
--
CREATE TABLE IF NOT EXISTS `ffinder` (
`id` int(10) unsigned NOT NULL auto_increment,
`uid` int(10) unsigned NOT NULL DEFAULT 0,
`cid` int(10) unsigned NOT NULL DEFAULT 0,
`fid` int(10) unsigned NOT NULL DEFAULT 0,
PRIMARY KEY(`id`)
) DEFAULT COLLATE utf8mb4_general_ci;
--
-- TABLE fserver
--
CREATE TABLE IF NOT EXISTS `fserver` (
`id` int(11) NOT NULL auto_increment,
`server` varchar(255) NOT NULL DEFAULT '',
`posturl` varchar(255) NOT NULL DEFAULT '',
`key` text,
PRIMARY KEY(`id`),
INDEX `server` (`server`(32))
) DEFAULT COLLATE utf8mb4_general_ci;
-- --
-- TABLE fsuggest -- TABLE fsuggest
-- --
@ -557,22 +535,6 @@ CREATE TABLE IF NOT EXISTS `item` (
INDEX `uid_ownerlink` (`uid`,`owner-link`(190)) INDEX `uid_ownerlink` (`uid`,`owner-link`(190))
) DEFAULT COLLATE utf8mb4_general_ci; ) DEFAULT COLLATE utf8mb4_general_ci;
--
-- TABLE item_id
--
CREATE TABLE IF NOT EXISTS `item_id` (
`id` int(11) NOT NULL auto_increment,
`iid` int(11) NOT NULL DEFAULT 0,
`uid` int(11) NOT NULL DEFAULT 0,
`sid` varchar(255) NOT NULL DEFAULT '',
`service` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY(`id`),
INDEX `uid` (`uid`),
INDEX `sid` (`sid`(32)),
INDEX `service` (`service`(32)),
INDEX `iid` (`iid`)
) DEFAULT COLLATE utf8mb4_general_ci;
-- --
-- TABLE locks -- TABLE locks
-- --
@ -947,23 +909,6 @@ CREATE TABLE IF NOT EXISTS `sign` (
UNIQUE INDEX `iid` (`iid`) UNIQUE INDEX `iid` (`iid`)
) DEFAULT COLLATE utf8mb4_general_ci; ) DEFAULT COLLATE utf8mb4_general_ci;
--
-- TABLE spam
--
CREATE TABLE IF NOT EXISTS `spam` (
`id` int(11) NOT NULL auto_increment,
`uid` int(11) NOT NULL DEFAULT 0,
`spam` int(11) NOT NULL DEFAULT 0,
`ham` int(11) NOT NULL DEFAULT 0,
`term` varchar(255) NOT NULL DEFAULT '',
`date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00',
PRIMARY KEY(`id`),
INDEX `uid` (`uid`),
INDEX `spam` (`spam`),
INDEX `ham` (`ham`),
INDEX `term` (`term`(32))
) DEFAULT COLLATE utf8mb4_general_ci;
-- --
-- TABLE term -- TABLE term
-- --

View file

@ -46,6 +46,7 @@ Example: To set the directory value please add this line to your .htconfig.php:
* **frontend_worker_timeout** - Value in minutes after we think that a frontend task was killed by the webserver. Default value is 10. * **frontend_worker_timeout** - Value in minutes after we think that a frontend task was killed by the webserver. Default value is 10.
* **hsts** (Boolean) - Enables the sending of HTTP Strict Transport Security headers * **hsts** (Boolean) - Enables the sending of HTTP Strict Transport Security headers
* **ignore_cache** (Boolean) - For development only. Disables the item cache. * **ignore_cache** (Boolean) - For development only. Disables the item cache.
* **instances_social_key** - Key to the API of https://instances.social which retrieves data about mastodon servers. See https://instances.social/api/token to get an API key.
* **ipv4_resolve** (Boolean) - Resolve IPV4 addresses only. Don't resolve to IPV6. Default value is false. * **ipv4_resolve** (Boolean) - Resolve IPV4 addresses only. Don't resolve to IPV6. Default value is false.
* **like_no_comment** (Boolean) - Don't update the "commented" value of an item when it is liked. * **like_no_comment** (Boolean) - Don't update the "commented" value of an item when it is liked.
* **local_block** (Boolean) - Used in conjunction with "block_public". * **local_block** (Boolean) - Used in conjunction with "block_public".

View file

@ -1,10 +1,9 @@
<?php <?php
/** /**
* @file include/acl_selectors.php * @file include/acl_selectors.php
*/ */
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Model\GlobalContact; use Friendica\Model\GlobalContact;
@ -12,10 +11,8 @@ use Friendica\Object\Contact;
require_once "include/contact_selectors.php"; require_once "include/contact_selectors.php";
require_once "include/contact_widgets.php"; require_once "include/contact_widgets.php";
require_once "include/features.php";
require_once "mod/proxy.php"; require_once "mod/proxy.php";
/** /**
* @package acl_selectors * @package acl_selectors
*/ */
@ -380,7 +377,7 @@ function populate_acl($user = null, $show_jotnets = false) {
'$aclModalTitle' => t('Permissions'), '$aclModalTitle' => t('Permissions'),
'$aclModalDismiss' => t('Close'), '$aclModalDismiss' => t('Close'),
'$features' => array( '$features' => array(
'aclautomention' => (feature_enabled($user['uid'], "aclautomention") ? "true" : "false") 'aclautomention' => (Feature::isEnabled($user['uid'], "aclautomention") ? "true" : "false")
), ),
)); ));
@ -498,10 +495,9 @@ function acl_lookup(App $a, $out_type = 'json') {
WHERE `uid` = %d AND NOT `self` WHERE `uid` = %d AND NOT `self`
AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND `success_update` >= `failure_update` AND `success_update` >= `failure_update`
AND `network` IN ('%s','%s','%s') $sql_extra2" , AND `network` IN ('%s', '%s') $sql_extra2" ,
intval(local_user()), intval(local_user()),
dbesc(NETWORK_DFRN), dbesc(NETWORK_DFRN),
dbesc(NETWORK_ZOT),
dbesc(NETWORK_DIASPORA) dbesc(NETWORK_DIASPORA)
); );
$contact_count = (int)$r[0]['c']; $contact_count = (int)$r[0]['c'];
@ -593,12 +589,11 @@ function acl_lookup(App $a, $out_type = 'json') {
} elseif ($type == 'm') { } elseif ($type == 'm') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr` FROM `contact` $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND `success_update` >= `failure_update` AND `network` IN ('%s','%s','%s') AND `success_update` >= `failure_update` AND `network` IN ('%s', '%s')
$sql_extra2 $sql_extra2
ORDER BY `name` ASC ", ORDER BY `name` ASC ",
intval(local_user()), intval(local_user()),
dbesc(NETWORK_DFRN), dbesc(NETWORK_DFRN),
dbesc(NETWORK_ZOT),
dbesc(NETWORK_DIASPORA) dbesc(NETWORK_DIASPORA)
); );
} elseif ($type == 'a') { } elseif ($type == 'a') {

View file

@ -6,12 +6,14 @@
* @todo Automatically detect if incoming data is HTML or BBCode * @todo Automatically detect if incoming data is HTML or BBCode
*/ */
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\NotificationsManager; use Friendica\Core\NotificationsManager;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Model\User; use Friendica\Model\User;
use Friendica\Network\FKOAuth1;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException;
use Friendica\Network\HTTPException\BadRequestException; use Friendica\Network\HTTPException\BadRequestException;
use Friendica\Network\HTTPException\ForbiddenException; use Friendica\Network\HTTPException\ForbiddenException;
@ -29,7 +31,6 @@ use Friendica\Util\XML;
require_once 'include/bbcode.php'; require_once 'include/bbcode.php';
require_once 'include/datetime.php'; require_once 'include/datetime.php';
require_once 'include/conversation.php'; require_once 'include/conversation.php';
require_once 'include/oauth.php';
require_once 'include/html2plain.php'; require_once 'include/html2plain.php';
require_once 'mod/share.php'; require_once 'mod/share.php';
require_once 'mod/item.php'; require_once 'mod/item.php';
@ -156,12 +157,12 @@ function api_register_func($path, $func, $auth = false, $method = API_METHOD_ANY
*/ */
function api_login(App $a) function api_login(App $a)
{ {
$oauth1 = new FKOAuth1();
// login with oauth // login with oauth
try { try {
$oauth = new FKOAuth1(); list($consumer, $token) = $oauth1->verify_request(OAuthRequest::from_request());
list($consumer,$token) = $oauth->verify_request(OAuthRequest::from_request());
if (!is_null($token)) { if (!is_null($token)) {
$oauth->loginUser($token->uid); $oauth1->loginUser($token->uid);
call_hooks('logged_in', $a->user); call_hooks('logged_in', $a->user);
return; return;
} }
@ -3363,9 +3364,9 @@ api_register_func('api/direct_messages', 'api_direct_messages_inbox', true);
function api_oauth_request_token($type) function api_oauth_request_token($type)
{ {
$oauth1 = new FKOAuth1();
try { try {
$oauth = new FKOAuth1(); $r = $oauth1->fetch_request_token(OAuthRequest::from_request());
$r = $oauth->fetch_request_token(OAuthRequest::from_request());
} catch (Exception $e) { } catch (Exception $e) {
echo "error=" . OAuthUtil::urlencode_rfc3986($e->getMessage()); echo "error=" . OAuthUtil::urlencode_rfc3986($e->getMessage());
killme(); killme();
@ -3376,9 +3377,9 @@ function api_oauth_request_token($type)
function api_oauth_access_token($type) function api_oauth_access_token($type)
{ {
$oauth1 = new FKOAuth1();
try { try {
$oauth = new FKOAuth1(); $r = $oauth1->fetch_access_token(OAuthRequest::from_request());
$r = $oauth->fetch_access_token(OAuthRequest::from_request());
} catch (Exception $e) { } catch (Exception $e) {
echo "error=". OAuthUtil::urlencode_rfc3986($e->getMessage()); echo "error=". OAuthUtil::urlencode_rfc3986($e->getMessage());
killme(); killme();
@ -5100,7 +5101,7 @@ function api_friendica_profile_show($type)
$profileid = (x($_REQUEST, 'profile_id') ? $_REQUEST['profile_id'] : 0); $profileid = (x($_REQUEST, 'profile_id') ? $_REQUEST['profile_id'] : 0);
// retrieve general information about profiles for user // retrieve general information about profiles for user
$multi_profiles = feature_enabled(api_user(), 'multi_profiles'); $multi_profiles = Feature::isEnabled(api_user(), 'multi_profiles');
$directory = Config::get('system', 'directory'); $directory = Config::get('system', 'directory');
// get data of the specified profile id or all profiles of the user if not specified // get data of the specified profile id or all profiles of the user if not specified

View file

@ -85,7 +85,6 @@ function network_to_name($s, $profile = "") {
NETWORK_LINKEDIN => t('LinkedIn'), NETWORK_LINKEDIN => t('LinkedIn'),
NETWORK_XMPP => t('XMPP/IM'), NETWORK_XMPP => t('XMPP/IM'),
NETWORK_MYSPACE => t('MySpace'), NETWORK_MYSPACE => t('MySpace'),
NETWORK_MAIL2 => t('Email'),
NETWORK_GPLUS => t('Google+'), NETWORK_GPLUS => t('Google+'),
NETWORK_PUMPIO => t('pump.io'), NETWORK_PUMPIO => t('pump.io'),
NETWORK_TWITTER => t('Twitter'), NETWORK_TWITTER => t('Twitter'),

View file

@ -1,5 +1,8 @@
<?php <?php
/**
* @file include/contact_widgets.php
*/
use Friendica\Content\Feature;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
@ -105,7 +108,7 @@ function networks_widget($baseurl, $selected = '') {
return ''; return '';
} }
if (!feature_enabled(local_user(), 'networks')) { if (!Feature::isEnabled(local_user(), 'networks')) {
return ''; return '';
} }
@ -144,7 +147,7 @@ function fileas_widget($baseurl, $selected = '') {
return ''; return '';
} }
if (! feature_enabled(local_user(), 'filing')) { if (! Feature::isEnabled(local_user(), 'filing')) {
return ''; return '';
} }
@ -178,7 +181,7 @@ function categories_widget($baseurl, $selected = '') {
$a = get_app(); $a = get_app();
if (! feature_enabled($a->profile['profile_uid'], 'categories')) { if (! Feature::isEnabled($a->profile['profile_uid'], 'categories')) {
return ''; return '';
} }

View file

@ -3,6 +3,7 @@
* @file include/conversation.php * @file include/conversation.php
*/ */
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
use Friendica\Core\System; use Friendica\Core\System;
@ -915,7 +916,7 @@ function conversation(App $a, $items, $mode, $update, $preview = false) {
'$mode' => $mode, '$mode' => $mode,
'$user' => $a->user, '$user' => $a->user,
'$threads' => $threads, '$threads' => $threads,
'$dropping' => ($page_dropping && feature_enabled(local_user(), 'multi_delete') ? t('Delete Selected Items') : False), '$dropping' => ($page_dropping && Feature::isEnabled(local_user(), 'multi_delete') ? t('Delete Selected Items') : False),
)); ));
return $o; return $o;
@ -1305,7 +1306,7 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false) {
'$title' => $x['title'], '$title' => $x['title'],
'$placeholdertitle' => t('Set title'), '$placeholdertitle' => t('Set title'),
'$category' => $x['category'], '$category' => $x['category'],
'$placeholdercategory' => (feature_enabled(local_user(), 'categories') ? t('Categories (comma-separated list)') : ''), '$placeholdercategory' => (Feature::isEnabled(local_user(), 'categories') ? t('Categories (comma-separated list)') : ''),
'$wait' => t('Please wait'), '$wait' => t('Please wait'),
'$permset' => t('Permission settings'), '$permset' => t('Permission settings'),
'$shortpermset' => t('permissions'), '$shortpermset' => t('permissions'),
@ -1321,7 +1322,7 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false) {
'$lockstate' => $x['lockstate'], '$lockstate' => $x['lockstate'],
'$bang' => $x['bang'], '$bang' => $x['bang'],
'$profile_uid' => $x['profile_uid'], '$profile_uid' => $x['profile_uid'],
'$preview' => ((feature_enabled($x['profile_uid'],'preview')) ? t('Preview') : ''), '$preview' => ((Feature::isEnabled($x['profile_uid'],'preview')) ? t('Preview') : ''),
'$jotplugins' => $jotplugins, '$jotplugins' => $jotplugins,
'$notes_cid' => $notes_cid, '$notes_cid' => $notes_cid,
'$sourceapp' => t($a->sourcename), '$sourceapp' => t($a->sourcename),

View file

@ -91,9 +91,9 @@ function metopem($m, $e) {
return $key; return $key;
} }
function pubrsatome($key,&$m,&$e) { function pubrsatome($key, &$m, &$e)
require_once('library/asn1.php'); {
require_once('include/salmon.php'); require_once 'library/asn1.php';
$lines = explode("\n", $key); $lines = explode("\n", $key);
unset($lines[0]); unset($lines[0]);
@ -117,8 +117,8 @@ function pemtorsa($key) {
return metorsa($m, $e); return metorsa($m, $e);
} }
function pemtome($key, &$m, &$e) { function pemtome($key, &$m, &$e)
require_once('include/salmon.php'); {
$lines = explode("\n", $key); $lines = explode("\n", $key);
unset($lines[0]); unset($lines[0]);
unset($lines[count($lines)]); unset($lines[count($lines)]);

View file

@ -1104,7 +1104,8 @@ class dba {
* *
* $data = dba::select($table, $fields, $condition, $params); * $data = dba::select($table, $fields, $condition, $params);
*/ */
public static function select($table, $fields = array(), $condition = array(), $params = array()) { public static function select($table, array $fields = [], array $condition = [], array $params = [])
{
if ($table == '') { if ($table == '') {
return false; return false;
} }
@ -1115,17 +1116,7 @@ class dba {
$select_fields = "*"; $select_fields = "*";
} }
if (count($condition) > 0) { $condition_string = self::buildCondition($condition);
$array_element = each($condition);
$array_key = $array_element['key'];
if (is_int($array_key)) {
$condition_string = " WHERE ".array_shift($condition);
} else {
$condition_string = " WHERE `".implode("` = ? AND `", array_keys($condition))."` = ?";
}
} else {
$condition_string = "";
}
$param_string = ''; $param_string = '';
$single_row = false; $single_row = false;
@ -1147,6 +1138,11 @@ class dba {
$single_row = ($params['limit'] == 1); $single_row = ($params['limit'] == 1);
} }
if (isset($params['limit']) && is_array($params['limit'])) {
$param_string .= " LIMIT ".intval($params['limit'][0]).", ".intval($params['limit'][1]);
$single_row = ($params['limit'][1] == 1);
}
if (isset($params['only_query']) && $params['only_query']) { if (isset($params['only_query']) && $params['only_query']) {
$single_row = !$params['only_query']; $single_row = !$params['only_query'];
} }
@ -1164,6 +1160,71 @@ class dba {
} }
} }
/**
* @brief Counts the rows from a table satisfying the provided condition
*
* @param string $table Table name
* @param array $condition array of fields for condition
*
* @return int
*
* Example:
* $table = "item";
*
* $condition = ["uid" => 1, "network" => 'dspr'];
* or:
* $condition = ["`uid` = ? AND `network` IN (?, ?)", 1, 'dfrn', 'dspr'];
*
* $count = dba::count($table, $condition);
*/
public static function count($table, array $condition = [])
{
if ($table == '') {
return false;
}
$condition_string = self::buildCondition($condition);
$sql = "SELECT COUNT(*) AS `count` FROM `".$table."`".$condition_string;
$row = self::fetch_first($sql, $condition);
return $row['count'];
}
/**
* @brief Returns the SQL condition string built from the provided condition array
*
* This function operates with two modes.
* - Supplied with a filed/value associative array, it builds simple strict
* equality conditions linked by AND.
* - Supplied with a flat list, the first element is the condition string and
* the following arguments are the values to be interpolated
*
* $condition = ["uid" => 1, "network" => 'dspr'];
* or:
* $condition = ["`uid` = ? AND `network` IN (?, ?)", 1, 'dfrn', 'dspr'];
*
* In either case, the provided array is left with the parameters only
*
* @param array $condition
* @return string
*/
private static function buildCondition(array &$condition = [])
{
$condition_string = '';
if (count($condition) > 0) {
$array_element = each($condition);
$array_key = $array_element['key'];
if (is_int($array_key)) {
$condition_string = " WHERE ".array_shift($condition);
} else {
$condition_string = " WHERE `".implode("` = ? AND `", array_keys($condition))."` = ?";
}
}
return $condition_string;
}
/** /**
* @brief Fills an array with data from a query * @brief Fills an array with data from a query

View file

@ -1,5 +1,7 @@
<?php <?php
/**
* @file include/dbstructure.php
*/
use Friendica\App; use Friendica\App;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Config; use Friendica\Core\Config;
@ -77,30 +79,10 @@ function update_fail($update_id, $error_message) {
'to_email' => $admin['email'], 'to_email' => $admin['email'],
'preamble' => $preamble, 'preamble' => $preamble,
'body' => $body, 'body' => $body,
'language' => $lang, 'language' => $lang)
)); );
} }
/*
@TODO deprecated code?
$email_tpl = get_intltext_template("update_fail_eml.tpl");
$email_msg = replace_macros($email_tpl, array(
'$sitename' => $a->config['sitename'],
'$siteurl' => System::baseUrl(),
'$update' => DB_UPDATE_VERSION,
'$error' => sprintf(t('Update %s failed. See error logs.'), DB_UPDATE_VERSION)
));
$subject=sprintf(t('Update Error at %s'), System::baseUrl());
require_once('include/email.php');
$subject = email_header_encode($subject,'UTF-8');
mail($a->config['admin_email'], $subject, $email_msg,
'From: ' . 'Administrator' . '@' . $_SERVER['SERVER_NAME']."\n"
.'Content-type: text/plain; charset=UTF-8'."\n"
.'Content-transfer-encoding: 8bit');
*/
//try the logger //try the logger
logger("CRITICAL: Database structure update failed: ".$retval); logger("CRITICAL: Database structure update failed: ".$retval);
} }
@ -849,6 +831,7 @@ function db_definition() {
"indexes" => array( "indexes" => array(
"PRIMARY" => array("item-uri"), "PRIMARY" => array("item-uri"),
"conversation-uri" => array("conversation-uri"), "conversation-uri" => array("conversation-uri"),
"received" => array("received"),
) )
); );
$database["event"] = array( $database["event"] = array(
@ -905,29 +888,6 @@ function db_definition() {
"url" => array("UNIQUE", "url(190)"), "url" => array("UNIQUE", "url(190)"),
) )
); );
$database["ffinder"] = array(
"fields" => array(
"id" => array("type" => "int(10) unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"uid" => array("type" => "int(10) unsigned", "not null" => "1", "default" => "0", "relation" => array("user" => "uid")),
"cid" => array("type" => "int(10) unsigned", "not null" => "1", "default" => "0", "relation" => array("contact" => "id")),
"fid" => array("type" => "int(10) unsigned", "not null" => "1", "default" => "0", "relation" => array("fcontact" => "id")),
),
"indexes" => array(
"PRIMARY" => array("id"),
)
);
$database["fserver"] = array(
"fields" => array(
"id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"server" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"posturl" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"key" => array("type" => "text"),
),
"indexes" => array(
"PRIMARY" => array("id"),
"server" => array("server(32)"),
)
);
$database["fsuggest"] = array( $database["fsuggest"] = array(
"fields" => array( "fields" => array(
"id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"), "id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
@ -1189,22 +1149,6 @@ function db_definition() {
"uid_ownerlink" => array("uid","owner-link(190)"), "uid_ownerlink" => array("uid","owner-link(190)"),
) )
); );
$database["item_id"] = array(
"fields" => array(
"id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"iid" => array("type" => "int(11)", "not null" => "1", "default" => "0", "relation" => array("item" => "id")),
"uid" => array("type" => "int(11)", "not null" => "1", "default" => "0", "relation" => array("user" => "uid")),
"sid" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"service" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
),
"indexes" => array(
"PRIMARY" => array("id"),
"uid" => array("uid"),
"sid" => array("sid(32)"),
"service" => array("service(32)"),
"iid" => array("iid"),
)
);
$database["locks"] = array( $database["locks"] = array(
"fields" => array( "fields" => array(
"id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"), "id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
@ -1579,23 +1523,6 @@ function db_definition() {
"iid" => array("UNIQUE", "iid"), "iid" => array("UNIQUE", "iid"),
) )
); );
$database["spam"] = array(
"fields" => array(
"id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"uid" => array("type" => "int(11)", "not null" => "1", "default" => "0", "relation" => array("user" => "uid")),
"spam" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"ham" => array("type" => "int(11)", "not null" => "1", "default" => "0"),
"term" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"date" => array("type" => "datetime", "not null" => "1", "default" => NULL_DATE),
),
"indexes" => array(
"PRIMARY" => array("id"),
"uid" => array("uid"),
"spam" => array("spam"),
"ham" => array("ham"),
"term" => array("term(32)"),
)
);
$database["term"] = array( $database["term"] = array(
"fields" => array( "fields" => array(
"tid" => array("type" => "int(10) unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"), "tid" => array("type" => "int(10) unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),

View file

@ -1,317 +0,0 @@
<?php
require_once('include/html2plain.php');
require_once('include/msgclean.php');
require_once('include/quoteconvert.php');
function email_connect($mailbox,$username,$password) {
if (! function_exists('imap_open'))
return false;
$mbox = @imap_open($mailbox,$username,$password);
return $mbox;
}
function email_poll($mbox,$email_addr) {
if (! ($mbox && $email_addr))
return array();
$search1 = @imap_search($mbox,'FROM "' . $email_addr . '"', SE_UID);
if (!$search1) {
$search1 = array();
} else {
logger("Found mails from ".$email_addr, LOGGER_DEBUG);
}
$search2 = @imap_search($mbox,'TO "' . $email_addr . '"', SE_UID);
if (!$search2) {
$search2 = array();
} else {
logger("Found mails to ".$email_addr, LOGGER_DEBUG);
}
$search3 = @imap_search($mbox,'CC "' . $email_addr . '"', SE_UID);
if (!$search3) {
$search3 = array();
} else {
logger("Found mails cc ".$email_addr, LOGGER_DEBUG);
}
$res = array_unique(array_merge($search1, $search2, $search3));
return $res;
}
function construct_mailbox_name($mailacct) {
$ret = '{' . $mailacct['server'] . ((intval($mailacct['port'])) ? ':' . $mailacct['port'] : '');
$ret .= (($mailacct['ssltype']) ? '/' . $mailacct['ssltype'] . '/novalidate-cert' : '');
$ret .= '}' . $mailacct['mailbox'];
return $ret;
}
function email_msg_meta($mbox,$uid) {
$ret = (($mbox && $uid) ? @imap_fetch_overview($mbox,$uid,FT_UID) : array(array())); // POSSIBLE CLEANUP --> array(array()) is probably redundant now
return ((count($ret)) ? $ret : array());
}
function email_msg_headers($mbox,$uid) {
$raw_header = (($mbox && $uid) ? @imap_fetchheader($mbox,$uid,FT_UID) : '');
$raw_header = str_replace("\r",'',$raw_header);
$ret = array();
$h = explode("\n",$raw_header);
if (count($h))
foreach ($h as $line ) {
if (preg_match("/^[a-zA-Z]/", $line)) {
$key = substr($line,0,strpos($line,':'));
$value = substr($line,strpos($line,':')+1);
$last_entry = strtolower($key);
$ret[$last_entry] = trim($value);
}
else {
$ret[$last_entry] .= ' ' . trim($line);
}
}
return $ret;
}
function email_get_msg($mbox,$uid, $reply) {
$ret = array();
$struc = (($mbox && $uid) ? @imap_fetchstructure($mbox,$uid,FT_UID) : null);
if (! $struc)
return $ret;
if (! $struc->parts) {
$ret['body'] = email_get_part($mbox,$uid,$struc,0, 'html');
$html = $ret['body'];
if (trim($ret['body']) == '')
$ret['body'] = email_get_part($mbox,$uid,$struc,0, 'plain');
else
$ret['body'] = html2bbcode($ret['body']);
}
else {
$text = '';
$html = '';
foreach ($struc->parts as $ptop => $p) {
$x = email_get_part($mbox,$uid,$p,$ptop + 1, 'plain');
if ($x) {
$text .= $x;
}
$x = email_get_part($mbox,$uid,$p,$ptop + 1, 'html');
if ($x) {
$html .= $x;
}
}
if (trim($html) != '') {
$ret['body'] = html2bbcode($html);
} else {
$ret['body'] = $text;
}
}
$ret['body'] = removegpg($ret['body']);
$msg = removesig($ret['body']);
$ret['body'] = $msg['body'];
$ret['body'] = convertquote($ret['body'], $reply);
if (trim($html) != '') {
$ret['body'] = removelinebreak($ret['body']);
}
$ret['body'] = unifyattributionline($ret['body']);
return $ret;
}
// At the moment - only return plain/text.
// Later we'll repackage inline images as data url's and make the HTML safe
function email_get_part($mbox,$uid,$p,$partno, $subtype) {
// $partno = '1', '2', '2.1', '2.1.3', etc for multipart, 0 if simple
global $htmlmsg,$plainmsg,$charset,$attachments;
//echo $partno."\n";
// DECODE DATA
$data = ($partno)
? @imap_fetchbody($mbox,$uid,$partno, FT_UID|FT_PEEK)
: @imap_body($mbox,$uid,FT_UID|FT_PEEK);
// Any part may be encoded, even plain text messages, so check everything.
if ($p->encoding==4)
$data = quoted_printable_decode($data);
elseif ($p->encoding==3)
$data = base64_decode($data);
// PARAMETERS
// get all parameters, like charset, filenames of attachments, etc.
$params = array();
if ($p->parameters)
foreach ($p->parameters as $x)
$params[strtolower($x->attribute)] = $x->value;
if (isset($p->dparameters) && $p->dparameters)
foreach ($p->dparameters as $x)
$params[strtolower($x->attribute)] = $x->value;
// ATTACHMENT
// Any part with a filename is an attachment,
// so an attached text file (type 0) is not mistaken as the message.
if ((isset($params['filename']) && $params['filename']) || (isset($params['name']) && $params['name'])) {
// filename may be given as 'Filename' or 'Name' or both
$filename = ($params['filename'])? $params['filename'] : $params['name'];
// filename may be encoded, so see imap_mime_header_decode()
$attachments[$filename] = $data; // this is a problem if two files have same name
}
// TEXT
if ($p->type == 0 && $data) {
// Messages may be split in different parts because of inline attachments,
// so append parts together with blank row.
if (strtolower($p->subtype)==$subtype) {
$data = iconv($params['charset'], 'UTF-8//IGNORE', $data);
return (trim($data) ."\n\n");
} else
$data = '';
// $htmlmsg .= $data ."<br><br>";
$charset = $params['charset']; // assume all parts are same charset
}
// EMBEDDED MESSAGE
// Many bounce notifications embed the original message as type 2,
// but AOL uses type 1 (multipart), which is not handled here.
// There are no PHP functions to parse embedded messages,
// so this just appends the raw source to the main message.
// elseif ($p->type==2 && $data) {
// $plainmsg .= $data."\n\n";
// }
// SUBPART RECURSION
if (isset($p->parts) && $p->parts) {
$x = "";
foreach ($p->parts as $partno0=>$p2) {
$x .= email_get_part($mbox,$uid,$p2,$partno . '.' . ($partno0+1), $subtype); // 1.2, 1.2.1, etc.
//if ($x) {
// return $x;
//}
}
return $x;
}
}
function email_header_encode($in_str, $charset) {
$out_str = $in_str;
$need_to_convert = false;
for ($x = 0; $x < strlen($in_str); $x ++) {
if ((ord($in_str[$x]) == 0) || ((ord($in_str[$x]) > 128))) {
$need_to_convert = true;
}
}
if (! $need_to_convert)
return $in_str;
if ($out_str && $charset) {
// define start delimimter, end delimiter and spacer
$end = "?=";
$start = "=?" . $charset . "?B?";
$spacer = $end . "\r\n " . $start;
// determine length of encoded text within chunks
// and ensure length is even
$length = 75 - strlen($start) - strlen($end);
/*
[EDIT BY danbrown AT php DOT net: The following
is a bugfix provided by (gardan AT gmx DOT de)
on 31-MAR-2005 with the following note:
"This means: $length should not be even,
but divisible by 4. The reason is that in
base64-encoding 3 8-bit-chars are represented
by 4 6-bit-chars. These 4 chars must not be
split between two encoded words, according
to RFC-2047.
*/
$length = $length - ($length % 4);
// encode the string and split it into chunks
// with spacers after each chunk
$out_str = base64_encode($out_str);
$out_str = chunk_split($out_str, $length, $spacer);
// remove trailing spacer and
// add start and end delimiters
$spacer = preg_quote($spacer,'/');
$out_str = preg_replace("/" . $spacer . "$/", "", $out_str);
$out_str = $start . $out_str . $end;
}
return $out_str;
}
/**
* email_send is used by NETWORK_EMAIL and NETWORK_EMAIL2 code
* (not to notify the user, but to send items to email contacts)
*
* @todo This could be changed to use the Emailer class
*/
function email_send($addr, $subject, $headers, $item) {
//$headers .= 'MIME-Version: 1.0' . "\n";
//$headers .= 'Content-Type: text/html; charset=UTF-8' . "\n";
//$headers .= 'Content-Type: text/plain; charset=UTF-8' . "\n";
//$headers .= 'Content-Transfer-Encoding: 8bit' . "\n\n";
$part = uniqid("", true);
$html = prepare_body($item);
$headers .= "Mime-Version: 1.0\n";
$headers .= 'Content-Type: multipart/alternative; boundary="=_'.$part.'"'."\n\n";
$body = "\n--=_".$part."\n";
$body .= "Content-Transfer-Encoding: 8bit\n";
$body .= "Content-Type: text/plain; charset=utf-8; format=flowed\n\n";
$body .= html2plain($html)."\n";
$body .= "--=_".$part."\n";
$body .= "Content-Transfer-Encoding: 8bit\n";
$body .= "Content-Type: text/html; charset=utf-8\n\n";
$body .= '<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">'.$html."</body></html>\n";
$body .= "--=_".$part."--";
//$message = '<html><body>' . $html . '</body></html>';
//$message = html2plain($html);
logger('notifier: email delivery to ' . $addr);
mail($addr, $subject, $body, $headers);
}
function iri2msgid($iri) {
if (!strpos($iri, "@"))
$msgid = preg_replace("/urn:(\S+):(\S+)\.(\S+):(\d+):(\S+)/i", "urn!$1!$4!$5@$2.$3", $iri);
else
$msgid = $iri;
return($msgid);
}
function msgid2iri($msgid) {
if (strpos($msgid, "@"))
$iri = preg_replace("/urn!(\S+)!(\d+)!(\S+)@(\S+)\.(\S+)/i", "urn:$1:$4.$5:$2:$3", $msgid);
else
$iri = $msgid;
return($iri);
}

View file

@ -8,7 +8,6 @@ use Friendica\Core\System;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Util\Emailer; use Friendica\Util\Emailer;
require_once 'include/email.php';
require_once 'include/bbcode.php'; require_once 'include/bbcode.php';
require_once 'include/html2bbcode.php'; require_once 'include/html2bbcode.php';

View file

@ -5,6 +5,7 @@
*/ */
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Database\DBM; use Friendica\Database\DBM;
@ -899,7 +900,7 @@ function widget_events() {
* for exporting the cal is enabled (otherwise the widget would appear for logged in users * for exporting the cal is enabled (otherwise the widget would appear for logged in users
* on foreigen profile pages even if the widget is disabled). * on foreigen profile pages even if the widget is disabled).
*/ */
if (intval($owner_uid) && local_user() !== $owner_uid && ! feature_enabled($owner_uid, "export_calendar")) { if (intval($owner_uid) && local_user() !== $owner_uid && ! Feature::isEnabled($owner_uid, "export_calendar")) {
return; return;
} }
@ -907,7 +908,7 @@ function widget_events() {
* If it's a kind of profile page (intval($owner_uid)) return if the user not logged in and * If it's a kind of profile page (intval($owner_uid)) return if the user not logged in and
* export feature isn't enabled. * export feature isn't enabled.
*/ */
if (intval($owner_uid) && ! local_user() && ! feature_enabled($owner_uid, "export_calendar")) { if (intval($owner_uid) && ! local_user() && ! Feature::isEnabled($owner_uid, "export_calendar")) {
return; return;
} }

View file

@ -1,33 +0,0 @@
<?php
use Friendica\Database\DBM;
function fcontact_store($url,$name,$photo) {
$nurl = str_replace(array('https:','//www.'), array('http:','//'), $url);
$r = q("SELECT `id` FROM `fcontact` WHERE `url` = '%s' LIMIT 1",
dbesc($nurl)
);
if (DBM::is_result($r))
return $r[0]['id'];
$r = dba::insert('fcontact', array('url' => $nurl, 'name' => $name, 'photo' => $photo));
if (DBM::is_result($r)) {
$r = q("SELECT `id` FROM `fcontact` WHERE `url` = '%s' LIMIT 1",
dbesc($nurl)
);
if (DBM::is_result($r))
return $r[0]['id'];
}
return 0;
}
function ffinder_store($uid,$cid,$fid) {
$r = dba::insert('ffinder', array('uid' => $uid, 'cid' => $cid, 'fid' => $fid));
return $r;
}

View file

@ -1,144 +0,0 @@
<?php
/**
* @file include/features.php
* @brief Features management
*/
use Friendica\Core\Config;
use Friendica\Core\PConfig;
/**
* @brief check if feature is enabled
*
* @return boolean
*/
function feature_enabled($uid, $feature) {
$x = Config::get('feature_lock', $feature, false);
if ($x === false) {
$x = PConfig::get($uid, 'feature', $feature, false);
}
if ($x === false) {
$x = Config::get('feature', $feature, false);
}
if ($x === false) {
$x = get_feature_default($feature);
}
$arr = array('uid' => $uid, 'feature' => $feature, 'enabled' => $x);
call_hooks('feature_enabled',$arr);
return($arr['enabled']);
}
/**
* @brief check if feature is enabled or disabled by default
*
* @param string $feature
* @return boolean
*/
function get_feature_default($feature) {
$f = get_features();
foreach ($f as $cat) {
foreach ($cat as $feat) {
if (is_array($feat) && $feat[0] === $feature)
return $feat[3];
}
}
return false;
}
/**
* @brief Get a list of all available features
*
* The array includes the setting group, the setting name,
* explainations for the setting and if it's enabled or disabled
* by default
*
* @param bool $filtered True removes any locked features
*
* @return array
*/
function get_features($filtered = true) {
$arr = array(
// General
'general' => array(
t('General Features'),
//array('expire', t('Content Expiration'), t('Remove old posts/comments after a period of time')),
array('multi_profiles', t('Multiple Profiles'), t('Ability to create multiple profiles'), false, Config::get('feature_lock','multi_profiles', false)),
array('photo_location', t('Photo Location'), t('Photo metadata is normally stripped. This extracts the location (if present) prior to stripping metadata and links it to a map.'), false, Config::get('feature_lock','photo_location', false)),
array('export_calendar', t('Export Public Calendar'), t('Ability for visitors to download the public calendar'), false, Config::get('feature_lock','export_calendar', false)),
),
// Post composition
'composition' => array(
t('Post Composition Features'),
array('preview', t('Post Preview'), t('Allow previewing posts and comments before publishing them'), false, Config::get('feature_lock','preview', false)),
array('aclautomention', t('Auto-mention Forums'), t('Add/remove mention when a forum page is selected/deselected in ACL window.'), false, Config::get('feature_lock','aclautomention', false)),
),
// Network sidebar widgets
'widgets' => array(
t('Network Sidebar Widgets'),
array('archives', t('Search by Date'), t('Ability to select posts by date ranges'), false, Config::get('feature_lock','archives', false)),
array('forumlist_widget', t('List Forums'), t('Enable widget to display the forums your are connected with'), true, Config::get('feature_lock','forumlist_widget', false)),
array('groups', t('Group Filter'), t('Enable widget to display Network posts only from selected group'), false, Config::get('feature_lock','groups', false)),
array('networks', t('Network Filter'), t('Enable widget to display Network posts only from selected network'), false, Config::get('feature_lock','networks', false)),
array('savedsearch', t('Saved Searches'), t('Save search terms for re-use'), false, Config::get('feature_lock','savedsearch', false)),
),
// Network tabs
'net_tabs' => array(
t('Network Tabs'),
array('personal_tab', t('Network Personal Tab'), t('Enable tab to display only Network posts that you\'ve interacted on'), false, Config::get('feature_lock','personal_tab', false)),
array('new_tab', t('Network New Tab'), t('Enable tab to display only new Network posts (from the last 12 hours)'), false, Config::get('feature_lock','new_tab', false)),
array('link_tab', t('Network Shared Links Tab'), t('Enable tab to display only Network posts with links in them'), false, Config::get('feature_lock','link_tab', false)),
),
// Item tools
'tools' => array(
t('Post/Comment Tools'),
array('multi_delete', t('Multiple Deletion'), t('Select and delete multiple posts/comments at once'), false, Config::get('feature_lock','multi_delete', false)),
array('edit_posts', t('Edit Sent Posts'), t('Edit and correct posts and comments after sending'), false, Config::get('feature_lock','edit_posts', false)),
array('commtag', t('Tagging'), t('Ability to tag existing posts'), false, Config::get('feature_lock','commtag', false)),
array('categories', t('Post Categories'), t('Add categories to your posts'), false, Config::get('feature_lock','categories', false)),
array('filing', t('Saved Folders'), t('Ability to file posts under folders'), false, Config::get('feature_lock','filing', false)),
array('dislike', t('Dislike Posts'), t('Ability to dislike posts/comments'), false, Config::get('feature_lock','dislike', false)),
array('star_posts', t('Star Posts'), t('Ability to mark special posts with a star indicator'), false, Config::get('feature_lock','star_posts', false)),
array('ignore_posts', t('Mute Post Notifications'), t('Ability to mute notifications for a thread'), false, Config::get('feature_lock','ignore_posts', false)),
),
// Advanced Profile Settings
'advanced_profile' => array(
t('Advanced Profile Settings'),
array('forumlist_profile', t('List Forums'), t('Show visitors public community forums at the Advanced Profile Page'), false, Config::get('feature_lock','forumlist_profile', false)),
array('tagadelic', t('Tag Cloud'), t('Provide a personal tag cloud on your profile page'), false, Config::get('feature_lock', 'tagadelic', false)),
),
);
// removed any locked features and remove the entire category if this makes it empty
if ($filtered) {
foreach ($arr as $k => $x) {
$has_items = false;
$kquantity = count($arr[$k]);
for ($y = 0; $y < $kquantity; $y ++) {
if (is_array($arr[$k][$y])) {
if ($arr[$k][$y][4] === false) {
$has_items = true;
} else {
unset($arr[$k][$y]);
}
}
}
if (! $has_items) {
unset($arr[$k]);
}
}
}
call_hooks('get_features',$arr);
return $arr;
}

View file

@ -12,9 +12,9 @@ use Friendica\Object\Contact;
use Friendica\Protocol\Diaspora; use Friendica\Protocol\Diaspora;
use Friendica\Protocol\OStatus; use Friendica\Protocol\OStatus;
use Friendica\Protocol\PortableContact; use Friendica\Protocol\PortableContact;
use Friendica\Protocol\Salmon;
require_once 'include/group.php'; require_once 'include/group.php';
require_once 'include/salmon.php';
function update_contact($id) { function update_contact($id) {
/* /*
@ -268,7 +268,7 @@ function new_contact($uid, $url, $interactive = false, $network = '') {
$item['verb'] = ACTIVITY_FOLLOW; $item['verb'] = ACTIVITY_FOLLOW;
$item['follow'] = $contact["url"]; $item['follow'] = $contact["url"];
$slap = OStatus::salmon($item, $r[0]); $slap = OStatus::salmon($item, $r[0]);
slapper($r[0], $contact['notify'], $slap); Salmon::slapper($r[0], $contact['notify'], $slap);
} }
if ($contact['network'] == NETWORK_DIASPORA) { if ($contact['network'] == NETWORK_DIASPORA) {

View file

@ -4,6 +4,7 @@
*/ */
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Content\ForumManager; use Friendica\Content\ForumManager;
use Friendica\Core\Cache; use Friendica\Core\Cache;
use Friendica\Core\Config; use Friendica\Core\Config;
@ -309,7 +310,7 @@ function profile_sidebar($profile, $block = 0)
} }
// show edit profile to yourself // show edit profile to yourself
if (!$is_contact && $profile['uid'] == local_user() && feature_enabled(local_user(), 'multi_profiles')) { if (!$is_contact && $profile['uid'] == local_user() && Feature::isEnabled(local_user(), 'multi_profiles')) {
$profile['edit'] = array(System::baseUrl(). '/profiles', t('Profiles'),"", t('Manage/edit profiles')); $profile['edit'] = array(System::baseUrl(). '/profiles', t('Profiles'),"", t('Manage/edit profiles'));
$r = q( $r = q(
"SELECT * FROM `profile` WHERE `uid` = %d", "SELECT * FROM `profile` WHERE `uid` = %d",
@ -336,7 +337,7 @@ function profile_sidebar($profile, $block = 0)
} }
} }
} }
if (!$is_contact && $profile['uid'] == local_user() && !feature_enabled(local_user(), 'multi_profiles')) { if (!$is_contact && $profile['uid'] == local_user() && !Feature::isEnabled(local_user(), 'multi_profiles')) {
$profile['edit'] = array(System::baseUrl(). '/profiles/'.$profile['id'], t('Edit profile'),"", t('Edit profile')); $profile['edit'] = array(System::baseUrl(). '/profiles/'.$profile['id'], t('Edit profile'),"", t('Edit profile'));
$profile['menu'] = array( $profile['menu'] = array(
'chg_photo' => t('Change profile photo'), 'chg_photo' => t('Change profile photo'),
@ -790,7 +791,7 @@ function advanced_profile(App $a)
} }
//show subcribed forum if it is enabled in the usersettings //show subcribed forum if it is enabled in the usersettings
if (feature_enabled($uid, 'forumlist_profile')) { if (Feature::isEnabled($uid, 'forumlist_profile')) {
$profile['forumlist'] = array( t('Forums:'), ForumManager::profileAdvanced($uid)); $profile['forumlist'] = array( t('Forums:'), ForumManager::profileAdvanced($uid));
} }

View file

@ -4,6 +4,7 @@
*/ */
use Friendica\App; use Friendica\App;
use Friendica\ParseUrl; use Friendica\ParseUrl;
use Friendica\Content\Feature;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
use Friendica\Core\Worker; use Friendica\Core\Worker;
@ -17,12 +18,10 @@ use Friendica\Util\Lock;
require_once 'include/bbcode.php'; require_once 'include/bbcode.php';
require_once 'include/oembed.php'; require_once 'include/oembed.php';
require_once 'include/salmon.php';
require_once 'include/crypto.php'; require_once 'include/crypto.php';
require_once 'include/tags.php'; require_once 'include/tags.php';
require_once 'include/files.php'; require_once 'include/files.php';
require_once 'include/text.php'; require_once 'include/text.php';
require_once 'include/email.php';
require_once 'include/threads.php'; require_once 'include/threads.php';
require_once 'include/plaintext.php'; require_once 'include/plaintext.php';
require_once 'include/feed.php'; require_once 'include/feed.php';
@ -1152,6 +1151,19 @@ function item_store($arr, $force_parent = false, $notify = false, $dontcache = f
* @param array $arr Contains the just posted item record * @param array $arr Contains the just posted item record
*/ */
function item_set_last_item($arr) { function item_set_last_item($arr) {
// Unarchive the author
$contact = dba::select('contact', [], ['id' => $arr["author-link"]], ['limit' => 1]);
if ($contact['term-date'] > NULL_DATE) {
Contact::unmarkForArchival($contact);
}
// Unarchive the contact if it is a toplevel posting
if ($arr["parent-uri"] === $arr["uri"]) {
$contact = dba::select('contact', [], ['id' => $arr["contact-id"]], ['limit' => 1]);
if ($contact['term-date'] > NULL_DATE) {
Contact::unmarkForArchival($contact);
}
}
$update = (!$arr['private'] && (($arr["author-link"] === $arr["owner-link"]) || ($arr["parent-uri"] === $arr["uri"]))); $update = (!$arr['private'] && (($arr["author-link"] === $arr["owner-link"]) || ($arr["parent-uri"] === $arr["uri"])));
@ -1680,8 +1692,8 @@ function new_follower($importer, $contact, $datarray, $item, $sharing = false) {
dbesc($name), dbesc($name),
dbesc($nick), dbesc($nick),
dbesc($photo), dbesc($photo),
dbesc(($sharing) ? NETWORK_ZOT : NETWORK_OSTATUS), dbesc(NETWORK_OSTATUS),
intval(($sharing) ? CONTACT_IS_SHARING : CONTACT_IS_FOLLOWER) intval(CONTACT_IS_FOLLOWER)
); );
$r = q("SELECT `id`, `network` FROM `contact` WHERE `uid` = %d AND `url` = '%s' AND `pending` = 1 LIMIT 1", $r = q("SELECT `id`, `network` FROM `contact` WHERE `uid` = %d AND `url` = '%s' AND `pending` = 1 LIMIT 1",
intval($importer['uid']), intval($importer['uid']),
@ -2221,7 +2233,6 @@ function drop_item($id, $interactive = true) {
// Now delete them // Now delete them
if ($parentid != "") { if ($parentid != "") {
$r = q("DELETE FROM `item_id` WHERE `iid` IN (%s)", dbesc($parentid));
$r = q("DELETE FROM `sign` WHERE `iid` IN (%s)", dbesc($parentid)); $r = q("DELETE FROM `sign` WHERE `iid` IN (%s)", dbesc($parentid));
} }
@ -2357,7 +2368,7 @@ function posted_dates($uid, $wall) {
function posted_date_widget($url, $uid, $wall) { function posted_date_widget($url, $uid, $wall) {
$o = ''; $o = '';
if (! feature_enabled($uid, 'archives')) { if (! Feature::isEnabled($uid, 'archives')) {
return $o; return $o;
} }

View file

@ -1,6 +1,9 @@
<?php <?php
/**
* @file include/nav.php
*/
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Database\DBM; use Friendica\Database\DBM;
@ -190,7 +193,7 @@ function nav_info(App $a)
$nav['settings'] = array('settings', t('Settings'), '', t('Account settings')); $nav['settings'] = array('settings', t('Settings'), '', t('Account settings'));
if (feature_enabled(local_user(), 'multi_profiles')) { if (Feature::isEnabled(local_user(), 'multi_profiles')) {
$nav['profiles'] = array('profiles', t('Profiles'), '', t('Manage/Edit Profiles')); $nav['profiles'] = array('profiles', t('Profiles'), '', t('Manage/Edit Profiles'));
} }
@ -206,7 +209,7 @@ function nav_info(App $a)
// Provide a banner/logo/whatever // Provide a banner/logo/whatever
$banner = Config::get('system', 'banner'); $banner = Config::get('system', 'banner');
if ($banner === false) { if (is_null($banner)) {
$banner = '<a href="https://friendi.ca"><img id="logo-img" src="images/friendica-32.png" alt="logo" /></a><span id="logo-text"><a href="https://friendi.ca">Friendica</a></span>'; $banner = '<a href="https://friendi.ca"><img id="logo-img" src="images/friendica-32.png" alt="logo" /></a><span id="logo-text"><a href="https://friendi.ca">Friendica</a></span>';
} }

View file

@ -126,8 +126,8 @@ function z_fetch_url($url, $binary = false, &$redirects = 0, $opts = array())
if (x($opts, 'timeout')) { if (x($opts, 'timeout')) {
@curl_setopt($ch, CURLOPT_TIMEOUT, $opts['timeout']); @curl_setopt($ch, CURLOPT_TIMEOUT, $opts['timeout']);
} else { } else {
$curl_time = intval(Config::get('system', 'curl_timeout')); $curl_time = Config::get('system', 'curl_timeout', 60);
@curl_setopt($ch, CURLOPT_TIMEOUT, (($curl_time !== false) ? $curl_time : 60)); @curl_setopt($ch, CURLOPT_TIMEOUT, intval($curl_time));
} }
// by default we will allow self-signed certs // by default we will allow self-signed certs
@ -302,8 +302,8 @@ function post_url($url, $params, $headers = null, &$redirects = 0, $timeout = 0)
if (intval($timeout)) { if (intval($timeout)) {
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
} else { } else {
$curl_time = intval(Config::get('system', 'curl_timeout')); $curl_time = Config::get('system', 'curl_timeout', 60);
curl_setopt($ch, CURLOPT_TIMEOUT, (($curl_time !== false) ? $curl_time : 60)); curl_setopt($ch, CURLOPT_TIMEOUT, intval($curl_time));
} }
if (defined('LIGHTTPD')) { if (defined('LIGHTTPD')) {

View file

@ -1,184 +0,0 @@
<?php
/**
* OAuth server
* Based on oauth2-php <http://code.google.com/p/oauth2-php/>
*
*/
use Friendica\App;
use Friendica\Core\Config;
use Friendica\Core\PConfig;
use Friendica\Core\System;
use Friendica\Database\DBM;
define('REQUEST_TOKEN_DURATION', 300);
define('ACCESS_TOKEN_DURATION', 31536000);
require_once("library/OAuth1.php");
require_once("library/oauth2-php/lib/OAuth2.inc");
class FKOAuthDataStore extends OAuthDataStore {
function gen_token(){
return md5(base64_encode(pack('N6', mt_rand(), mt_rand(), mt_rand(), mt_rand(), mt_rand(), uniqid())));
}
function lookup_consumer($consumer_key) {
logger(__function__.":".$consumer_key);
//echo "<pre>"; var_dump($consumer_key); killme();
$r = q("SELECT client_id, pw, redirect_uri FROM clients WHERE client_id='%s'",
dbesc($consumer_key)
);
if (DBM::is_result($r))
return new OAuthConsumer($r[0]['client_id'],$r[0]['pw'],$r[0]['redirect_uri']);
return null;
}
function lookup_token($consumer, $token_type, $token) {
logger(__function__.":".$consumer.", ". $token_type.", ".$token);
$r = q("SELECT id, secret,scope, expires, uid FROM tokens WHERE client_id='%s' AND scope='%s' AND id='%s'",
dbesc($consumer->key),
dbesc($token_type),
dbesc($token)
);
if (DBM::is_result($r)){
$ot=new OAuthToken($r[0]['id'],$r[0]['secret']);
$ot->scope=$r[0]['scope'];
$ot->expires = $r[0]['expires'];
$ot->uid = $r[0]['uid'];
return $ot;
}
return null;
}
function lookup_nonce($consumer, $token, $nonce, $timestamp) {
//echo __file__.":".__line__."<pre>"; var_dump($consumer,$key); killme();
$r = q("SELECT id, secret FROM tokens WHERE client_id='%s' AND id='%s' AND expires=%d",
dbesc($consumer->key),
dbesc($nonce),
intval($timestamp)
);
if (DBM::is_result($r))
return new OAuthToken($r[0]['id'],$r[0]['secret']);
return null;
}
function new_request_token($consumer, $callback = null) {
logger(__function__.":".$consumer.", ". $callback);
$key = $this->gen_token();
$sec = $this->gen_token();
if ($consumer->key){
$k = $consumer->key;
} else {
$k = $consumer;
}
$r = q("INSERT INTO tokens (id, secret, client_id, scope, expires) VALUES ('%s','%s','%s','%s', UNIX_TIMESTAMP()+%d)",
dbesc($key),
dbesc($sec),
dbesc($k),
'request',
intval(REQUEST_TOKEN_DURATION));
if (!$r) return null;
return new OAuthToken($key,$sec);
}
function new_access_token($token, $consumer, $verifier = null) {
logger(__function__.":".$token.", ". $consumer.", ". $verifier);
// return a new access token attached to this consumer
// for the user associated with this token if the request token
// is authorized
// should also invalidate the request token
$ret=Null;
// get user for this verifier
$uverifier = Config::get("oauth", $verifier);
logger(__function__.":".$verifier.",".$uverifier);
if (is_null($verifier) || ($uverifier!==false)){
$key = $this->gen_token();
$sec = $this->gen_token();
$r = q("INSERT INTO tokens (id, secret, client_id, scope, expires, uid) VALUES ('%s','%s','%s','%s', UNIX_TIMESTAMP()+%d, %d)",
dbesc($key),
dbesc($sec),
dbesc($consumer->key),
'access',
intval(ACCESS_TOKEN_DURATION),
intval($uverifier));
if ($r)
$ret = new OAuthToken($key,$sec);
}
dba::delete('tokens', array('id' => $token->key));
if (!is_null($ret) && $uverifier!==false){
Config::delete("oauth", $verifier);
/* $apps = PConfig::get($uverifier, "oauth", "apps");
if ($apps===false) $apps=array();
$apps[] = $consumer->key;
PConfig::set($uverifier, "oauth", "apps", $apps);*/
}
return $ret;
}
}
class FKOAuth1 extends OAuthServer {
function __construct() {
parent::__construct(new FKOAuthDataStore());
$this->add_signature_method(new OAuthSignatureMethod_PLAINTEXT());
$this->add_signature_method(new OAuthSignatureMethod_HMAC_SHA1());
}
function loginUser($uid){
logger("FKOAuth1::loginUser $uid");
$a = get_app();
$r = q("SELECT * FROM `user` WHERE uid=%d AND `blocked` = 0 AND `account_expired` = 0 AND `account_removed` = 0 AND `verified` = 1 LIMIT 1",
intval($uid)
);
if (DBM::is_result($r)){
$record = $r[0];
} else {
logger('FKOAuth1::loginUser failure: ' . print_r($_SERVER,true), LOGGER_DEBUG);
header('HTTP/1.0 401 Unauthorized');
die('This api requires login');
}
$_SESSION['uid'] = $record['uid'];
$_SESSION['theme'] = $record['theme'];
$_SESSION['mobile-theme'] = PConfig::get($record['uid'], 'system', 'mobile_theme');
$_SESSION['authenticated'] = 1;
$_SESSION['page_flags'] = $record['page-flags'];
$_SESSION['my_url'] = System::baseUrl() . '/profile/' . $record['nickname'];
$_SESSION['addr'] = $_SERVER['REMOTE_ADDR'];
$_SESSION["allow_api"] = true;
//notice( t("Welcome back ") . $record['username'] . EOL);
$a->user = $record;
if (strlen($a->user['timezone'])) {
date_default_timezone_set($a->user['timezone']);
$a->timezone = $a->user['timezone'];
}
$r = q("SELECT * FROM `contact` WHERE `uid` = %s AND `self` = 1 LIMIT 1",
intval($_SESSION['uid']));
if (DBM::is_result($r)) {
$a->contact = $r[0];
$a->cid = $r[0]['id'];
$_SESSION['cid'] = $a->cid;
}
q("UPDATE `user` SET `login_date` = '%s' WHERE `uid` = %d",
dbesc(datetime_convert()),
intval($_SESSION['uid'])
);
call_hooks('logged_in', $a->user);
}
}

0
include/oembed.php Executable file → Normal file
View file

View file

@ -120,48 +120,90 @@ function load_translation_table($lang) {
}} }}
// translate string if translation exists /**
* @brief Return the localized version of the provided string with optional string interpolation
if (! function_exists('t')) { *
function t($s) { * This function takes a english string as parameter, and if a localized version
* exists for the current language, substitutes it before performing an eventual
* string interpolation (sprintf) with additional optional arguments.
*
* Usages:
* - t('This is an example')
* - t('URL %s returned no result', $url)
* - t('Current version: %s, new version: %s', $current_version, $new_version)
*
* @param string $s
* @return string
*/
function t($s)
{
$a = get_app(); $a = get_app();
if (x($a->strings,$s)) { if (x($a->strings, $s)) {
$t = $a->strings[$s]; $t = $a->strings[$s];
return is_array($t)?$t[0]:$t; $s = is_array($t) ? $t[0] : $t;
}
if (func_num_args() > 1) {
$args = array_slice(func_get_args(), 1);
$s = @vsprintf($s, $args);
} }
return $s;
}}
if (! function_exists('tt')){ return $s;
function tt($singular, $plural, $count){ }
/**
* @brief Return the localized version of a singular/plural string with optional string interpolation
*
* This function takes two english strings as parameters, singular and plural, as
* well as a count. If a localized version exists for the current language, they
* are used instead. Discrimination between singular and plural is done using the
* localized function if any or the default one. Finally, a string interpolation
* is performed using the count as parameter.
*
* Usages:
* - tt('Like', 'Likes', $count)
* - tt("%s user deleted", "%s users deleted", count($users))
*
* @global type $lang
* @param string $singular
* @param string $plural
* @param int $count
* @return string
*/
function tt($singular, $plural, $count)
{
global $lang; global $lang;
$a = get_app(); $a = get_app();
if (x($a->strings,$singular)) { if (x($a->strings, $singular)) {
$t = $a->strings[$singular]; $t = $a->strings[$singular];
$f = 'string_plural_select_' . str_replace('-','_',$lang); if (is_array($t)) {
if (! function_exists($f)) $plural_function = 'string_plural_select_' . str_replace('-', '_', $lang);
$f = 'string_plural_select_default'; if (function_exists($plural_function)) {
$k = $f($count); $plural_function = 'string_plural_select_default';
return is_array($t)?$t[$k]:$t; }
$i = $plural_function($count);
$s = $t[$i];
} else {
$s = $t;
}
} elseif (string_plural_select_default($count)) {
$s = $plural;
} else {
$s = $singular;
} }
if ($count!=1){ $s = @sprintf($s, $count);
return $plural;
} else { return $s;
return $singular; }
}
}}
// provide a fallback which will not collide with // provide a fallback which will not collide with
// a function defined in any language file // a function defined in any language file
function string_plural_select_default($n)
if (! function_exists('string_plural_select_default')) { {
function string_plural_select_default($n) { return $n != 1;
return ($n != 1); }
}}

View file

@ -1,40 +0,0 @@
<?php
class pidfile {
private $_file;
private $_running;
public function __construct($dir, $name) {
$this->_file = "$dir/$name.pid";
if (file_exists($this->_file)) {
$pid = trim(@file_get_contents($this->_file));
if (($pid != "") && posix_kill($pid, 0)) {
$this->_running = true;
}
}
if (! $this->_running) {
$pid = getmypid();
file_put_contents($this->_file, $pid);
}
}
public function __destruct() {
if ((! $this->_running) && file_exists($this->_file)) {
@unlink($this->_file);
}
}
public function is_already_running() {
return $this->_running;
}
public function running_time() {
return(time() - @filectime($this->_file));
}
public function kill() {
if (file_exists($this->_file))
return(posix_kill(file_get_contents($this->_file), SIGTERM));
}
}

View file

@ -1,185 +0,0 @@
<?php
/**
* @file include/salmon.php
*/
use Friendica\Network\Probe;
use Friendica\Util\XML;
require_once 'include/crypto.php';
function get_salmon_key($uri, $keyhash)
{
$ret = array();
logger('Fetching salmon key for '.$uri);
$arr = Probe::lrdd($uri);
if (is_array($arr)) {
foreach ($arr as $a) {
if ($a['@attributes']['rel'] === 'magic-public-key') {
$ret[] = $a['@attributes']['href'];
}
}
} else {
return '';
}
// We have found at least one key URL
// If it's inline, parse it - otherwise get the key
if (count($ret) > 0) {
for ($x = 0; $x < count($ret); $x ++) {
if (substr($ret[$x], 0, 5) === 'data:') {
if (strstr($ret[$x], ',')) {
$ret[$x] = substr($ret[$x], strpos($ret[$x], ',') + 1);
} else {
$ret[$x] = substr($ret[$x], 5);
}
} elseif (normalise_link($ret[$x]) == 'http://') {
$ret[$x] = fetch_url($ret[$x]);
}
}
}
logger('Key located: ' . print_r($ret, true));
if (count($ret) == 1) {
// We only found one one key so we don't care if the hash matches.
// If it's the wrong key we'll find out soon enough because
// message verification will fail. This also covers some older
// software which don't supply a keyhash. As long as they only
// have one key we'll be right.
return $ret[0];
} else {
foreach ($ret as $a) {
$hash = base64url_encode(hash('sha256', $a));
if ($hash == $keyhash) {
return $a;
}
}
}
return '';
}
function slapper($owner, $url, $slap)
{
// does contact have a salmon endpoint?
if (! strlen($url)) {
return;
}
if (! $owner['sprvkey']) {
logger(sprintf("user '%s' (%d) does not have a salmon private key. Send failed.",
$owner['username'], $owner['uid']));
return;
}
logger('slapper called for '.$url.'. Data: ' . $slap);
// create a magic envelope
$data = base64url_encode($slap);
$data_type = 'application/atom+xml';
$encoding = 'base64url';
$algorithm = 'RSA-SHA256';
$keyhash = base64url_encode(hash('sha256', salmon_key($owner['spubkey'])), true);
$precomputed = '.' . base64url_encode($data_type) . '.' . base64url_encode($encoding) . '.' . base64url_encode($algorithm);
// GNU Social format
$signature = base64url_encode(rsa_sign($data . $precomputed, $owner['sprvkey']));
// Compliant format
$signature2 = base64url_encode(rsa_sign(str_replace('=', '', $data . $precomputed), $owner['sprvkey']));
// Old Status.net format
$signature3 = base64url_encode(rsa_sign($data, $owner['sprvkey']));
// At first try the non compliant method that works for GNU Social
$xmldata = array("me:env" => array("me:data" => $data,
"@attributes" => array("type" => $data_type),
"me:encoding" => $encoding,
"me:alg" => $algorithm,
"me:sig" => $signature,
"@attributes2" => array("key_id" => $keyhash)));
$namespaces = array("me" => "http://salmon-protocol.org/ns/magic-env");
$salmon = XML::fromArray($xmldata, $xml, false, $namespaces);
// slap them
post_url($url, $salmon, array(
'Content-type: application/magic-envelope+xml',
'Content-length: ' . strlen($salmon)
));
$a = get_app();
$return_code = $a->get_curl_code();
// check for success, e.g. 2xx
if ($return_code > 299) {
logger('GNU Social salmon failed. Falling back to compliant mode');
// Now try the compliant mode that normally isn't used for GNU Social
$xmldata = array("me:env" => array("me:data" => $data,
"@attributes" => array("type" => $data_type),
"me:encoding" => $encoding,
"me:alg" => $algorithm,
"me:sig" => $signature2,
"@attributes2" => array("key_id" => $keyhash)));
$namespaces = array("me" => "http://salmon-protocol.org/ns/magic-env");
$salmon = XML::fromArray($xmldata, $xml, false, $namespaces);
// slap them
post_url($url, $salmon, array(
'Content-type: application/magic-envelope+xml',
'Content-length: ' . strlen($salmon)
));
$return_code = $a->get_curl_code();
}
if ($return_code > 299) {
logger('compliant salmon failed. Falling back to old status.net');
// Last try. This will most likely fail as well.
$xmldata = array("me:env" => array("me:data" => $data,
"@attributes" => array("type" => $data_type),
"me:encoding" => $encoding,
"me:alg" => $algorithm,
"me:sig" => $signature3,
"@attributes2" => array("key_id" => $keyhash)));
$namespaces = array("me" => "http://salmon-protocol.org/ns/magic-env");
$salmon = XML::fromArray($xmldata, $xml, false, $namespaces);
// slap them
post_url($url, $salmon, array(
'Content-type: application/magic-envelope+xml',
'Content-length: ' . strlen($salmon))
);
$return_code = $a->get_curl_code();
}
logger('slapper for '.$url.' returned ' . $return_code);
if (! $return_code) {
return -1;
}
if (($return_code == 503) && (stristr($a->get_curl_headers(), 'retry-after'))) {
return -1;
}
return ((($return_code >= 200) && ($return_code < 300)) ? 0 : 1);
}

View file

@ -1,6 +1,9 @@
<?php <?php
/**
* @file include/tags.php
*/
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Object\Contact; use Friendica\Object\Contact;
@ -302,7 +305,7 @@ function tagcloud_wall_widget($limit = 50) {
return ""; return "";
} }
if(feature_enabled($a->profile['profile_uid'], 'tagadelic')) { if(Feature::isEnabled($a->profile['profile_uid'], 'tagadelic')) {
$owner_id = Contact::getIdForURL($a->profile['url']); $owner_id = Contact::getIdForURL($a->profile['url']);
if(!$owner_id) { if(!$owner_id) {

View file

@ -1,6 +1,9 @@
<?php <?php
/**
* @file include/text.php
*/
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Content\Smilies; use Friendica\Content\Smilies;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
@ -1046,7 +1049,7 @@ function search($s, $id = 'search-box', $url = 'search', $save = false, $aside =
'$action_url' => $url, '$action_url' => $url,
'$search_label' => t('Search'), '$search_label' => t('Search'),
'$save_label' => t('Save'), '$save_label' => t('Save'),
'$savedsearch' => feature_enabled(local_user(),'savedsearch'), '$savedsearch' => Feature::isEnabled(local_user(),'savedsearch'),
'$search_hint' => t('@name, !forum, #tags, content'), '$search_hint' => t('@name, !forum, #tags, content'),
); );

View file

@ -198,12 +198,6 @@ function import_account(App $a, $file) {
case NETWORK_DIASPORA: case NETWORK_DIASPORA:
// send relocate message (below) // send relocate message (below)
break; break;
case NETWORK_ZOT:
/// @TODO handle zot network
break;
case NETWORK_MAIL2:
/// @TODO ?
break;
case NETWORK_FEED: case NETWORK_FEED:
case NETWORK_MAIL: case NETWORK_MAIL:
// Nothing to do // Nothing to do

View file

@ -1,453 +0,0 @@
<?php
/**
* @file include/user.php
*/
use Friendica\Core\Config;
use Friendica\Core\System;
use Friendica\Database\DBM;
use Friendica\Object\Photo;
require_once 'include/network.php';
require_once 'include/plugin.php';
require_once 'include/text.php';
require_once 'include/pgettext.php';
require_once 'include/datetime.php';
require_once 'include/enotify.php';
function create_user($arr) {
// Required: { username, nickname, email } or { openid_url }
$a = get_app();
$result = array('success' => false, 'user' => null, 'password' => '', 'message' => '');
$using_invites = Config::get('system','invitation_only');
$num_invites = Config::get('system','number_invites');
$invite_id = ((x($arr,'invite_id')) ? notags(trim($arr['invite_id'])) : '');
$username = ((x($arr,'username')) ? notags(trim($arr['username'])) : '');
$nickname = ((x($arr,'nickname')) ? notags(trim($arr['nickname'])) : '');
$email = ((x($arr,'email')) ? notags(trim($arr['email'])) : '');
$openid_url = ((x($arr,'openid_url')) ? notags(trim($arr['openid_url'])) : '');
$photo = ((x($arr,'photo')) ? notags(trim($arr['photo'])) : '');
$password = ((x($arr,'password')) ? trim($arr['password']) : '');
$password1 = ((x($arr,'password1')) ? trim($arr['password1']) : '');
$confirm = ((x($arr,'confirm')) ? trim($arr['confirm']) : '');
$blocked = ((x($arr,'blocked')) ? intval($arr['blocked']) : 0);
$verified = ((x($arr,'verified')) ? intval($arr['verified']) : 0);
$publish = ((x($arr,'profile_publish_reg') && intval($arr['profile_publish_reg'])) ? 1 : 0);
$netpublish = ((strlen(Config::get('system','directory'))) ? $publish : 0);
if ($password1 != $confirm) {
$result['message'] .= t('Passwords do not match. Password unchanged.') . EOL;
return $result;
} elseif ($password1 != "")
$password = $password1;
$tmp_str = $openid_url;
if($using_invites) {
if(! $invite_id) {
$result['message'] .= t('An invitation is required.') . EOL;
return $result;
}
$r = q("SELECT * FROM `register` WHERE `hash` = '%s' LIMIT 1", dbesc($invite_id));
if(! results($r)) {
$result['message'] .= t('Invitation could not be verified.') . EOL;
return $result;
}
}
if((! x($username)) || (! x($email)) || (! x($nickname))) {
if($openid_url) {
if(! validate_url($tmp_str)) {
$result['message'] .= t('Invalid OpenID url') . EOL;
return $result;
}
$_SESSION['register'] = 1;
$_SESSION['openid'] = $openid_url;
require_once('library/openid.php');
$openid = new LightOpenID;
$openid->identity = $openid_url;
$openid->returnUrl = System::baseUrl() . '/openid';
$openid->required = array('namePerson/friendly', 'contact/email', 'namePerson');
$openid->optional = array('namePerson/first','media/image/aspect11','media/image/default');
try {
$authurl = $openid->authUrl();
} catch (Exception $e){
$result['message'] .= t("We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID."). EOL . EOL . t("The error message was:") . $e->getMessage() . EOL;
return $result;
}
goaway($authurl);
// NOTREACHED
}
notice( t('Please enter the required information.') . EOL );
return;
}
if(! validate_url($tmp_str))
$openid_url = '';
$err = '';
// collapse multiple spaces in name
$username = preg_replace('/ +/',' ',$username);
if(mb_strlen($username) > 48)
$result['message'] .= t('Please use a shorter name.') . EOL;
if(mb_strlen($username) < 3)
$result['message'] .= t('Name too short.') . EOL;
// So now we are just looking for a space in the full name.
$loose_reg = Config::get('system','no_regfullname');
if(! $loose_reg) {
$username = mb_convert_case($username,MB_CASE_TITLE,'UTF-8');
if(! strpos($username,' '))
$result['message'] .= t("That doesn't appear to be your full \x28First Last\x29 name.") . EOL;
}
if(! allowed_email($email))
$result['message'] .= t('Your email domain is not among those allowed on this site.') . EOL;
if((! valid_email($email)) || (! validate_email($email)))
$result['message'] .= t('Not a valid email address.') . EOL;
// Disallow somebody creating an account using openid that uses the admin email address,
// since openid bypasses email verification. We'll allow it if there is not yet an admin account.
$adminlist = explode(",", str_replace(" ", "", strtolower($a->config['admin_email'])));
//if((x($a->config,'admin_email')) && (strcasecmp($email,$a->config['admin_email']) == 0) && strlen($openid_url)) {
if((x($a->config,'admin_email')) && in_array(strtolower($email), $adminlist) && strlen($openid_url)) {
$r = q("SELECT * FROM `user` WHERE `email` = '%s' LIMIT 1",
dbesc($email)
);
if (DBM::is_result($r))
$result['message'] .= t('Cannot use that email.') . EOL;
}
$nickname = $arr['nickname'] = strtolower($nickname);
if(! preg_match("/^[a-z0-9][a-z0-9\_]*$/",$nickname))
$result['message'] .= t('Your "nickname" can only contain "a-z", "0-9" and "_".') . EOL;
$r = q("SELECT `uid` FROM `user`
WHERE `nickname` = '%s' LIMIT 1",
dbesc($nickname)
);
if (DBM::is_result($r))
$result['message'] .= t('Nickname is already registered. Please choose another.') . EOL;
// Check deleted accounts that had this nickname. Doesn't matter to us,
// but could be a security issue for federated platforms.
$r = q("SELECT * FROM `userd`
WHERE `username` = '%s' LIMIT 1",
dbesc($nickname)
);
if (DBM::is_result($r))
$result['message'] .= t('Nickname was once registered here and may not be re-used. Please choose another.') . EOL;
if(strlen($result['message'])) {
return $result;
}
$new_password = ((strlen($password)) ? $password : autoname(6) . mt_rand(100,9999));
$new_password_encoded = hash('whirlpool',$new_password);
$result['password'] = $new_password;
require_once('include/crypto.php');
$keys = new_keypair(4096);
if($keys === false) {
$result['message'] .= t('SERIOUS ERROR: Generation of security keys failed.') . EOL;
return $result;
}
$prvkey = $keys['prvkey'];
$pubkey = $keys['pubkey'];
// Create another keypair for signing/verifying salmon protocol messages.
$sres = new_keypair(512);
$sprvkey = $sres['prvkey'];
$spubkey = $sres['pubkey'];
$r = q("INSERT INTO `user` (`guid`, `username`, `password`, `email`, `openid`, `nickname`,
`pubkey`, `prvkey`, `spubkey`, `sprvkey`, `register_date`, `verified`, `blocked`, `timezone`, `default-location`)
VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, 'UTC', '')",
dbesc(generate_user_guid()),
dbesc($username),
dbesc($new_password_encoded),
dbesc($email),
dbesc($openid_url),
dbesc($nickname),
dbesc($pubkey),
dbesc($prvkey),
dbesc($spubkey),
dbesc($sprvkey),
dbesc(datetime_convert()),
intval($verified),
intval($blocked)
);
if ($r) {
$r = q("SELECT * FROM `user`
WHERE `username` = '%s' AND `password` = '%s' LIMIT 1",
dbesc($username),
dbesc($new_password_encoded)
);
if (DBM::is_result($r)) {
$u = $r[0];
$newuid = intval($r[0]['uid']);
}
}
else {
$result['message'] .= t('An error occurred during registration. Please try again.') . EOL ;
return $result;
}
/**
* if somebody clicked submit twice very quickly, they could end up with two accounts
* due to race condition. Remove this one.
*/
$r = q("SELECT `uid` FROM `user`
WHERE `nickname` = '%s' ",
dbesc($nickname)
);
if ((DBM::is_result($r)) && (count($r) > 1) && $newuid) {
$result['message'] .= t('Nickname is already registered. Please choose another.') . EOL;
dba::delete('user', array('uid' => $newuid));
return $result;
}
if(x($newuid) !== false) {
$r = q("INSERT INTO `profile` ( `uid`, `profile-name`, `is-default`, `name`, `photo`, `thumb`, `publish`, `net-publish` )
VALUES ( %d, '%s', %d, '%s', '%s', '%s', %d, %d ) ",
intval($newuid),
t('default'),
1,
dbesc($username),
dbesc(System::baseUrl() . "/photo/profile/{$newuid}.jpg"),
dbesc(System::baseUrl() . "/photo/avatar/{$newuid}.jpg"),
intval($publish),
intval($netpublish)
);
if ($r === false) {
$result['message'] .= t('An error occurred creating your default profile. Please try again.') . EOL;
// Start fresh next time.
dba::delete('user', array('uid' => $newuid));
return $result;
}
// Create the self contact
user_create_self_contact($newuid);
// Create a group with no members. This allows somebody to use it
// right away as a default group for new contacts.
require_once('include/group.php');
group_add($newuid, t('Friends'));
$r = q("SELECT `id` FROM `group` WHERE `uid` = %d AND `name` = '%s'",
intval($newuid),
dbesc(t('Friends'))
);
if (DBM::is_result($r)) {
$def_gid = $r[0]['id'];
q("UPDATE `user` SET `def_gid` = %d WHERE `uid` = %d",
intval($r[0]['id']),
intval($newuid)
);
}
if(Config::get('system', 'newuser_private') && $def_gid) {
q("UPDATE `user` SET `allow_gid` = '%s' WHERE `uid` = %d",
dbesc("<" . $def_gid . ">"),
intval($newuid)
);
}
}
// if we have no OpenID photo try to look up an avatar
if(! strlen($photo))
$photo = avatar_img($email);
// unless there is no avatar-plugin loaded
if (strlen($photo)) {
$photo_failure = false;
$filename = basename($photo);
$img_str = fetch_url($photo, true);
// guess mimetype from headers or filename
$type = Photo::guessImageType($photo, true);
$img = new Photo($img_str, $type);
if ($img->isValid()) {
$img->scaleImageSquare(175);
$hash = photo_new_resource();
$r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 4);
if ($r === false) {
$photo_failure = true;
}
$img->scaleImage(80);
$r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 5 );
if ($r === false) {
$photo_failure = true;
}
$img->scaleImage(48);
$r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 6 );
if ($r === false) {
$photo_failure = true;
}
if (! $photo_failure) {
q("UPDATE `photo` SET `profile` = 1 WHERE `resource-id` = '%s' ",
dbesc($hash)
);
}
}
}
call_hooks('register_account', $newuid);
$result['success'] = true;
$result['user'] = $u;
return $result;
}
/**
* @brief create the "self" contact from data from the user table
*
* @param integer $uid
*/
function user_create_self_contact($uid) {
// Only create the entry if it doesn't exist yet
$r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `self`", intval($uid));
if (DBM::is_result($r)) {
return;
}
$r = q("SELECT `uid`, `username`, `nickname` FROM `user` WHERE `uid` = %d", intval($uid));
if (!DBM::is_result($r)) {
return;
}
$user = $r[0];
q("INSERT INTO `contact` (`uid`, `created`, `self`, `name`, `nick`, `photo`, `thumb`, `micro`, `blocked`, `pending`, `url`, `nurl`,
`addr`, `request`, `notify`, `poll`, `confirm`, `poco`, `name-date`, `uri-date`, `avatar-date`, `closeness`)
VALUES (%d, '%s', 1, '%s', '%s', '%s', '%s', '%s', 0, 0, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', 0)",
intval($user['uid']),
datetime_convert(),
dbesc($user['username']),
dbesc($user['nickname']),
dbesc(System::baseUrl()."/photo/profile/".$user['uid'].".jpg"),
dbesc(System::baseUrl()."/photo/avatar/".$user['uid'].".jpg"),
dbesc(System::baseUrl()."/photo/micro/".$user['uid'].".jpg"),
dbesc(System::baseUrl()."/profile/".$user['nickname']),
dbesc(normalise_link(System::baseUrl()."/profile/".$user['nickname'])),
dbesc($user['nickname'].'@'.substr(System::baseUrl(), strpos(System::baseUrl(),'://') + 3)),
dbesc(System::baseUrl()."/dfrn_request/".$user['nickname']),
dbesc(System::baseUrl()."/dfrn_notify/".$user['nickname']),
dbesc(System::baseUrl()."/dfrn_poll/".$user['nickname']),
dbesc(System::baseUrl()."/dfrn_confirm/".$user['nickname']),
dbesc(System::baseUrl()."/poco/".$user['nickname']),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
dbesc(datetime_convert())
);
}
/**
* @brief send registration confiŕmation with the intormation that reg is pending
*
* @param string $email
* @param string $sitename
* @param string $username
* @return NULL|boolean from notification() and email() inherited
*/
function send_register_pending_eml($email, $sitename, $username) {
$body = deindent(t('
Dear %1$s,
Thank you for registering at %2$s. Your account is pending for approval by the administrator.
'));
$body = sprintf($body, $username, $sitename);
return notification(array(
'type' => SYSTEM_EMAIL,
'to_email' => $email,
'subject'=> sprintf( t('Registration at %s'), $sitename),
'body' => $body));
}
/*
* send registration confirmation.
* It's here as a function because the mail is sent
* from different parts
*/
function send_register_open_eml($email, $sitename, $siteurl, $username, $password){
$preamble = deindent(t('
Dear %1$s,
Thank you for registering at %2$s. Your account has been created.
'));
$body = deindent(t('
The login details are as follows:
Site Location: %3$s
Login Name: %1$s
Password: %5$s
You may change your password from your account "Settings" page after logging
in.
Please take a few moments to review the other account settings on that page.
You may also wish to add some basic information to your default profile
(on the "Profiles" page) so that other people can easily find you.
We recommend setting your full name, adding a profile photo,
adding some profile "keywords" (very useful in making new friends) - and
perhaps what country you live in; if you do not wish to be more specific
than that.
We fully respect your right to privacy, and none of these items are necessary.
If you are new and do not know anybody here, they may help
you to make some new and interesting friends.
Thank you and welcome to %2$s.'));
$preamble = sprintf($preamble, $username, $sitename);
$body = sprintf($body, $email, $sitename, $siteurl, $username, $password);
return notification(array(
'type' => SYSTEM_EMAIL,
'to_email' => $email,
'subject'=> sprintf( t('Registration details for %s'), $sitename),
'preamble'=> $preamble,
'body' => $body));
}

File diff suppressed because it is too large Load diff

View file

@ -5,8 +5,8 @@
* This calendar is for profile visitors and contains only the events * This calendar is for profile visitors and contains only the events
* of the profile owner * of the profile owner
*/ */
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
use Friendica\Core\System; use Friendica\Core\System;
@ -301,7 +301,7 @@ function cal_content(App $a) {
// Test permissions // Test permissions
// Respect the export feature setting for all other /cal pages if it's not the own profile // Respect the export feature setting for all other /cal pages if it's not the own profile
if( ((local_user() !== intval($owner_uid))) && ! feature_enabled($owner_uid, "export_calendar")) { if( ((local_user() !== intval($owner_uid))) && ! Feature::isEnabled($owner_uid, "export_calendar")) {
notice( t('Permission denied.') . EOL); notice( t('Permission denied.') . EOL);
goaway('cal/' . $nick); goaway('cal/' . $nick);
} }

View file

@ -559,7 +559,7 @@ function contacts_content(App $a) {
} }
$lblsuggest = (($contact['network'] === NETWORK_DFRN) ? t('Suggest friends') : ''); $lblsuggest = (($contact['network'] === NETWORK_DFRN) ? t('Suggest friends') : '');
$poll_enabled = in_array($contact['network'], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_FEED, NETWORK_MAIL, NETWORK_MAIL2)); $poll_enabled = in_array($contact['network'], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_FEED, NETWORK_MAIL));
$nettype = sprintf( t('Network type: %s'),network_to_name($contact['network'], $contact["url"])); $nettype = sprintf( t('Network type: %s'),network_to_name($contact['network'], $contact["url"]));
@ -586,7 +586,7 @@ function contacts_content(App $a) {
'3' => t('Fetch keywords'), '3' => t('Fetch keywords'),
'2' => t('Fetch information and keywords'))); '2' => t('Fetch information and keywords')));
} }
if (in_array($contact['network'], array(NETWORK_FEED, NETWORK_MAIL, NETWORK_MAIL2))) if (in_array($contact['network'], array(NETWORK_FEED, NETWORK_MAIL)))
$poll_interval = contact_poll_interval($contact['priority'],(! $poll_enabled)); $poll_interval = contact_poll_interval($contact['priority'],(! $poll_enabled));
if ($contact['network'] == NETWORK_DFRN) if ($contact['network'] == NETWORK_DFRN)
@ -994,7 +994,7 @@ function _contact_detail_for_template($rr){
*/ */
function contact_actions($contact) { function contact_actions($contact) {
$poll_enabled = in_array($contact['network'], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_FEED, NETWORK_MAIL, NETWORK_MAIL2)); $poll_enabled = in_array($contact['network'], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_FEED, NETWORK_MAIL));
$contact_action = array(); $contact_action = array();
// Provide friend suggestion only for Friendica contacts // Provide friend suggestion only for Friendica contacts

View file

@ -292,15 +292,12 @@ function dfrn_request_post(App $a) {
* *
* Cleanup old introductions that remain blocked. * Cleanup old introductions that remain blocked.
* Also remove the contact record, but only if there is no existing relationship * Also remove the contact record, but only if there is no existing relationship
* Do not remove email contacts as these may be awaiting email verification
*/ */
$r = q("SELECT `intro`.*, `intro`.`id` AS `iid`, `contact`.`id` AS `cid`, `contact`.`rel` $r = q("SELECT `intro`.*, `intro`.`id` AS `iid`, `contact`.`id` AS `cid`, `contact`.`rel`
FROM `intro` LEFT JOIN `contact` on `intro`.`contact-id` = `contact`.`id` FROM `intro` LEFT JOIN `contact` on `intro`.`contact-id` = `contact`.`id`
WHERE `intro`.`blocked` = 1 AND `contact`.`self` = 0 WHERE `intro`.`blocked` = 1 AND `contact`.`self` = 0
AND `contact`.`network` != '%s' AND `intro`.`datetime` < UTC_TIMESTAMP() - INTERVAL 30 MINUTE "
AND `intro`.`datetime` < UTC_TIMESTAMP() - INTERVAL 30 MINUTE ",
dbesc(NETWORK_MAIL2)
); );
if (DBM::is_result($r)) { if (DBM::is_result($r)) {
foreach ($r as $rr) { foreach ($r as $rr) {
@ -315,32 +312,6 @@ function dfrn_request_post(App $a) {
} }
} }
/*
*
* Cleanup any old email intros - which will have a greater lifetime
*/
$r = q("SELECT `intro`.*, `intro`.`id` AS `iid`, `contact`.`id` AS `cid`, `contact`.`rel`
FROM `intro` LEFT JOIN `contact` on `intro`.`contact-id` = `contact`.`id`
WHERE `intro`.`blocked` = 1 AND `contact`.`self` = 0
AND `contact`.`network` = '%s'
AND `intro`.`datetime` < UTC_TIMESTAMP() - INTERVAL 3 DAY ",
dbesc(NETWORK_MAIL2)
);
if (DBM::is_result($r)) {
foreach ($r as $rr) {
if(! $rr['rel']) {
q("DELETE FROM `contact` WHERE `id` = %d AND NOT `self`",
intval($rr['cid'])
);
}
q("DELETE FROM `intro` WHERE `id` = %d",
intval($rr['iid'])
);
}
}
$email_follow = (x($_POST,'email_follow') ? intval($_POST['email_follow']) : 0);
$real_name = (x($_POST,'realname') ? notags(trim($_POST['realname'])) : ''); $real_name = (x($_POST,'realname') ? notags(trim($_POST['realname'])) : '');
$url = trim($_POST['dfrn_url']); $url = trim($_POST['dfrn_url']);
@ -351,125 +322,25 @@ function dfrn_request_post(App $a) {
$hcard = ''; $hcard = '';
if($email_follow) { // Detect the network
$data = Probe::uri($url);
$network = $data["network"];
if(! validate_email($url)) { // Canonicalise email-style profile locator
notice( t('Invalid email address.') . EOL); $url = Probe::webfingerDfrn($url,$hcard);
return;
if (substr($url,0,5) === 'stat:') {
// Every time we detect the remote subscription we define this as OStatus.
// We do this even if it is not OStatus.
// we only need to pass this through another section of the code.
if ($network != NETWORK_DIASPORA) {
$network = NETWORK_OSTATUS;
} }
$addr = $url; $url = substr($url,5);
$name = ($realname) ? $realname : $addr;
$nick = substr($addr,0,strpos($addr,'@'));
$url = 'http://' . substr($addr,strpos($addr,'@') + 1);
$nurl = normalise_url($host);
$poll = 'email ' . random_string();
$notify = 'smtp ' . random_string();
$network = NETWORK_MAIL2;
$rel = CONTACT_IS_FOLLOWER;
$mail_disabled = ((function_exists('imap_open') && (! Config::get('system','imap_disabled'))) ? 0 : 1);
if(Config::get('system','dfrn_only'))
$mail_disabled = 1;
if(! $mail_disabled) {
$failed = false;
$r = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1",
intval($uid)
);
if (! DBM::is_result($r)) {
notice( t('This account has not been configured for email. Request failed.') . EOL);
return;
}
}
$r = q("insert into contact ( uid, created, addr, name, nick, url, nurl, poll, notify, blocked, pending, network, rel )
values( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d ) ",
intval($uid),
dbesc(datetime_convert()),
dbesc($addr),
dbesc($name),
dbesc($nick),
dbesc($url),
dbesc($nurl),
dbesc($poll),
dbesc($notify),
intval($blocked),
intval($pending),
dbesc($network),
intval($rel)
);
$r = q("SELECT `id`, `network` FROM `contact` WHERE `poll` = '%s' AND `uid` = %d LIMIT 1",
dbesc($poll),
intval($uid)
);
if (DBM::is_result($r)) {
$contact_id = $r[0]['id'];
$def_gid = get_default_group($uid, $r[0]["network"]);
if (intval($def_gid))
group_add_member($uid, '', $contact_id, $def_gid);
$photo = avatar_img($addr);
$r = q("UPDATE `contact` SET
`photo` = '%s',
`thumb` = '%s',
`micro` = '%s',
`name-date` = '%s',
`uri-date` = '%s',
`avatar-date` = '%s',
`hidden` = 0,
WHERE `id` = %d
",
dbesc($photos[0]),
dbesc($photos[1]),
dbesc($photos[2]),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($contact_id)
);
}
// contact is created. Now create an introduction
$hash = random_string();
$r = q("INSERT INTO `intro` ( `uid`, `contact-id`, knowyou, note, hash, datetime, blocked )
VALUES( %d , %d, %d, '%s', '%s', '%s', %d ) ",
intval($uid),
intval($contact_id),
((x($_POST,'knowyou') && ($_POST['knowyou'] == 1)) ? 1 : 0),
dbesc(notags(trim($_POST['dfrn-request-message']))),
dbesc($hash),
dbesc(datetime_convert()),
1
);
// Next send an email verify form to the requestor.
} else { } else {
// Detect the network $network = NETWORK_DFRN;
$data = Probe::uri($url);
$network = $data["network"];
// Canonicalise email-style profile locator
$url = Probe::webfingerDfrn($url,$hcard);
if (substr($url,0,5) === 'stat:') {
// Every time we detect the remote subscription we define this as OStatus.
// We do this even if it is not OStatus.
// we only need to pass this through another section of the code.
if ($network != NETWORK_DIASPORA)
$network = NETWORK_OSTATUS;
$url = substr($url,5);
} else
$network = NETWORK_DFRN;
} }
logger('dfrn_request: url: ' . $url . ',network=' . $network, LOGGER_DEBUG); logger('dfrn_request: url: ' . $url . ',network=' . $network, LOGGER_DEBUG);
@ -849,27 +720,6 @@ function dfrn_request_content(App $a) {
$page_desc = t("Please enter your 'Identity Address' from one of the following supported communications networks:"); $page_desc = t("Please enter your 'Identity Address' from one of the following supported communications networks:");
// see if we are allowed to have NETWORK_MAIL2 contacts
$mail_disabled = ((function_exists('imap_open') && (! Config::get('system','imap_disabled'))) ? 0 : 1);
if (Config::get('system','dfrn_only')) {
$mail_disabled = 1;
}
if (! $mail_disabled) {
$r = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1",
intval($a->profile['uid'])
);
if (! DBM::is_result($r)) {
$mail_disabled = 1;
}
}
// "coming soon" is disabled for now
//$emailnet = (($mail_disabled) ? '' : t("<strike>Connect as an email follower</strike> \x28Coming soon\x29"));
$emailnet = "";
$invite_desc = sprintf( $invite_desc = sprintf(
t('If you are not yet a member of the free social web, <a href="%s/siteinfo">follow this link to find a public Friendica site and join us today</a>.'), t('If you are not yet a member of the free social web, <a href="%s/siteinfo">follow this link to find a public Friendica site and join us today</a>.'),
get_server() get_server()
@ -877,7 +727,7 @@ function dfrn_request_content(App $a) {
$o = replace_macros($tpl,array( $o = replace_macros($tpl,array(
'$header' => t('Friend/Connection Request'), '$header' => t('Friend/Connection Request'),
'$desc' => t('Examples: jojo@demo.friendica.com, http://demo.friendica.com/profile/jojo, testuser@identi.ca'), '$desc' => t('Examples: jojo@demo.friendica.com, http://demo.friendica.com/profile/jojo, testuser@gnusocial.de'),
'$pls_answer' => t('Please answer the following:'), '$pls_answer' => t('Please answer the following:'),
'$does_know_you' => array('knowyou', sprintf(t('Does %s know you?'),$a->profile['name']), false, '', array(t('No'), t('Yes'))), '$does_know_you' => array('knowyou', sprintf(t('Does %s know you?'),$a->profile['name']), false, '', array(t('No'), t('Yes'))),
/*'$does_know' => sprintf( t('Does %s know you?'),$a->profile['name']), /*'$does_know' => sprintf( t('Does %s know you?'),$a->profile['name']),
@ -886,12 +736,11 @@ function dfrn_request_content(App $a) {
'$add_note' => t('Add a personal note:'), '$add_note' => t('Add a personal note:'),
'$page_desc' => $page_desc, '$page_desc' => $page_desc,
'$friendica' => t('Friendica'), '$friendica' => t('Friendica'),
'$statusnet' => t('StatusNet/Federated Social Web'), '$statusnet' => t('GNU Social (Pleroma, Mastodon)'),
'$diaspora' => t('Diaspora'), '$diaspora' => t('Diaspora (Socialhome, Hubzilla)'),
'$diasnote' => sprintf (t(' - please do not use this form. Instead, enter %s into your Diaspora search bar.'),$target_addr), '$diasnote' => sprintf (t(' - please do not use this form. Instead, enter %s into your Diaspora search bar.'),$target_addr),
'$your_address' => t('Your Identity Address:'), '$your_address' => t('Your Identity Address:'),
'$invite_desc' => $invite_desc, '$invite_desc' => $invite_desc,
'$emailnet' => $emailnet,
'$submit' => t('Submit Request'), '$submit' => t('Submit Request'),
'$cancel' => t('Cancel'), '$cancel' => t('Cancel'),
'$nickname' => $a->argv[1], '$nickname' => $a->argv[1],

View file

@ -1,6 +1,9 @@
<?php <?php
/**
* @file mod/editpost.php
*/
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Database\DBM; use Friendica\Database\DBM;
@ -131,7 +134,7 @@ function editpost_content(App $a) {
'$title' => htmlspecialchars($itm[0]['title']), '$title' => htmlspecialchars($itm[0]['title']),
'$placeholdertitle' => t('Set title'), '$placeholdertitle' => t('Set title'),
'$category' => file_tag_file_to_list($itm[0]['file'], 'category'), '$category' => file_tag_file_to_list($itm[0]['file'], 'category'),
'$placeholdercategory' => (feature_enabled(local_user(),'categories') ? t('Categories (comma-separated list)') : ''), '$placeholdercategory' => (Feature::isEnabled(local_user(),'categories') ? t('Categories (comma-separated list)') : ''),
'$emtitle' => t('Example: bob@example.com, mary@example.com'), '$emtitle' => t('Example: bob@example.com, mary@example.com'),
'$lockstate' => $lockstate, '$lockstate' => $lockstate,
'$acl' => '', // populate_acl((($group) ? $group_acl : $a->user)), '$acl' => '', // populate_acl((($group) ? $group_acl : $a->user)),

View file

@ -18,15 +18,11 @@ function hostxrd_init(App $a) {
Config::set('system','site_pubkey', $res['pubkey']); Config::set('system','site_pubkey', $res['pubkey']);
} }
//$tpl = file_get_contents('view/xrd_host.tpl');
/*echo str_replace(array(
'$zhost','$zroot','$domain','$zot_post','$bigkey'),array($a->get_hostname(),System::baseUrl(),System::baseUrl(),System::baseUrl() . '/post', salmon_key(Config::get('system','site_pubkey'))),$tpl);*/
$tpl = get_markup_template('xrd_host.tpl'); $tpl = get_markup_template('xrd_host.tpl');
echo replace_macros($tpl, array( echo replace_macros($tpl, array(
'$zhost' => $a->get_hostname(), '$zhost' => $a->get_hostname(),
'$zroot' => System::baseUrl(), '$zroot' => System::baseUrl(),
'$domain' => System::baseUrl(), '$domain' => System::baseUrl(),
'$zot_post' => System::baseUrl() . '/post',
'$bigkey' => salmon_key(Config::get('system','site_pubkey')), '$bigkey' => salmon_key(Config::get('system','site_pubkey')),
)); ));
exit(); exit();

2
mod/install.php Executable file → Normal file
View file

@ -318,7 +318,7 @@ function check_php(&$phpath, &$checks) {
$help = ""; $help = "";
if (!$passed) { if (!$passed) {
$help .= t('Could not find a command line version of PHP in the web server PATH.'). EOL; $help .= t('Could not find a command line version of PHP in the web server PATH.'). EOL;
$help .= t("If you don't have a command line version of PHP installed on server, you will not be able to run the background processing. See <a href='https://github.com/friendica/friendica/blob/master/doc/Install.md#set-up-the-worker'>'Setup the worker'</a>") . EOL; $help .= t("If you don't have a command line version of PHP installed on your server, you will not be able to run the background processing. See <a href='https://github.com/friendica/friendica/blob/master/doc/Install.md#set-up-the-worker'>'Setup the worker'</a>") . EOL;
$help .= EOL . EOL; $help .= EOL . EOL;
$tpl = get_markup_template('field_input.tpl'); $tpl = get_markup_template('field_input.tpl');
$help .= replace_macros($tpl, array( $help .= replace_macros($tpl, array(

View file

@ -1,18 +1,15 @@
<?php <?php
/** /**
* module: invite.php * Module: invite.php
* *
* send email invitations to join social network * Send email invitations to join social network
* *
*/ */
use Friendica\App; use Friendica\App;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Protocol\Email;
require_once('include/email.php');
function invite_post(App $a) { function invite_post(App $a) {
@ -78,7 +75,7 @@ function invite_post(App $a) {
$nmessage = $message; $nmessage = $message;
} }
$res = mail($recip, email_header_encode( t('Please join us on Friendica'),'UTF-8'), $res = mail($recip, Email::encodeHeader(t('Please join us on Friendica'),'UTF-8'),
$nmessage, $nmessage,
"From: " . $a->user['email'] . "\n" "From: " . $a->user['email'] . "\n"
. 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n"

View file

@ -1,4 +1,7 @@
<?php <?php
/**
* @file mod/item.php
*/
/* /*
* This is the POST destination for most all locally posted * This is the POST destination for most all locally posted
@ -14,7 +17,6 @@
* Posts that originate externally or do not fall into the above * Posts that originate externally or do not fall into the above
* posting categories go through item_store() instead of this function. * posting categories go through item_store() instead of this function.
*/ */
use Friendica\App; use Friendica\App;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\System; use Friendica\Core\System;
@ -24,11 +26,11 @@ use Friendica\Model\GlobalContact;
use Friendica\Network\Probe; use Friendica\Network\Probe;
use Friendica\Object\Contact; use Friendica\Object\Contact;
use Friendica\Protocol\Diaspora; use Friendica\Protocol\Diaspora;
use Friendica\Protocol\Email;
use Friendica\Util\Emailer; use Friendica\Util\Emailer;
require_once 'include/crypto.php'; require_once 'include/crypto.php';
require_once 'include/enotify.php'; require_once 'include/enotify.php';
require_once 'include/email.php';
require_once 'include/tags.php'; require_once 'include/tags.php';
require_once 'include/files.php'; require_once 'include/files.php';
require_once 'include/threads.php'; require_once 'include/threads.php';
@ -1030,9 +1032,9 @@ function item_post(App $a) {
$disclaimer .= sprintf( t('You may visit them online at %s'), System::baseUrl() . '/profile/' . $a->user['nickname']) . EOL; $disclaimer .= sprintf( t('You may visit them online at %s'), System::baseUrl() . '/profile/' . $a->user['nickname']) . EOL;
$disclaimer .= t('Please contact the sender by replying to this post if you do not wish to receive these messages.') . EOL; $disclaimer .= t('Please contact the sender by replying to this post if you do not wish to receive these messages.') . EOL;
if (!$datarray['title']=='') { if (!$datarray['title']=='') {
$subject = email_header_encode($datarray['title'], 'UTF-8'); $subject = Email::encodeHeader($datarray['title'], 'UTF-8');
} else { } else {
$subject = email_header_encode('[Friendica]' . ' ' . sprintf( t('%s posted an update.'), $a->user['username']), 'UTF-8'); $subject = Email::encodeHeader('[Friendica]' . ' ' . sprintf( t('%s posted an update.'), $a->user['username']), 'UTF-8');
} }
$link = '<a href="' . System::baseUrl() . '/profile/' . $a->user['nickname'] . '"><img src="' . $author['thumb'] . '" alt="' . $a->user['username'] . '" /></a><br /><br />'; $link = '<a href="' . System::baseUrl() . '/profile/' . $a->user['nickname'] . '"><img src="' . $author['thumb'] . '" alt="' . $a->user['username'] . '" /></a><br /><br />';
$html = prepare_body($datarray); $html = prepare_body($datarray);

0
mod/like.php Executable file → Normal file
View file

View file

@ -1,12 +1,13 @@
<?php <?php
/**
* @file mod/lostpass.php
*/
use Friendica\App; use Friendica\App;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Database\DBM; use Friendica\Database\DBM;
require_once('include/email.php'); require_once 'include/enotify.php';
require_once('include/enotify.php'); require_once 'include/text.php';
require_once('include/text.php');
function lostpass_post(App $a) { function lostpass_post(App $a) {

View file

@ -3,6 +3,7 @@
* @file mod/network.php * @file mod/network.php
*/ */
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Content\ForumManager; use Friendica\Content\ForumManager;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Config; use Friendica\Core\Config;
@ -156,8 +157,8 @@ function network_init(App $a) {
$a->page['aside'] = ''; $a->page['aside'] = '';
} }
$a->page['aside'] .= (feature_enabled(local_user(),'groups') ? group_side('network/0','network','standard',$group_id) : ''); $a->page['aside'] .= (Feature::isEnabled(local_user(),'groups') ? group_side('network/0','network','standard',$group_id) : '');
$a->page['aside'] .= (feature_enabled(local_user(), 'forumlist_widget') ? ForumManager::widget(local_user(), $cid) : ''); $a->page['aside'] .= (Feature::isEnabled(local_user(), 'forumlist_widget') ? ForumManager::widget(local_user(), $cid) : '');
$a->page['aside'] .= posted_date_widget('network',local_user(),false); $a->page['aside'] .= posted_date_widget('network',local_user(),false);
$a->page['aside'] .= networks_widget('network',(x($_GET, 'nets') ? $_GET['nets'] : '')); $a->page['aside'] .= networks_widget('network',(x($_GET, 'nets') ? $_GET['nets'] : ''));
$a->page['aside'] .= saved_searches($search); $a->page['aside'] .= saved_searches($search);
@ -166,7 +167,7 @@ function network_init(App $a) {
function saved_searches($search) { function saved_searches($search) {
if (!feature_enabled(local_user(),'savedsearch')) { if (!Feature::isEnabled(local_user(),'savedsearch')) {
return ''; return '';
} }
@ -918,7 +919,7 @@ function network_tabs(App $a)
), ),
); );
if (feature_enabled(local_user(),'personal_tab')) { if (Feature::isEnabled(local_user(),'personal_tab')) {
$tabs[] = array( $tabs[] = array(
'label' => t('Personal'), 'label' => t('Personal'),
'url' => str_replace('/new', '', $cmd) . ((x($_GET,'cid')) ? '/?f=&cid=' . $_GET['cid'] : '/?f=') . '&conv=1', 'url' => str_replace('/new', '', $cmd) . ((x($_GET,'cid')) ? '/?f=&cid=' . $_GET['cid'] : '/?f=') . '&conv=1',
@ -929,7 +930,7 @@ function network_tabs(App $a)
); );
} }
if (feature_enabled(local_user(),'new_tab')) { if (Feature::isEnabled(local_user(),'new_tab')) {
$tabs[] = array( $tabs[] = array(
'label' => t('New'), 'label' => t('New'),
'url' => 'network/new' . ((x($_GET,'cid')) ? '/?f=&cid=' . $_GET['cid'] : ''), 'url' => 'network/new' . ((x($_GET,'cid')) ? '/?f=&cid=' . $_GET['cid'] : ''),
@ -940,7 +941,7 @@ function network_tabs(App $a)
); );
} }
if (feature_enabled(local_user(),'link_tab')) { if (Feature::isEnabled(local_user(),'link_tab')) {
$tabs[] = array( $tabs[] = array(
'label' => t('Shared Links'), 'label' => t('Shared Links'),
'url' => str_replace('/new', '', $cmd) . ((x($_GET,'cid')) ? '/?f=&cid=' . $_GET['cid'] : '/?f=') . '&bmark=1', 'url' => str_replace('/new', '', $cmd) . ((x($_GET,'cid')) ? '/?f=&cid=' . $_GET['cid'] : '/?f=') . '&bmark=1',
@ -951,7 +952,7 @@ function network_tabs(App $a)
); );
} }
if (feature_enabled(local_user(),'star_posts')) { if (Feature::isEnabled(local_user(),'star_posts')) {
$tabs[] = array( $tabs[] = array(
'label' => t('Starred'), 'label' => t('Starred'),
'url' => str_replace('/new', '', $cmd) . ((x($_GET,'cid')) ? '/?f=&cid=' . $_GET['cid'] : '/?f=') . '&star=1', 'url' => str_replace('/new', '', $cmd) . ((x($_GET,'cid')) ? '/?f=&cid=' . $_GET['cid'] : '/?f=') . '&star=1',

View file

@ -1,6 +1,6 @@
<?php <?php
/* identi.ca -> friendica items permanent-url compatibility */ /* GNU Social -> friendica items permanent-url compatibility */
use Friendica\App; use Friendica\App;
use Friendica\Core\System; use Friendica\Core\System;

View file

@ -3,6 +3,7 @@
* @file mod/photos.php * @file mod/photos.php
*/ */
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\Worker; use Friendica\Core\Worker;
@ -895,7 +896,7 @@ function photos_post(App $a) {
/// @TODO merge these 2 if() into one? /// @TODO merge these 2 if() into one?
if ($exif && $exif['GPS']) { if ($exif && $exif['GPS']) {
if (feature_enabled($channel_id,'photo_location')) { if (Feature::isEnabled($channel_id,'photo_location')) {
$lat = getGps($exif['GPS']['GPSLatitude'], $exif['GPS']['GPSLatitudeRef']); $lat = getGps($exif['GPS']['GPSLatitude'], $exif['GPS']['GPSLatitudeRef']);
$lon = getGps($exif['GPS']['GPSLongitude'], $exif['GPS']['GPSLongitudeRef']); $lon = getGps($exif['GPS']['GPSLongitude'], $exif['GPS']['GPSLongitudeRef']);
} }
@ -1584,7 +1585,7 @@ function photos_content(App $a) {
$likebuttons = replace_macros($like_tpl, array( $likebuttons = replace_macros($like_tpl, array(
'$id' => $link_item['id'], '$id' => $link_item['id'],
'$likethis' => t("I like this \x28toggle\x29"), '$likethis' => t("I like this \x28toggle\x29"),
'$nolike' => (feature_enabled(local_user(), 'dislike') ? t("I don't like this \x28toggle\x29") : ''), '$nolike' => (Feature::isEnabled(local_user(), 'dislike') ? t("I don't like this \x28toggle\x29") : ''),
'$wait' => t('Please wait'), '$wait' => t('Please wait'),
'$return_path' => $a->query_string, '$return_path' => $a->query_string,
)); ));
@ -1735,7 +1736,7 @@ function photos_content(App $a) {
$response_verbs = array('like'); $response_verbs = array('like');
if (feature_enabled($owner_uid, 'dislike')) { if (Feature::isEnabled($owner_uid, 'dislike')) {
$response_verbs[] = 'dislike'; $response_verbs[] = 'dislike';
} }
$responses = get_responses($conv_responses,$response_verbs, '', $link_item); $responses = get_responses($conv_responses,$response_verbs, '', $link_item);

View file

@ -3,6 +3,7 @@
* @file include/ping.php * @file include/ping.php
*/ */
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Content\ForumManager; use Friendica\Content\ForumManager;
use Friendica\Core\Cache; use Friendica\Core\Cache;
use Friendica\Core\System; use Friendica\Core\System;
@ -149,7 +150,7 @@ function ping_init(App $a)
} }
if ($network_count) { if ($network_count) {
if (intval(feature_enabled(local_user(), 'groups'))) { if (intval(Feature::isEnabled(local_user(), 'groups'))) {
// Find out how unseen network posts are spread across groups // Find out how unseen network posts are spread across groups
$group_counts = groups_count_unseen(); $group_counts = groups_count_unseen();
if (DBM::is_result($group_counts)) { if (DBM::is_result($group_counts)) {
@ -161,7 +162,7 @@ function ping_init(App $a)
} }
} }
if (intval(feature_enabled(local_user(), 'forumlist_widget'))) { if (intval(Feature::isEnabled(local_user(), 'forumlist_widget'))) {
$forum_counts = ForumManager::countUnseenItems(); $forum_counts = ForumManager::countUnseenItems();
if (DBM::is_result($forums_counts)) { if (DBM::is_result($forums_counts)) {
foreach ($forums_counts as $forum_count) { foreach ($forums_counts as $forum_count) {

View file

@ -1,54 +0,0 @@
<?php
/**
* Zot endpoint
*/
use Friendica\App;
use Friendica\Database\DBM;
require_once('include/salmon.php');
require_once('include/crypto.php');
// not yet ready for prime time
//require_once('include/zot.php');
function post_post(App $a) {
$bulk_delivery = false;
if ($a->argc == 1) {
$bulk_delivery = true;
}
else {
$nickname = $a->argv[2];
$r = q("SELECT * FROM `user` WHERE `nickname` = '%s'
AND `account_expired` = 0 AND `account_removed` = 0 LIMIT 1",
dbesc($nickname)
);
if (! DBM::is_result($r)) {
http_status_exit(500);
}
$importer = $r[0];
}
$xml = file_get_contents('php://input');
logger('mod-post: new zot: ' . $xml, LOGGER_DATA);
if(! $xml)
http_status_exit(500);
$msg = zot_decode($importer,$xml);
logger('mod-post: decoded msg: ' . print_r($msg,true), LOGGER_DATA);
if(! is_array($msg))
http_status_exit(500);
$ret = 0;
$ret = zot_incoming($bulk_delivery, $importer,$msg);
http_status_exit(($ret) ? $ret : 200);
// NOTREACHED
}

View file

@ -3,6 +3,7 @@
* @file mod/profiles.php * @file mod/profiles.php
*/ */
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
use Friendica\Core\System; use Friendica\Core\System;
@ -673,10 +674,10 @@ function profiles_content(App $a) {
array(t('No'), t('Yes')) //Off - On strings array(t('No'), t('Yes')) //Off - On strings
), ),
'$multi_profiles' => feature_enabled(local_user(), 'multi_profiles'), '$multi_profiles' => Feature::isEnabled(local_user(), 'multi_profiles'),
'$form_security_token' => get_form_security_token("profile_edit"), '$form_security_token' => get_form_security_token("profile_edit"),
'$form_security_token_photo' => get_form_security_token("profile_photo"), '$form_security_token_photo' => get_form_security_token("profile_photo"),
'$profile_clone_link' => ((feature_enabled(local_user(), 'multi_profiles')) ? 'profiles/clone/' . $r[0]['id'] . '?t=' . get_form_security_token("profile_clone") : ""), '$profile_clone_link' => ((Feature::isEnabled(local_user(), 'multi_profiles')) ? 'profiles/clone/' . $r[0]['id'] . '?t=' . get_form_security_token("profile_clone") : ""),
'$profile_drop_link' => 'profiles/drop/' . $r[0]['id'] . '?t=' . get_form_security_token("profile_drop"), '$profile_drop_link' => 'profiles/drop/' . $r[0]['id'] . '?t=' . get_form_security_token("profile_drop"),
'$profile_action' => t('Profile Actions'), '$profile_action' => t('Profile Actions'),
@ -754,7 +755,7 @@ function profiles_content(App $a) {
return $o; return $o;
} else { } else {
// If we don't support multi profiles, don't display this list. // If we don't support multi profiles, don't display this list.
if (!feature_enabled(local_user(), 'multi_profiles')) { if (!Feature::isEnabled(local_user(), 'multi_profiles')) {
$r = q("SELECT * FROM `profile` WHERE `uid` = %d AND `is-default`=1", $r = q("SELECT * FROM `profile` WHERE `uid` = %d AND `is-default`=1",
local_user() local_user()
); );

View file

@ -1,7 +1,7 @@
<?php <?php
/** /**
* Diaspora endpoint * @file mod/receive.php
* @brief Diaspora endpoint
*/ */
use Friendica\App; use Friendica\App;
@ -9,10 +9,14 @@ use Friendica\Core\Config;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Protocol\Diaspora; use Friendica\Protocol\Diaspora;
require_once('include/salmon.php'); require_once 'include/crypto.php';
require_once('include/crypto.php');
function receive_post(App $a) { /**
* @param object $a App
* @return void
*/
function receive_post(App $a)
{
$enabled = intval(Config::get('system', 'diaspora_enabled')); $enabled = intval(Config::get('system', 'diaspora_enabled'));
if (!$enabled) { if (!$enabled) {
logger('mod-diaspora: disabled'); logger('mod-diaspora: disabled');
@ -44,7 +48,7 @@ function receive_post(App $a) {
if (!$xml) { if (!$xml) {
$postdata = file_get_contents("php://input"); $postdata = file_get_contents("php://input");
if ($postdata == '') { if ($postdata == '') {
http_status_exit(500); http_status_exit(500);
} }
@ -80,4 +84,3 @@ function receive_post(App $a) {
http_status_exit(($ret) ? 200 : 500); http_status_exit(($ret) ? 200 : 500);
// NOTREACHED // NOTREACHED
} }

View file

@ -5,10 +5,10 @@ use Friendica\Core\Config;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Model\User;
require_once('include/enotify.php'); require_once 'include/enotify.php';
require_once('include/bbcode.php'); require_once 'include/bbcode.php';
require_once('include/user.php');
if(! function_exists('register_post')) { if(! function_exists('register_post')) {
function register_post(App $a) { function register_post(App $a) {
@ -61,7 +61,7 @@ function register_post(App $a) {
$arr['verified'] = $verified; $arr['verified'] = $verified;
$arr['language'] = get_browser_language(); $arr['language'] = get_browser_language();
$result = create_user($arr); $result = User::create($arr);
if(! $result['success']) { if(! $result['success']) {
notice($result['message']); notice($result['message']);
@ -89,7 +89,7 @@ function register_post(App $a) {
// Only send a password mail when the password wasn't manually provided // Only send a password mail when the password wasn't manually provided
if (!x($_POST,'password1') || !x($_POST,'confirm')) { if (!x($_POST,'password1') || !x($_POST,'confirm')) {
$res = send_register_open_eml( $res = User::sendRegisterOpenEmail(
$user['email'], $user['email'],
$a->config['sitename'], $a->config['sitename'],
System::baseUrl(), System::baseUrl(),
@ -159,7 +159,7 @@ function register_post(App $a) {
)); ));
} }
// send notification to the user, that the registration is pending // send notification to the user, that the registration is pending
send_register_pending_eml( User::sendRegisterPendingEmail(
$user['email'], $user['email'],
$a->config['sitename'], $a->config['sitename'],
$user['username']); $user['username']);

View file

@ -6,11 +6,10 @@ use Friendica\Core\System;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Database\DBM; use Friendica\Database\DBM;
require_once('include/enotify.php'); require_once 'include/enotify.php';
require_once('include/user.php');
function user_allow($hash) {
function user_allow($hash)
{
$a = get_app(); $a = get_app();
$register = q("SELECT * FROM `register` WHERE `hash` = '%s' LIMIT 1", $register = q("SELECT * FROM `register` WHERE `hash` = '%s' LIMIT 1",
@ -18,7 +17,7 @@ function user_allow($hash) {
); );
if (! DBM::is_result($register)) { if (!DBM::is_result($register)) {
return false; return false;
} }
@ -26,7 +25,7 @@ function user_allow($hash) {
intval($register[0]['uid']) intval($register[0]['uid'])
); );
if (! DBM::is_result($user)) { if (!DBM::is_result($user)) {
killme(); killme();
} }
@ -44,14 +43,14 @@ function user_allow($hash) {
); );
if (DBM::is_result($r) && $r[0]['net-publish']) { if (DBM::is_result($r) && $r[0]['net-publish']) {
$url = System::baseUrl() . '/profile/' . $user[0]['nickname']; $url = System::baseUrl() . '/profile/' . $user[0]['nickname'];
if ($url && strlen(Config::get('system','directory'))) { if ($url && strlen(Config::get('system', 'directory'))) {
Worker::add(PRIORITY_LOW, "Directory", $url); Worker::add(PRIORITY_LOW, "Directory", $url);
} }
} }
push_lang($register[0]['language']); push_lang($register[0]['language']);
send_register_open_eml( User::sendRegisterOpenEmail(
$user[0]['email'], $user[0]['email'],
$a->config['sitename'], $a->config['sitename'],
System::baseUrl(), System::baseUrl(),
@ -60,20 +59,17 @@ function user_allow($hash) {
pop_lang(); pop_lang();
if($res) { if ($res) {
info( t('Account approved.') . EOL ); info(t('Account approved.') . EOL);
return true; return true;
} }
} }
// This does not have to go through user_remove() and save the nickname // This does not have to go through user_remove() and save the nickname
// permanently against re-registration, as the person was not yet // permanently against re-registration, as the person was not yet
// allowed to have friends on this system // allowed to have friends on this system
function user_deny($hash)
function user_deny($hash) { {
$register = q("SELECT * FROM `register` WHERE `hash` = '%s' LIMIT 1", $register = q("SELECT * FROM `register` WHERE `hash` = '%s' LIMIT 1",
dbesc($hash) dbesc($hash)
); );
@ -91,23 +87,22 @@ function user_deny($hash) {
notice(sprintf(t('Registration revoked for %s'), $user[0]['username']) . EOL); notice(sprintf(t('Registration revoked for %s'), $user[0]['username']) . EOL);
return true; return true;
} }
function regmod_content(App $a) { function regmod_content(App $a)
{
global $lang; global $lang;
$_SESSION['return_url'] = $a->cmd; $_SESSION['return_url'] = $a->cmd;
if (! local_user()) { if (!local_user()) {
info( t('Please login.') . EOL); info(t('Please login.') . EOL);
$o .= '<br /><br />' . login(($a->config['register_policy'] == REGISTER_CLOSED) ? 0 : 1); $o .= '<br /><br />' . login(($a->config['register_policy'] == REGISTER_CLOSED) ? 0 : 1);
return $o; return $o;
} }
if ((!is_site_admin()) || (x($_SESSION,'submanage') && intval($_SESSION['submanage']))) { if ((!is_site_admin()) || (x($_SESSION, 'submanage') && intval($_SESSION['submanage']))) {
notice( t('Permission denied.') . EOL); notice(t('Permission denied.') . EOL);
return ''; return '';
} }
@ -115,20 +110,18 @@ function regmod_content(App $a) {
killme(); killme();
} }
$cmd = $a->argv[1]; $cmd = $a->argv[1];
$hash = $a->argv[2]; $hash = $a->argv[2];
if ($cmd === 'deny') { if ($cmd === 'deny') {
user_deny($hash); user_deny($hash);
goaway(System::baseUrl()."/admin/users/"); goaway(System::baseUrl() . "/admin/users/");
killme(); killme();
} }
if ($cmd === 'allow') { if ($cmd === 'allow') {
user_allow($hash); user_allow($hash);
goaway(System::baseUrl()."/admin/users/"); goaway(System::baseUrl() . "/admin/users/");
killme(); killme();
} }
} }

0
mod/repair_ostatus.php Executable file → Normal file
View file

View file

@ -6,8 +6,8 @@ use Friendica\App;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Protocol\OStatus; use Friendica\Protocol\OStatus;
use Friendica\Protocol\Salmon;
require_once 'include/salmon.php';
require_once 'include/crypto.php'; require_once 'include/crypto.php';
require_once 'include/items.php'; require_once 'include/items.php';
require_once 'include/follow.php'; require_once 'include/follow.php';
@ -103,7 +103,7 @@ function salmon_post(App $a) {
logger('mod-salmon: Fetching key for ' . $author_link); logger('mod-salmon: Fetching key for ' . $author_link);
$key = get_salmon_key($author_link,$keyhash); $key = Salmon::getKey($author_link, $keyhash);
if(! $key) { if(! $key) {
logger('mod-salmon: Could not retrieve author key.'); logger('mod-salmon: Could not retrieve author key.');

View file

@ -1,20 +1,23 @@
<?php <?php
/**
* @file mod/search.php
*/
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\Cache; use Friendica\Core\Cache;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Database\DBM; use Friendica\Database\DBM;
require_once("include/bbcode.php"); require_once "include/bbcode.php";
require_once('include/security.php'); require_once 'include/security.php';
require_once('include/conversation.php'); require_once 'include/conversation.php';
require_once('mod/dirfind.php'); require_once 'mod/dirfind.php';
function search_saved_searches() { function search_saved_searches() {
$o = ''; $o = '';
if (! feature_enabled(local_user(),'savedsearch')) if (! Feature::isEnabled(local_user(),'savedsearch'))
return $o; return $o;
$r = q("SELECT `id`,`term` FROM `search` WHERE `uid` = %d", $r = q("SELECT `id`,`term` FROM `search` WHERE `uid` = %d",

View file

@ -3,6 +3,7 @@
* @file mod/settings.php * @file mod/settings.php
*/ */
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Core\Config; use Friendica\Core\Config;
@ -10,6 +11,7 @@ use Friendica\Core\PConfig;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Model\GlobalContact; use Friendica\Model\GlobalContact;
use Friendica\Model\User; use Friendica\Model\User;
use Friendica\Protocol\Email;
require_once 'include/group.php'; require_once 'include/group.php';
@ -51,7 +53,7 @@ function settings_init(App $a) {
), ),
); );
if (get_features()) { if (Feature::get()) {
$tabs[] = array( $tabs[] = array(
'label' => t('Additional features'), 'label' => t('Additional features'),
'url' => 'settings/features', 'url' => 'settings/features',
@ -259,12 +261,12 @@ function settings_post(App $a) {
); );
if (DBM::is_result($r)) { if (DBM::is_result($r)) {
$eacct = $r[0]; $eacct = $r[0];
require_once('include/email.php'); $mb = Email::constructMailboxName($eacct);
$mb = construct_mailbox_name($eacct);
if (strlen($eacct['server'])) { if (strlen($eacct['server'])) {
$dcrpass = ''; $dcrpass = '';
openssl_private_decrypt(hex2bin($eacct['pass']), $dcrpass, $a->user['prvkey']); openssl_private_decrypt(hex2bin($eacct['pass']), $dcrpass, $a->user['prvkey']);
$mbox = email_connect($mb, $mail_user, $dcrpass); $mbox = Email::connect($mb, $mail_user, $dcrpass);
unset($dcrpass); unset($dcrpass);
if (!$mbox) { if (!$mbox) {
$failed = true; $failed = true;
@ -347,7 +349,6 @@ function settings_post(App $a) {
} }
} }
$r = q("UPDATE `user` SET `theme` = '%s' WHERE `uid` = %d", $r = q("UPDATE `user` SET `theme` = '%s' WHERE `uid` = %d",
dbesc($theme), dbesc($theme),
intval(local_user()) intval(local_user())
@ -369,7 +370,6 @@ function settings_post(App $a) {
call_hooks('settings_post', $_POST); call_hooks('settings_post', $_POST);
if (x($_POST, 'password') || x($_POST, 'confirm')) { if (x($_POST, 'password') || x($_POST, 'confirm')) {
$newpass = $_POST['password']; $newpass = $_POST['password'];
$confirm = $_POST['confirm']; $confirm = $_POST['confirm'];
@ -384,9 +384,8 @@ function settings_post(App $a) {
$err = true; $err = true;
} }
// check if the old password was supplied correctly before // check if the old password was supplied correctly before changing it to the new value
// changing it to the new value if (!User::authenticate(intval(local_user()), $_POST['opassword'])) {
if (User::authenticate(intval(local_user()), $_POST['opassword'])) {
notice(t('Wrong password.') . EOL); notice(t('Wrong password.') . EOL);
$err = true; $err = true;
} }
@ -397,14 +396,14 @@ function settings_post(App $a) {
dbesc($password), dbesc($password),
intval(local_user()) intval(local_user())
); );
if ($r) if ($r) {
info(t('Password changed.') . EOL); info(t('Password changed.') . EOL);
else } else {
notice(t('Password update failed. Please try again.') . EOL); notice(t('Password update failed. Please try again.') . EOL);
}
} }
} }
$username = ((x($_POST, 'username')) ? notags(trim($_POST['username'])) : ''); $username = ((x($_POST, 'username')) ? notags(trim($_POST['username'])) : '');
$email = ((x($_POST, 'email')) ? notags(trim($_POST['email'])) : ''); $email = ((x($_POST, 'email')) ? notags(trim($_POST['email'])) : '');
$timezone = ((x($_POST, 'timezone')) ? notags(trim($_POST['timezone'])) : ''); $timezone = ((x($_POST, 'timezone')) ? notags(trim($_POST['timezone'])) : '');
@ -786,12 +785,12 @@ function settings_content(App $a) {
if (($a->argc > 1) && ($a->argv[1] === 'features')) { if (($a->argc > 1) && ($a->argv[1] === 'features')) {
$arr = array(); $arr = array();
$features = get_features(); $features = Feature::get();
foreach ($features as $fname => $fdata) { foreach ($features as $fname => $fdata) {
$arr[$fname] = array(); $arr[$fname] = array();
$arr[$fname][0] = $fdata[0]; $arr[$fname][0] = $fdata[0];
foreach (array_slice($fdata,1) as $f) { foreach (array_slice($fdata,1) as $f) {
$arr[$fname][1][] = array('feature_' .$f[0], $f[1],((intval(feature_enabled(local_user(), $f[0]))) ? "1" : ''), $f[2],array(t('Off'), t('On'))); $arr[$fname][1][] = array('feature_' .$f[0], $f[1],((intval(Feature::isEnabled(local_user(), $f[0]))) ? "1" : ''), $f[2],array(t('Off'), t('On')));
} }
} }

View file

@ -94,7 +94,6 @@ function xrd_xml($a, $uri, $alias, $profile_url, $r) {
'$profile_url' => $profile_url, '$profile_url' => $profile_url,
'$hcard_url' => System::baseUrl() . '/hcard/' . $r['nickname'], '$hcard_url' => System::baseUrl() . '/hcard/' . $r['nickname'],
'$atom' => System::baseUrl() . '/dfrn_poll/' . $r['nickname'], '$atom' => System::baseUrl() . '/dfrn_poll/' . $r['nickname'],
'$zot_post' => System::baseUrl() . '/post/' . $r['nickname'],
'$poco_url' => System::baseUrl() . '/poco/' . $r['nickname'], '$poco_url' => System::baseUrl() . '/poco/' . $r['nickname'],
'$photo' => System::baseUrl() . '/photo/profile/' . $r['uid'] . '.jpg', '$photo' => System::baseUrl() . '/photo/profile/' . $r['uid'] . '.jpg',
'$baseurl' => System::baseUrl(), '$baseurl' => System::baseUrl(),

156
src/Content/Feature.php Normal file
View file

@ -0,0 +1,156 @@
<?php
/**
* @file src/Content/Feature.php
* @brief Features management
*/
namespace Friendica\Content;
use Friendica\Core\Config;
use Friendica\Core\PConfig;
require_once 'include/plugin.php';
class Feature
{
/**
* @brief check if feature is enabled
*
* @param integer $uid user id
* @param string $feature feature
* @return boolean
*/
public static function isEnabled($uid, $feature)
{
$x = Config::get('feature_lock', $feature, false);
if ($x === false) {
$x = PConfig::get($uid, 'feature', $feature, false);
}
if ($x === false) {
$x = Config::get('feature', $feature, false);
}
if ($x === false) {
$x = self::getDefault($feature);
}
$arr = array('uid' => $uid, 'feature' => $feature, 'enabled' => $x);
call_hooks('isEnabled', $arr);
return($arr['enabled']);
}
/**
* @brief check if feature is enabled or disabled by default
*
* @param string $feature feature
* @return boolean
*/
private static function getDefault($feature)
{
$f = self::get();
foreach ($f as $cat) {
foreach ($cat as $feat) {
if (is_array($feat) && $feat[0] === $feature) {
return $feat[3];
}
}
}
return false;
}
/**
* @brief Get a list of all available features
*
* The array includes the setting group, the setting name,
* explainations for the setting and if it's enabled or disabled
* by default
*
* @param bool $filtered True removes any locked features
*
* @return array
*/
public static function get($filtered = true)
{
$arr = array(
// General
'general' => array(
t('General Features'),
//array('expire', t('Content Expiration'), t('Remove old posts/comments after a period of time')),
array('multi_profiles', t('Multiple Profiles'), t('Ability to create multiple profiles'), false, Config::get('feature_lock', 'multi_profiles', false)),
array('photo_location', t('Photo Location'), t('Photo metadata is normally stripped. This extracts the location (if present) prior to stripping metadata and links it to a map.'), false, Config::get('feature_lock', 'photo_location', false)),
array('export_calendar', t('Export Public Calendar'), t('Ability for visitors to download the public calendar'), false, Config::get('feature_lock', 'export_calendar', false)),
),
// Post composition
'composition' => array(
t('Post Composition Features'),
array('preview', t('Post Preview'), t('Allow previewing posts and comments before publishing them'), false, Config::get('feature_lock', 'preview', false)),
array('aclautomention', t('Auto-mention Forums'), t('Add/remove mention when a forum page is selected/deselected in ACL window.'), false, Config::get('feature_lock', 'aclautomention', false)),
),
// Network sidebar widgets
'widgets' => array(
t('Network Sidebar Widgets'),
array('archives', t('Search by Date'), t('Ability to select posts by date ranges'), false, Config::get('feature_lock', 'archives', false)),
array('forumlist_widget', t('List Forums'), t('Enable widget to display the forums your are connected with'), true, Config::get('feature_lock', 'forumlist_widget', false)),
array('groups', t('Group Filter'), t('Enable widget to display Network posts only from selected group'), false, Config::get('feature_lock', 'groups', false)),
array('networks', t('Network Filter'), t('Enable widget to display Network posts only from selected network'), false, Config::get('feature_lock', 'networks', false)),
array('savedsearch', t('Saved Searches'), t('Save search terms for re-use'), false, Config::get('feature_lock', 'savedsearch', false)),
),
// Network tabs
'net_tabs' => array(
t('Network Tabs'),
array('personal_tab', t('Network Personal Tab'), t('Enable tab to display only Network posts that you\'ve interacted on'), false, Config::get('feature_lock', 'personal_tab', false)),
array('new_tab', t('Network New Tab'), t('Enable tab to display only new Network posts (from the last 12 hours)'), false, Config::get('feature_lock', 'new_tab', false)),
array('link_tab', t('Network Shared Links Tab'), t('Enable tab to display only Network posts with links in them'), false, Config::get('feature_lock', 'link_tab', false)),
),
// Item tools
'tools' => array(
t('Post/Comment Tools'),
array('multi_delete', t('Multiple Deletion'), t('Select and delete multiple posts/comments at once'), false, Config::get('feature_lock', 'multi_delete', false)),
array('edit_posts', t('Edit Sent Posts'), t('Edit and correct posts and comments after sending'), false, Config::get('feature_lock', 'edit_posts', false)),
array('commtag', t('Tagging'), t('Ability to tag existing posts'), false, Config::get('feature_lock', 'commtag', false)),
array('categories', t('Post Categories'), t('Add categories to your posts'), false, Config::get('feature_lock', 'categories', false)),
array('filing', t('Saved Folders'), t('Ability to file posts under folders'), false, Config::get('feature_lock', 'filing', false)),
array('dislike', t('Dislike Posts'), t('Ability to dislike posts/comments'), false, Config::get('feature_lock', 'dislike', false)),
array('star_posts', t('Star Posts'), t('Ability to mark special posts with a star indicator'), false, Config::get('feature_lock', 'star_posts', false)),
array('ignore_posts', t('Mute Post Notifications'), t('Ability to mute notifications for a thread'), false, Config::get('feature_lock', 'ignore_posts', false)),
),
// Advanced Profile Settings
'advanced_profile' => array(
t('Advanced Profile Settings'),
array('forumlist_profile', t('List Forums'), t('Show visitors public community forums at the Advanced Profile Page'), false, Config::get('feature_lock', 'forumlist_profile', false)),
array('tagadelic', t('Tag Cloud'), t('Provide a personal tag cloud on your profile page'), false, Config::get('feature_lock', 'tagadelic', false)),
),
);
// removed any locked features and remove the entire category if this makes it empty
if ($filtered) {
foreach ($arr as $k => $x) {
$has_items = false;
$kquantity = count($arr[$k]);
for ($y = 0; $y < $kquantity; $y ++) {
if (is_array($arr[$k][$y])) {
if ($arr[$k][$y][4] === false) {
$has_items = true;
} else {
unset($arr[$k][$y]);
}
}
}
if (! $has_items) {
unset($arr[$k]);
}
}
}
call_hooks('get', $arr);
return $arr;
}
}

View file

@ -6,6 +6,7 @@
namespace Friendica\Content; namespace Friendica\Content;
use Friendica\App; use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use dba; use dba;
@ -82,7 +83,7 @@ class ForumManager
*/ */
public static function widget($uid, $cid = 0) public static function widget($uid, $cid = 0)
{ {
if (! intval(feature_enabled(local_user(), 'forumlist_widget'))) { if (! intval(Feature::isEnabled(local_user(), 'forumlist_widget'))) {
return; return;
} }
@ -141,7 +142,7 @@ class ForumManager
*/ */
public static function profileAdvanced($uid) public static function profileAdvanced($uid)
{ {
$profile = intval(feature_enabled($uid, 'forumlist_profile')); $profile = intval(Feature::isEnabled($uid, 'forumlist_profile'));
if (! $profile) { if (! $profile) {
return; return;
} }

View file

@ -7,19 +7,41 @@
namespace Friendica\Model; namespace Friendica\Model;
use Friendica\Core\Config;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Object\Contact;
use Friendica\Object\Photo;
use dba; use dba;
require_once 'boot.php'; require_once 'boot.php';
require_once 'include/crypto.php';
require_once 'include/enotify.php';
require_once 'include/group.php';
require_once 'include/network.php';
require_once 'library/openid.php';
require_once 'include/pgettext.php';
require_once 'include/plugin.php'; require_once 'include/plugin.php';
require_once 'include/text.php';
/** /**
* @brief This class handles User related functions * @brief This class handles User related functions
*/ */
class User class User
{ {
/**
* @brief Authenticate a user with a clear text password
*
* User info can be any of the following:
* - User DB object
* - User Id
* - User email or username or nickname
* - User array with at least the uid and the hashed password
*
* @param mixed $user_info
* @param string $password
* @return boolean
*/
public static function authenticate($user_info, $password) public static function authenticate($user_info, $password)
{ {
if (is_object($user_info)) { if (is_object($user_info)) {
@ -66,6 +88,424 @@ class User
return $user['uid']; return $user['uid'];
} }
/**
* @brief Catch-all user creation function
*
* Creates a user from the provided data array, either form fields or OpenID.
* Required: { username, nickname, email } or { openid_url }
*
* Performs the following:
* - Sends to the OpenId auth URL (if relevant)
* - Creates new key pairs for crypto
* - Create self-contact
* - Create profile image
*
* @param array $data
* @return string
*/
public static function create(array $data)
{
$a = get_app();
$result = array('success' => false, 'user' => null, 'password' => '', 'message' => '');
$using_invites = Config::get('system', 'invitation_only');
$num_invites = Config::get('system', 'number_invites');
$invite_id = x($data, 'invite_id') ? notags(trim($data['invite_id'])) : '';
$username = x($data, 'username') ? notags(trim($data['username'])) : '';
$nickname = x($data, 'nickname') ? notags(trim($data['nickname'])) : '';
$email = x($data, 'email') ? notags(trim($data['email'])) : '';
$openid_url = x($data, 'openid_url') ? notags(trim($data['openid_url'])) : '';
$photo = x($data, 'photo') ? notags(trim($data['photo'])) : '';
$password = x($data, 'password') ? trim($data['password']) : '';
$password1 = x($data, 'password1') ? trim($data['password1']) : '';
$confirm = x($data, 'confirm') ? trim($data['confirm']) : '';
$blocked = x($data, 'blocked') ? intval($data['blocked']) : 0;
$verified = x($data, 'verified') ? intval($data['verified']) : 0;
$publish = x($data, 'profile_publish_reg') && intval($data['profile_publish_reg']) ? 1 : 0;
$netpublish = strlen(Config::get('system', 'directory')) ? $publish : 0;
if ($password1 != $confirm) {
$result['message'] .= t('Passwords do not match. Password unchanged.') . EOL;
return $result;
} elseif ($password1 != "") {
$password = $password1;
}
$tmp_str = $openid_url;
if ($using_invites) {
if (!$invite_id) {
$result['message'] .= t('An invitation is required.') . EOL;
return $result;
}
$r = q("SELECT * FROM `register` WHERE `hash` = '%s' LIMIT 1", dbesc($invite_id));
if (!results($r)) {
$result['message'] .= t('Invitation could not be verified.') . EOL;
return $result;
}
}
if (!x($username) || !x($email) || !x($nickname)) {
if ($openid_url) {
if (!validate_url($tmp_str)) {
$result['message'] .= t('Invalid OpenID url') . EOL;
return $result;
}
$_SESSION['register'] = 1;
$_SESSION['openid'] = $openid_url;
$openid = new LightOpenID;
$openid->identity = $openid_url;
$openid->returnUrl = System::baseUrl() . '/openid';
$openid->required = array('namePerson/friendly', 'contact/email', 'namePerson');
$openid->optional = array('namePerson/first', 'media/image/aspect11', 'media/image/default');
try {
$authurl = $openid->authUrl();
} catch (Exception $e) {
$result['message'] .= t("We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID.") . EOL . EOL . t("The error message was:") . $e->getMessage() . EOL;
return $result;
}
goaway($authurl);
// NOTREACHED
}
notice(t('Please enter the required information.') . EOL);
return;
}
if (!validate_url($tmp_str)) {
$openid_url = '';
}
$err = '';
// collapse multiple spaces in name
$username = preg_replace('/ +/', ' ', $username);
if (mb_strlen($username) > 48) {
$result['message'] .= t('Please use a shorter name.') . EOL;
}
if (mb_strlen($username) < 3) {
$result['message'] .= t('Name too short.') . EOL;
}
// So now we are just looking for a space in the full name.
$loose_reg = Config::get('system', 'no_regfullname');
if (!$loose_reg) {
$username = mb_convert_case($username, MB_CASE_TITLE, 'UTF-8');
if (!strpos($username, ' ')) {
$result['message'] .= t("That doesn't appear to be your full \x28First Last\x29 name.") . EOL;
}
}
if (!allowed_email($email)) {
$result['message'] .= t('Your email domain is not among those allowed on this site.') . EOL;
}
if (!valid_email($email) || !validate_email($email)) {
$result['message'] .= t('Not a valid email address.') . EOL;
}
// Disallow somebody creating an account using openid that uses the admin email address,
// since openid bypasses email verification. We'll allow it if there is not yet an admin account.
$adminlist = explode(",", str_replace(" ", "", strtolower($a->config['admin_email'])));
//if((x($a->config,'admin_email')) && (strcasecmp($email,$a->config['admin_email']) == 0) && strlen($openid_url)) {
if (x($a->config, 'admin_email') && in_array(strtolower($email), $adminlist) && strlen($openid_url)) {
$r = q("SELECT * FROM `user` WHERE `email` = '%s' LIMIT 1",
dbesc($email)
);
if (DBM::is_result($r)) {
$result['message'] .= t('Cannot use that email.') . EOL;
}
}
$nickname = $data['nickname'] = strtolower($nickname);
if (!preg_match("/^[a-z0-9][a-z0-9\_]*$/", $nickname)) {
$result['message'] .= t('Your "nickname" can only contain "a-z", "0-9" and "_".') . EOL;
}
$r = q("SELECT `uid` FROM `user`
WHERE `nickname` = '%s' LIMIT 1",
dbesc($nickname)
);
if (DBM::is_result($r)) {
$result['message'] .= t('Nickname is already registered. Please choose another.') . EOL;
}
// Check deleted accounts that had this nickname. Doesn't matter to us,
// but could be a security issue for federated platforms.
$r = q("SELECT * FROM `userd`
WHERE `username` = '%s' LIMIT 1",
dbesc($nickname)
);
if (DBM::is_result($r)) {
$result['message'] .= t('Nickname was once registered here and may not be re-used. Please choose another.') . EOL;
}
if (strlen($result['message'])) {
return $result;
}
$new_password = strlen($password) ? $password : autoname(6) . mt_rand(100, 9999);
$new_password_encoded = hash('whirlpool', $new_password);
$result['password'] = $new_password;
$keys = new_keypair(4096);
if ($keys === false) {
$result['message'] .= t('SERIOUS ERROR: Generation of security keys failed.') . EOL;
return $result;
}
$prvkey = $keys['prvkey'];
$pubkey = $keys['pubkey'];
// Create another keypair for signing/verifying salmon protocol messages.
$sres = new_keypair(512);
$sprvkey = $sres['prvkey'];
$spubkey = $sres['pubkey'];
$r = q("INSERT INTO `user` (`guid`, `username`, `password`, `email`, `openid`, `nickname`,
`pubkey`, `prvkey`, `spubkey`, `sprvkey`, `register_date`, `verified`, `blocked`, `timezone`, `default-location`)
VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, 'UTC', '')",
dbesc(generate_user_guid()),
dbesc($username),
dbesc($new_password_encoded),
dbesc($email),
dbesc($openid_url),
dbesc($nickname),
dbesc($pubkey),
dbesc($prvkey),
dbesc($spubkey),
dbesc($sprvkey),
dbesc(datetime_convert()),
intval($verified),
intval($blocked)
);
if ($r) {
$r = q("SELECT * FROM `user`
WHERE `username` = '%s' AND `password` = '%s' LIMIT 1",
dbesc($username),
dbesc($new_password_encoded)
);
if (DBM::is_result($r)) {
$u = $r[0];
$newuid = intval($r[0]['uid']);
}
} else {
$result['message'] .= t('An error occurred during registration. Please try again.') . EOL;
return $result;
}
/**
* if somebody clicked submit twice very quickly, they could end up with two accounts
* due to race condition. Remove this one.
*/
$r = q("SELECT `uid` FROM `user`
WHERE `nickname` = '%s' ",
dbesc($nickname)
);
if (DBM::is_result($r) && count($r) > 1 && $newuid) {
$result['message'] .= t('Nickname is already registered. Please choose another.') . EOL;
dba::delete('user', array('uid' => $newuid));
return $result;
}
if (x($newuid) !== false) {
$r = q("INSERT INTO `profile` ( `uid`, `profile-name`, `is-default`, `name`, `photo`, `thumb`, `publish`, `net-publish` )
VALUES ( %d, '%s', %d, '%s', '%s', '%s', %d, %d ) ",
intval($newuid),
t('default'),
1,
dbesc($username),
dbesc(System::baseUrl() . "/photo/profile/{$newuid}.jpg"),
dbesc(System::baseUrl() . "/photo/avatar/{$newuid}.jpg"),
intval($publish),
intval($netpublish)
);
if ($r === false) {
$result['message'] .= t('An error occurred creating your default profile. Please try again.') . EOL;
// Start fresh next time.
dba::delete('user', array('uid' => $newuid));
return $result;
}
// Create the self contact
Contact::createSelfFromUserId($newuid);
// Create a group with no members. This allows somebody to use it
// right away as a default group for new contacts.
group_add($newuid, t('Friends'));
$r = q("SELECT `id` FROM `group` WHERE `uid` = %d AND `name` = '%s'",
intval($newuid),
dbesc(t('Friends'))
);
if (DBM::is_result($r)) {
$def_gid = $r[0]['id'];
q("UPDATE `user` SET `def_gid` = %d WHERE `uid` = %d",
intval($r[0]['id']),
intval($newuid)
);
}
if (Config::get('system', 'newuser_private') && $def_gid) {
q("UPDATE `user` SET `allow_gid` = '%s' WHERE `uid` = %d",
dbesc("<" . $def_gid . ">"),
intval($newuid)
);
}
}
// if we have no OpenID photo try to look up an avatar
if (!strlen($photo)) {
$photo = avatar_img($email);
}
// unless there is no avatar-plugin loaded
if (strlen($photo)) {
$photo_failure = false;
$filename = basename($photo);
$img_str = fetch_url($photo, true);
// guess mimetype from headers or filename
$type = Photo::guessImageType($photo, true);
$img = new Photo($img_str, $type);
if ($img->isValid()) {
$img->scaleImageSquare(175);
$hash = photo_new_resource();
$r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 4);
if ($r === false) {
$photo_failure = true;
}
$img->scaleImage(80);
$r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 5);
if ($r === false) {
$photo_failure = true;
}
$img->scaleImage(48);
$r = $img->store($newuid, 0, $hash, $filename, t('Profile Photos'), 6);
if ($r === false) {
$photo_failure = true;
}
if (!$photo_failure) {
q("UPDATE `photo` SET `profile` = 1 WHERE `resource-id` = '%s' ",
dbesc($hash)
);
}
}
}
call_hooks('register_account', $newuid);
$result['success'] = true;
$result['user'] = $u;
return $result;
}
/**
* @brief Sends pending registration confiŕmation email
*
* @param string $email
* @param string $sitename
* @param string $username
* @return NULL|boolean from notification() and email() inherited
*/
public static function sendRegisterPendingEmail($email, $sitename, $username)
{
$body = deindent(t('
Dear %1$s,
Thank you for registering at %2$s. Your account is pending for approval by the administrator.
'));
$body = sprintf($body, $username, $sitename);
return notification(array(
'type' => SYSTEM_EMAIL,
'to_email' => $email,
'subject'=> sprintf( t('Registration at %s'), $sitename),
'body' => $body));
}
/**
* @brief Sends registration confirmation
*
* It's here as a function because the mail is sent from different parts
*
* @param string $email
* @param string $sitename
* @param string $siteurl
* @param string $username
* @param string $password
* @return NULL|boolean from notification() and email() inherited
*/
public static function sendRegisterOpenEmail($email, $sitename, $siteurl, $username, $password)
{
$preamble = deindent(t('
Dear %1$s,
Thank you for registering at %2$s. Your account has been created.
'));
$body = deindent(t('
The login details are as follows:
Site Location: %3$s
Login Name: %1$s
Password: %5$s
You may change your password from your account "Settings" page after logging
in.
Please take a few moments to review the other account settings on that page.
You may also wish to add some basic information to your default profile
(on the "Profiles" page) so that other people can easily find you.
We recommend setting your full name, adding a profile photo,
adding some profile "keywords" (very useful in making new friends) - and
perhaps what country you live in; if you do not wish to be more specific
than that.
We fully respect your right to privacy, and none of these items are necessary.
If you are new and do not know anybody here, they may help
you to make some new and interesting friends.
Thank you and welcome to %2$s.'));
$preamble = sprintf($preamble, $username, $sitename);
$body = sprintf($body, $email, $sitename, $siteurl, $username, $password);
return notification(array(
'type' => SYSTEM_EMAIL,
'to_email' => $email,
'subject'=> sprintf( t('Registration details for %s'), $sitename),
'preamble'=> $preamble,
'body' => $body));
}
/** /**
* @param object $uid user to remove * @param object $uid user to remove
* @return void * @return void

78
src/Network/FKOAuth1.php Normal file
View file

@ -0,0 +1,78 @@
<?php
/**
* @file src/Protocol/OAuth1.php
*/
namespace Friendica\Network;
use Friendica\App;
use Friendica\Core\PConfig;
use Friendica\Core\System;
use Friendica\Database\DBM;
use Friendica\Network\FKOAuthDataStore;
use dba;
use OAuthServer;
use OAuthSignatureMethod_PLAINTEXT;
use OAuthSignatureMethod_HMAC_SHA1;
require_once "library/OAuth1.php";
require_once "include/plugin.php";
/**
* @brief OAuth protocol
*/
class FKOAuth1 extends OAuthServer
{
/**
* @brief Constructor
*/
public function __construct()
{
parent::__construct(new FKOAuthDataStore());
$this->add_signature_method(new OAuthSignatureMethod_PLAINTEXT());
$this->add_signature_method(new OAuthSignatureMethod_HMAC_SHA1());
}
/**
* @param string $uid user id
* @return void
*/
public function loginUser($uid)
{
logger("FKOAuth1::loginUser $uid");
$a = get_app();
$record = dba::select('user', array(), array('uid' => $uid, 'blocked' => 0, 'account_expired' => 0, 'account_removed' => 0, 'verified' => 1), array('limit' => 1));
if (!DBM::is_result($record)) {
logger('FKOAuth1::loginUser failure: ' . print_r($_SERVER, true), LOGGER_DEBUG);
header('HTTP/1.0 401 Unauthorized');
die('This api requires login');
}
$_SESSION['uid'] = $record['uid'];
$_SESSION['theme'] = $record['theme'];
$_SESSION['mobile-theme'] = PConfig::get($record['uid'], 'system', 'mobile_theme');
$_SESSION['authenticated'] = 1;
$_SESSION['page_flags'] = $record['page-flags'];
$_SESSION['my_url'] = System::baseUrl() . '/profile/' . $record['nickname'];
$_SESSION['addr'] = $_SERVER['REMOTE_ADDR'];
$_SESSION["allow_api"] = true;
$a->user = $record;
if (strlen($a->user['timezone'])) {
date_default_timezone_set($a->user['timezone']);
$a->timezone = $a->user['timezone'];
}
$r = dba::select('contact', array(), array('uid' => $_SESSION['uid'], 'self' => 1), array('limit' => 1));
if (DBM::is_result($r)) {
$a->contact = $r;
$a->cid = $r['id'];
$_SESSION['cid'] = $a->cid;
}
dba::update('user', ['login_date' => datetime_convert()], ['uid' => $_SESSION['uid']]);
call_hooks('logged_in', $a->user);
}
}

View file

@ -0,0 +1,180 @@
<?php
/**
* @file src/Protocol/FKOAuthDataStore.php
* OAuth server
* Based on oauth2-php <http://code.google.com/p/oauth2-php/>
*
*/
namespace Friendica\Network;
use Friendica\App;
use Friendica\Core\Config;
use Friendica\Core\System;
use Friendica\Database\DBM;
use dba;
use OAuthDataStore;
define('REQUEST_TOKEN_DURATION', 300);
define('ACCESS_TOKEN_DURATION', 31536000);
require_once "library/OAuth1.php";
require_once "library/oauth2-php/lib/OAuth2.inc";
/**
* @brief OAuthDataStore class
*/
class FKOAuthDataStore extends OAuthDataStore
{
/**
* @return string
*/
private static function genToken()
{
return md5(base64_encode(pack('N6', mt_rand(), mt_rand(), mt_rand(), mt_rand(), mt_rand(), uniqid())));
}
/**
* @param string $consumer_key key
* @return mixed
*/
public function lookup_consumer($consumer_key)
{
logger(__function__.":".$consumer_key);
$s = dba::select('clients', array('client_id', 'pw', 'redirect_uri'), array('client_id' => $consumer_key));
$r = dba::inArray($r);
if (DBM::is_result($r)) {
return new OAuthConsumer($r[0]['client_id'], $r[0]['pw'], $r[0]['redirect_uri']);
}
return null;
}
/**
* @param string $consumer consumer
* @param string $token_type type
* @param string $token token
* @return mixed
*/
public function lookup_token($consumer, $token_type, $token)
{
logger(__function__.":".$consumer.", ". $token_type.", ".$token);
$s = dba::select('tokens', array('id', 'secret', 'scope', 'expires', 'uid'), array('client_id' => $consumer->key, 'scope' => $token_type, 'id' => $token));
$r = dba::inArray($s);
if (DBM::is_result($r)) {
$ot=new OAuthToken($r[0]['id'], $r[0]['secret']);
$ot->scope = $r[0]['scope'];
$ot->expires = $r[0]['expires'];
$ot->uid = $r[0]['uid'];
return $ot;
}
return null;
}
/**
* @param string $consumer consumer
* @param string $token token
* @param string $nonce nonce
* @param string $timestamp timestamp
* @return mixed
*/
public function lookup_nonce($consumer, $token, $nonce, $timestamp)
{
$r = dba::select('tokens', ['id', 'secret'], ['client_id' => $consumer->key, 'id' => $nonce, 'expires' => $timestamp], ['limit' => 1]);
if (DBM::is_result($r)) {
return new OAuthToken($r['id'], $r['secret']);
}
return null;
}
/**
* @param string $consumer consumer
* @param string $callback optional, default null
* @return mixed
*/
public function new_request_token($consumer, $callback = null)
{
logger(__function__.":".$consumer.", ". $callback);
$key = self::genToken();
$sec = self::genToken();
if ($consumer->key) {
$k = $consumer->key;
} else {
$k = $consumer;
}
$r = dba::insert(
'tokens',
array(
'id' => $key,
'secret' => $sec,
'client_id' => $k,
'scope' => 'request',
'expires' => UNIX_TIMESTAMP() + REQUEST_TOKEN_DURATION)
);
if (!$r) {
return null;
}
return new OAuthToken($key, $sec);
}
/**
* @param string $token token
* @param string $consumer consumer
* @param string $verifier optional, defult null
* @return object
*/
public function new_access_token($token, $consumer, $verifier = null)
{
logger(__function__.":".$token.", ". $consumer.", ". $verifier);
// return a new access token attached to this consumer
// for the user associated with this token if the request token
// is authorized
// should also invalidate the request token
$ret = null;
// get user for this verifier
$uverifier = Config::get("oauth", $verifier);
logger(__function__.":".$verifier.",".$uverifier);
if (is_null($verifier) || ($uverifier!==false)) {
$key = self::genToken();
$sec = self::genToken();
$r = dba::insert(
'tokens',
array(
'id' => $key,
'secret' => $sec,
'client_id' => $consumer->key,
'scope' => 'access',
'expires' => UNIX_TIMESTAMP() + ACCESS_TOKEN_DURATION,
'uid' => $uverifier)
);
if ($r) {
$ret = new OAuthToken($key, $sec);
}
}
dba::delete('tokens', array('id' => $token->key));
if (!is_null($ret) && !is_null($uverifier)) {
Config::delete("oauth", $verifier);
}
return $ret;
}
}

View file

@ -15,6 +15,7 @@ use Friendica\Core\Cache;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Object\Profile; use Friendica\Object\Profile;
use Friendica\Protocol\Email;
use Friendica\Util\XML; use Friendica\Util\XML;
use dba; use dba;
@ -22,7 +23,6 @@ use DomXPath;
use DOMDocument; use DOMDocument;
require_once 'include/feed.php'; require_once 'include/feed.php';
require_once 'include/email.php';
require_once 'include/network.php'; require_once 'include/network.php';
/** /**
@ -1517,16 +1517,16 @@ class Probe
$r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1", intval($uid)); $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1", intval($uid));
if (DBM::is_result($x) && DBM::is_result($r)) { if (DBM::is_result($x) && DBM::is_result($r)) {
$mailbox = construct_mailbox_name($r[0]); $mailbox = Email::constructMailboxName($r[0]);
$password = ''; $password = '';
openssl_private_decrypt(hex2bin($r[0]['pass']), $password, $x[0]['prvkey']); openssl_private_decrypt(hex2bin($r[0]['pass']), $password, $x[0]['prvkey']);
$mbox = email_connect($mailbox, $r[0]['user'], $password); $mbox = Email::connect($mailbox, $r[0]['user'], $password);
if (!mbox) { if (!mbox) {
return false; return false;
} }
} }
$msgs = email_poll($mbox, $uri); $msgs = Email::poll($mbox, $uri);
logger('searching '.$uri.', '.count($msgs).' messages found.', LOGGER_DEBUG); logger('searching '.$uri.', '.count($msgs).' messages found.', LOGGER_DEBUG);
if (!count($msgs)) { if (!count($msgs)) {
@ -1546,7 +1546,7 @@ class Probe
$data["notify"] = 'smtp '.random_string(); $data["notify"] = 'smtp '.random_string();
$data["poll"] = 'email '.random_string(); $data["poll"] = 'email '.random_string();
$x = email_msg_meta($mbox, $msgs[0]); $x = Email::messageMeta($mbox, $msgs[0]);
if (stristr($x[0]->from, $uri)) { if (stristr($x[0]->from, $uri)) {
$adr = imap_rfc822_parse_adrlist($x[0]->from, ''); $adr = imap_rfc822_parse_adrlist($x[0]->from, '');
} elseif (stristr($x[0]->to, $uri)) { } elseif (stristr($x[0]->to, $uri)) {

View file

@ -17,6 +17,7 @@ use Friendica\Object\Photo;
use Friendica\Protocol\Diaspora; use Friendica\Protocol\Diaspora;
use Friendica\Protocol\DFRN; use Friendica\Protocol\DFRN;
use Friendica\Protocol\OStatus; use Friendica\Protocol\OStatus;
use Friendica\Protocol\Salmon;
use dba; use dba;
require_once 'boot.php'; require_once 'boot.php';
@ -27,6 +28,52 @@ require_once 'include/text.php';
*/ */
class Contact extends BaseObject class Contact extends BaseObject
{ {
/**
* Creates the self-contact for the provided user id
*
* @param int $uid
* @return bool Operation success
*/
public static function createSelfFromUserId($uid)
{
// Only create the entry if it doesn't exist yet
if (dba::exists('contact', ['uid' => intval($uid), 'self'])) {
return true;
}
$user = dba::select('user', ['uid', 'username', 'nickname'], ['uid' => intval($uid)], ['limit' => 1]);
if (!DBM::is_result($user)) {
return false;
}
$return = dba::insert('contact', [
'uid' => $user['uid'],
'created' => datetime_convert(),
'self' => 1,
'name' => $user['username'],
'nick' => $user['nickname'],
'photo' => System::baseUrl() . '/photo/profile/' . $user['uid'] . '.jpg',
'thumb' => System::baseUrl() . '/photo/avatar/' . $user['uid'] . '.jpg',
'micro' => System::baseUrl() . '/photo/micro/' . $user['uid'] . '.jpg',
'blocked' => 0,
'pending' => 0,
'url' => System::baseUrl() . '/profile/' . $user['nickname'],
'nurl' => normalise_link(System::baseUrl() . '/profile/' . $user['nickname']),
'addr' => $user['nickname'] . '@' . substr(System::baseUrl(), strpos(System::baseUrl(), '://') + 3),
'request' => System::baseUrl() . '/dfrn_request/' . $user['nickname'],
'notify' => System::baseUrl() . '/dfrn_notify/' . $user['nickname'],
'poll' => System::baseUrl() . '/dfrn_poll/' . $user['nickname'],
'confirm' => System::baseUrl() . '/dfrn_confirm/' . $user['nickname'],
'poco' => System::baseUrl() . '/poco/' . $user['nickname'],
'name-date' => datetime_convert(),
'uri-date' => datetime_convert(),
'avatar-date' => datetime_convert(),
'closeness' => 0
]);
return $return;
}
/** /**
* @brief Marks a contact for removal * @brief Marks a contact for removal
* *
@ -71,8 +118,7 @@ class Contact extends BaseObject
$slap = OStatus::salmon($item, $user); $slap = OStatus::salmon($item, $user);
if ((x($contact, 'notify')) && (strlen($contact['notify']))) { if ((x($contact, 'notify')) && (strlen($contact['notify']))) {
require_once 'include/salmon.php'; Salmon::slapper($user, $contact['notify'], $slap);
slapper($user, $contact['notify'], $slap);
} }
} elseif ($contact['network'] === NETWORK_DIASPORA) { } elseif ($contact['network'] === NETWORK_DIASPORA) {
Diaspora::sendUnshare($user, $contact); Diaspora::sendUnshare($user, $contact);
@ -95,8 +141,8 @@ class Contact extends BaseObject
*/ */
public static function markForArchival(array $contact) public static function markForArchival(array $contact)
{ {
// Contact already archived, nothing to do // Contact already archived or "self" contact? => nothing to do
if ($contact['archive']) { if ($contact['archive'] || $contact['self']) {
return; return;
} }
@ -104,7 +150,7 @@ class Contact extends BaseObject
dba::update('contact', array('term-date' => datetime_convert()), array('id' => $contact['id'])); dba::update('contact', array('term-date' => datetime_convert()), array('id' => $contact['id']));
if ($contact['url'] != '') { if ($contact['url'] != '') {
dba::update('contact', array('term-date' => datetime_convert()), array('`nurl` = ? AND `term-date` <= ?', normalise_link($contact['url']), NULL_DATE)); dba::update('contact', array('term-date' => datetime_convert()), array('`nurl` = ? AND `term-date` <= ? AND NOT `self`', normalise_link($contact['url']), NULL_DATE));
} }
} else { } else {
/* @todo /* @todo
@ -123,7 +169,7 @@ class Contact extends BaseObject
dba::update('contact', array('archive' => 1), array('id' => $contact['id'])); dba::update('contact', array('archive' => 1), array('id' => $contact['id']));
if ($contact['url'] != '') { if ($contact['url'] != '') {
dba::update('contact', array('archive' => 1), array('nurl' => normalise_link($contact['url']))); dba::update('contact', array('archive' => 1), array('nurl' => normalise_link($contact['url']), 'self' => false));
} }
} }
} }
@ -139,7 +185,7 @@ class Contact extends BaseObject
*/ */
public static function unmarkForArchival(array $contact) public static function unmarkForArchival(array $contact)
{ {
$condition = array('`id` = ? AND (`term-date` > ? OR `archive`)', $contact[`id`], NULL_DATE); $condition = array('`id` = ? AND (`term-date` > ? OR `archive`)', $contact['id'], NULL_DATE);
$exists = dba::exists('contact', $condition); $exists = dba::exists('contact', $condition);
// We don't need to update, we never marked this contact for archival // We don't need to update, we never marked this contact for archival
@ -822,7 +868,33 @@ class Contact extends BaseObject
} }
/** /**
* @brief Updates the avatar links in a contact only if needed * @brief Blocks a contact
*
* @param int $uid
* @return bool
*/
public static function block($uid)
{
$return = dba::update('contact', ['blocked' => true], ['id' => $uid]);
return $return;
}
/**
* @brief Unblocks a contact
*
* @param int $uid
* @return bool
*/
public static function unblock($uid)
{
$return = dba::update('contact', ['blocked' => false], ['id' => $uid]);
return $return;
}
/**
* @brief Updates the avatar links in a contact only if needed
* *
* @param string $avatar Link to avatar picture * @param string $avatar Link to avatar picture
* @param int $uid User id of contact owner * @param int $uid User id of contact owner

View file

@ -5,6 +5,7 @@
namespace Friendica\Object; namespace Friendica\Object;
use Friendica\BaseObject; use Friendica\BaseObject;
use Friendica\Content\Feature;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
use Friendica\Database\DBM; use Friendica\Database\DBM;
@ -161,7 +162,7 @@ class Item extends BaseObject
$drop = array( $drop = array(
'dropping' => $dropping, 'dropping' => $dropping,
'pagedrop' => ((feature_enabled($conv->getProfileOwner(), 'multi_delete')) ? $item['pagedrop'] : ''), 'pagedrop' => ((Feature::isEnabled($conv->getProfileOwner(), 'multi_delete')) ? $item['pagedrop'] : ''),
'select' => t('Select'), 'select' => t('Select'),
'delete' => t('Delete'), 'delete' => t('Delete'),
); );
@ -279,7 +280,7 @@ class Item extends BaseObject
} }
$tagger = ''; $tagger = '';
if (feature_enabled($conv->getProfileOwner(), 'commtag')) { if (Feature::isEnabled($conv->getProfileOwner(), 'commtag')) {
$tagger = array( $tagger = array(
'add' => t("add tag"), 'add' => t("add tag"),
'class' => "", 'class' => "",
@ -293,7 +294,7 @@ class Item extends BaseObject
if ($conv->isWritable()) { if ($conv->isWritable()) {
$buttons = array( $buttons = array(
'like' => array( t("I like this \x28toggle\x29"), t("like")), 'like' => array( t("I like this \x28toggle\x29"), t("like")),
'dislike' => ((feature_enabled($conv->getProfileOwner(), 'dislike')) ? array( t("I don't like this \x28toggle\x29"), t("dislike")) : ''), 'dislike' => ((Feature::isEnabled($conv->getProfileOwner(), 'dislike')) ? array( t("I don't like this \x28toggle\x29"), t("dislike")) : ''),
); );
if ($shareable) { if ($shareable) {
$buttons['share'] = array( t('Share this'), t('share')); $buttons['share'] = array( t('Share this'), t('share'));
@ -378,12 +379,12 @@ class Item extends BaseObject
'owner_photo' => $a->remove_baseurl(proxy_url($item['owner-thumb'], false, PROXY_SIZE_THUMB)), 'owner_photo' => $a->remove_baseurl(proxy_url($item['owner-thumb'], false, PROXY_SIZE_THUMB)),
'owner_name' => htmlentities($owner_name_e), 'owner_name' => htmlentities($owner_name_e),
'plink' => get_plink($item), 'plink' => get_plink($item),
'edpost' => ((feature_enabled($conv->getProfileOwner(), 'edit_posts')) ? $edpost : ''), 'edpost' => ((Feature::isEnabled($conv->getProfileOwner(), 'edit_posts')) ? $edpost : ''),
'isstarred' => $isstarred, 'isstarred' => $isstarred,
'star' => ((feature_enabled($conv->getProfileOwner(), 'star_posts')) ? $star : ''), 'star' => ((Feature::isEnabled($conv->getProfileOwner(), 'star_posts')) ? $star : ''),
'ignore' => ((feature_enabled($conv->getProfileOwner(), 'ignore_posts')) ? $ignore : ''), 'ignore' => ((Feature::isEnabled($conv->getProfileOwner(), 'ignore_posts')) ? $ignore : ''),
'tagger' => $tagger, 'tagger' => $tagger,
'filer' => ((feature_enabled($conv->getProfileOwner(), 'filing')) ? $filer : ''), 'filer' => ((Feature::isEnabled($conv->getProfileOwner(), 'filing')) ? $filer : ''),
'drop' => $drop, 'drop' => $drop,
'vote' => $buttons, 'vote' => $buttons,
'like' => $responses['like']['output'], 'like' => $responses['like']['output'],
@ -791,7 +792,7 @@ class Item extends BaseObject
'$edimg' => t('Image'), '$edimg' => t('Image'),
'$edurl' => t('Link'), '$edurl' => t('Link'),
'$edvideo' => t('Video'), '$edvideo' => t('Video'),
'$preview' => ((feature_enabled($conv->getProfileOwner(), 'preview')) ? t('Preview') : ''), '$preview' => ((Feature::isEnabled($conv->getProfileOwner(), 'preview')) ? t('Preview') : ''),
'$indent' => $indent, '$indent' => $indent,
'$sourceapp' => t($a->sourcename), '$sourceapp' => t($a->sourcename),
'$ww' => (($conv->getMode() === 'network') ? $ww : ''), '$ww' => (($conv->getMode() === 'network') ? $ww : ''),

View file

@ -1339,10 +1339,6 @@ class Diaspora
if ($r) { if ($r) {
$cid = $r[0]["id"]; $cid = $r[0]["id"];
$network = $r[0]["network"]; $network = $r[0]["network"];
// We are receiving content from a user that possibly is about to be terminated
// This means the user is vital, so we remove a possible termination date.
Contact::unmarkForArchival($r[0]);
} else { } else {
$cid = $contact["id"]; $cid = $contact["id"];
$network = NETWORK_DIASPORA; $network = NETWORK_DIASPORA;

377
src/Protocol/Email.php Normal file
View file

@ -0,0 +1,377 @@
<?php
/**
* @file src/Protocol/Email.php
*/
namespace Friendica\Protocol;
require_once 'include/html2plain.php';
require_once 'include/msgclean.php';
require_once 'include/quoteconvert.php';
/**
* @brief Email class
*/
class Email
{
/**
* @param string $mailbox The mailbox name
* @param string $username The username
* @param string $password The password
* @return object
*/
public static function connect($mailbox, $username, $password)
{
if (! function_exists('imap_open')) {
return false;
}
$mbox = @imap_open($mailbox, $username, $password);
return $mbox;
}
/**
* @param object $mbox mailbox
* @param string $email_addr email
* @return array
*/
public static function poll($mbox, $email_addr)
{
if (! ($mbox && $email_addr))
return array();
$search1 = @imap_search($mbox, 'FROM "' . $email_addr . '"', SE_UID);
if (!$search1) {
$search1 = array();
} else {
logger("Found mails from ".$email_addr, LOGGER_DEBUG);
}
$search2 = @imap_search($mbox, 'TO "' . $email_addr . '"', SE_UID);
if (!$search2) {
$search2 = array();
} else {
logger("Found mails to ".$email_addr, LOGGER_DEBUG);
}
$search3 = @imap_search($mbox, 'CC "' . $email_addr . '"', SE_UID);
if (!$search3) {
$search3 = array();
} else {
logger("Found mails cc ".$email_addr, LOGGER_DEBUG);
}
$res = array_unique(array_merge($search1, $search2, $search3));
return $res;
}
/**
* @param array $mailacct mail account
* @return object
*/
public static function constructMailboxName($mailacct)
{
$ret = '{' . $mailacct['server'] . ((intval($mailacct['port'])) ? ':' . $mailacct['port'] : '');
$ret .= (($mailacct['ssltype']) ? '/' . $mailacct['ssltype'] . '/novalidate-cert' : '');
$ret .= '}' . $mailacct['mailbox'];
return $ret;
}
/**
* @param object $mbox mailbox
* @param integer $uid user id
* @return mixed
*/
public static function messageMeta($mbox, $uid)
{
$ret = (($mbox && $uid) ? @imap_fetch_overview($mbox, $uid, FT_UID) : array(array())); // POSSIBLE CLEANUP --> array(array()) is probably redundant now
return (count($ret)) ? $ret : array();
}
/**
* @param object $mbox mailbox
* @param integer $uid user id
* @param string $reply reply
* @return array
*/
public static function getMessage($mbox, $uid, $reply)
{
$ret = array();
$struc = (($mbox && $uid) ? @imap_fetchstructure($mbox, $uid, FT_UID) : null);
if (! $struc) {
return $ret;
}
if (! $struc->parts) {
$ret['body'] = self::messageGetPart($mbox, $uid, $struc, 0, 'html');
$html = $ret['body'];
if (trim($ret['body']) == '') {
$ret['body'] = self::messageGetPart($mbox, $uid, $struc, 0, 'plain');
} else {
$ret['body'] = html2bbcode($ret['body']);
}
} else {
$text = '';
$html = '';
foreach ($struc->parts as $ptop => $p) {
$x = self::messageGetPart($mbox, $uid, $p, $ptop + 1, 'plain');
if ($x) {
$text .= $x;
}
$x = self::messageGetPart($mbox, $uid, $p, $ptop + 1, 'html');
if ($x) {
$html .= $x;
}
}
if (trim($html) != '') {
$ret['body'] = html2bbcode($html);
} else {
$ret['body'] = $text;
}
}
$ret['body'] = removegpg($ret['body']);
$msg = removesig($ret['body']);
$ret['body'] = $msg['body'];
$ret['body'] = convertquote($ret['body'], $reply);
if (trim($html) != '') {
$ret['body'] = removelinebreak($ret['body']);
}
$ret['body'] = unifyattributionline($ret['body']);
return $ret;
}
// At the moment - only return plain/text.
// Later we'll repackage inline images as data url's and make the HTML safe
/**
* @param object $mbox mailbox
* @param integer $uid user id
* @param object $p parts
* @param integer $partno part number
* @param string $subtype sub type
* @return string
*/
private static function messageGetPart($mbox, $uid, $p, $partno, $subtype)
{
// $partno = '1', '2', '2.1', '2.1.3', etc for multipart, 0 if simple
global $htmlmsg,$plainmsg,$charset,$attachments;
//echo $partno."\n";
// DECODE DATA
$data = ($partno)
? @imap_fetchbody($mbox, $uid, $partno, FT_UID|FT_PEEK)
: @imap_body($mbox, $uid, FT_UID|FT_PEEK);
// Any part may be encoded, even plain text messages, so check everything.
if ($p->encoding==4) {
$data = quoted_printable_decode($data);
} elseif ($p->encoding==3) {
$data = base64_decode($data);
}
// PARAMETERS
// get all parameters, like charset, filenames of attachments, etc.
$params = array();
if ($p->parameters) {
foreach ($p->parameters as $x) {
$params[strtolower($x->attribute)] = $x->value;
}
}
if (isset($p->dparameters) && $p->dparameters) {
foreach ($p->dparameters as $x) {
$params[strtolower($x->attribute)] = $x->value;
}
}
// ATTACHMENT
// Any part with a filename is an attachment,
// so an attached text file (type 0) is not mistaken as the message.
if ((isset($params['filename']) && $params['filename']) || (isset($params['name']) && $params['name'])) {
// filename may be given as 'Filename' or 'Name' or both
$filename = ($params['filename'])? $params['filename'] : $params['name'];
// filename may be encoded, so see imap_mime_header_decode()
$attachments[$filename] = $data; // this is a problem if two files have same name
}
// TEXT
if ($p->type == 0 && $data) {
// Messages may be split in different parts because of inline attachments,
// so append parts together with blank row.
if (strtolower($p->subtype)==$subtype) {
$data = iconv($params['charset'], 'UTF-8//IGNORE', $data);
return (trim($data) ."\n\n");
} else {
$data = '';
}
// $htmlmsg .= $data ."<br><br>";
$charset = $params['charset']; // assume all parts are same charset
}
// EMBEDDED MESSAGE
// Many bounce notifications embed the original message as type 2,
// but AOL uses type 1 (multipart), which is not handled here.
// There are no PHP functions to parse embedded messages,
// so this just appends the raw source to the main message.
// elseif ($p->type==2 && $data) {
// $plainmsg .= $data."\n\n";
// }
// SUBPART RECURSION
if (isset($p->parts) && $p->parts) {
$x = "";
foreach ($p->parts as $partno0 => $p2) {
$x .= self::messageGetPart($mbox, $uid, $p2, $partno . '.' . ($partno0+1), $subtype); // 1.2, 1.2.1, etc.
//if ($x) {
// return $x;
//}
}
return $x;
}
}
/**
* @param string $in_str in string
* @param string $charset character set
* @return string
*/
public static function encodeHeader($in_str, $charset)
{
$out_str = $in_str;
$need_to_convert = false;
for ($x = 0; $x < strlen($in_str); $x ++) {
if ((ord($in_str[$x]) == 0) || ((ord($in_str[$x]) > 128))) {
$need_to_convert = true;
}
}
if (! $need_to_convert) {
return $in_str;
}
if ($out_str && $charset) {
// define start delimimter, end delimiter and spacer
$end = "?=";
$start = "=?" . $charset . "?B?";
$spacer = $end . "\r\n " . $start;
// determine length of encoded text within chunks
// and ensure length is even
$length = 75 - strlen($start) - strlen($end);
/*
[EDIT BY danbrown AT php DOT net: The following
is a bugfix provided by (gardan AT gmx DOT de)
on 31-MAR-2005 with the following note:
"This means: $length should not be even,
but divisible by 4. The reason is that in
base64-encoding 3 8-bit-chars are represented
by 4 6-bit-chars. These 4 chars must not be
split between two encoded words, according
to RFC-2047.
*/
$length = $length - ($length % 4);
// encode the string and split it into chunks
// with spacers after each chunk
$out_str = base64_encode($out_str);
$out_str = chunk_split($out_str, $length, $spacer);
// remove trailing spacer and
// add start and end delimiters
$spacer = preg_quote($spacer, '/');
$out_str = preg_replace("/" . $spacer . "$/", "", $out_str);
$out_str = $start . $out_str . $end;
}
return $out_str;
}
/**
* Function send is used by NETWORK_EMAIL and NETWORK_EMAIL2 code
* (not to notify the user, but to send items to email contacts)
*
* @param string $addr address
* @param string $subject subject
* @param string $headers headers
* @param array $item item
*
* @return void
*
* @todo This could be changed to use the Emailer class
*/
public static function send($addr, $subject, $headers, $item)
{
//$headers .= 'MIME-Version: 1.0' . "\n";
//$headers .= 'Content-Type: text/html; charset=UTF-8' . "\n";
//$headers .= 'Content-Type: text/plain; charset=UTF-8' . "\n";
//$headers .= 'Content-Transfer-Encoding: 8bit' . "\n\n";
$part = uniqid("", true);
$html = prepare_body($item);
$headers .= "Mime-Version: 1.0\n";
$headers .= 'Content-Type: multipart/alternative; boundary="=_'.$part.'"'."\n\n";
$body = "\n--=_".$part."\n";
$body .= "Content-Transfer-Encoding: 8bit\n";
$body .= "Content-Type: text/plain; charset=utf-8; format=flowed\n\n";
$body .= html2plain($html)."\n";
$body .= "--=_".$part."\n";
$body .= "Content-Transfer-Encoding: 8bit\n";
$body .= "Content-Type: text/html; charset=utf-8\n\n";
$body .= '<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">'.$html."</body></html>\n";
$body .= "--=_".$part."--";
//$message = '<html><body>' . $html . '</body></html>';
//$message = html2plain($html);
logger('notifier: email delivery to ' . $addr);
mail($addr, $subject, $body, $headers);
}
/**
* @param string $iri string
* @return string
*/
public static function iri2msgid($iri)
{
if (!strpos($iri, "@")) {
$msgid = preg_replace("/urn:(\S+):(\S+)\.(\S+):(\d+):(\S+)/i", "urn!$1!$4!$5@$2.$3", $iri);
} else {
$msgid = $iri;
}
return($msgid);
}
/**
* @param string $msgid msgid
* @return string
*/
public static function msgid2iri($msgid)
{
if (strpos($msgid, "@")) {
$iri = preg_replace("/urn!(\S+)!(\d+)!(\S+)@(\S+)\.(\S+)/i", "urn:$1:$4.$5:$2:$3", $msgid);
} else {
$iri = $msgid;
}
return($iri);
}
}

View file

@ -151,11 +151,8 @@ class OStatus
// Only update the contacts if it is an OStatus contact // Only update the contacts if it is an OStatus contact
if ($r && ($r['id'] > 0) && !$onlyfetch && ($contact["network"] == NETWORK_OSTATUS)) { if ($r && ($r['id'] > 0) && !$onlyfetch && ($contact["network"] == NETWORK_OSTATUS)) {
// This contact is vital, so we awake it from the dead
Contact::unmarkForArchival($contact);
// Update contact data // Update contact data
$current = $contact; $current = $contact;
unset($current['name-date']); unset($current['name-date']);

View file

@ -1343,14 +1343,17 @@ class PortableContact
// Disvover Mastodon servers // Disvover Mastodon servers
if (!Config::get('system', 'ostatus_disabled')) { if (!Config::get('system', 'ostatus_disabled')) {
$serverdata = fetch_url("https://instances.mastodon.xyz/instances.json"); $accesstoken = Config::get('system', 'instances_social_key');
if (!empty($accesstoken)) {
if ($serverdata) { $api = 'https://instances.social/api/1.0/instances/list?count=0';
$servers = json_decode($serverdata); $header = array('Authorization: Bearer '.$accesstoken);
$serverdata = z_fetch_url($api, false, $redirects, ['headers' => $header]);
foreach ($servers as $server) { if ($serverdata['success']) {
$url = (is_null($server->https_score) ? 'http' : 'https').'://'.$server->name; $servers = json_decode($serverdata['body']);
Worker::add(PRIORITY_LOW, "DiscoverPoCo", "server", $url); foreach ($servers->instances as $server) {
$url = (is_null($server->https_score) ? 'http' : 'https').'://'.$server->name;
Worker::add(PRIORITY_LOW, "DiscoverPoCo", "server", $url);
}
} }
} }
} }

204
src/Protocol/Salmon.php Normal file
View file

@ -0,0 +1,204 @@
<?php
/**
* @file src/Protocol/Salmon.php
*/
namespace Friendica\Protocol;
use Friendica\Network\Probe;
use Friendica\Util\XML;
require_once 'include/crypto.php';
/**
* @brief Salmon Protocol class
* The Salmon Protocol is a message exchange protocol running over HTTP designed to decentralize commentary
* and annotations made against newsfeed articles such as blog posts.
*/
class Salmon
{
/**
* @param string $uri Uniform Resource Identifier
* @param string $keyhash encoded key
* @return mixed
*/
public static function getKey($uri, $keyhash)
{
$ret = array();
logger('Fetching salmon key for '.$uri);
$arr = Probe::lrdd($uri);
if (is_array($arr)) {
foreach ($arr as $a) {
if ($a['@attributes']['rel'] === 'magic-public-key') {
$ret[] = $a['@attributes']['href'];
}
}
} else {
return '';
}
// We have found at least one key URL
// If it's inline, parse it - otherwise get the key
if (count($ret) > 0) {
for ($x = 0; $x < count($ret); $x ++) {
if (substr($ret[$x], 0, 5) === 'data:') {
if (strstr($ret[$x], ',')) {
$ret[$x] = substr($ret[$x], strpos($ret[$x], ',') + 1);
} else {
$ret[$x] = substr($ret[$x], 5);
}
} elseif (normalise_link($ret[$x]) == 'http://') {
$ret[$x] = fetch_url($ret[$x]);
}
}
}
logger('Key located: ' . print_r($ret, true));
if (count($ret) == 1) {
// We only found one one key so we don't care if the hash matches.
// If it's the wrong key we'll find out soon enough because
// message verification will fail. This also covers some older
// software which don't supply a keyhash. As long as they only
// have one key we'll be right.
return $ret[0];
} else {
foreach ($ret as $a) {
$hash = base64url_encode(hash('sha256', $a));
if ($hash == $keyhash) {
return $a;
}
}
}
return '';
}
/**
* @param array $owner owner
* @param string $url url
* @param string $slap slap
* @return integer
*/
public static function slapper($owner, $url, $slap)
{
// does contact have a salmon endpoint?
if (! strlen($url)) {
return;
}
if (! $owner['sprvkey']) {
logger(sprintf("user '%s' (%d) does not have a salmon private key. Send failed.",
$owner['username'], $owner['uid']));
return;
}
logger('slapper called for '.$url.'. Data: ' . $slap);
// create a magic envelope
$data = base64url_encode($slap);
$data_type = 'application/atom+xml';
$encoding = 'base64url';
$algorithm = 'RSA-SHA256';
$keyhash = base64url_encode(hash('sha256', salmon_key($owner['spubkey'])), true);
$precomputed = '.' . base64url_encode($data_type) . '.' . base64url_encode($encoding) . '.' . base64url_encode($algorithm);
// GNU Social format
$signature = base64url_encode(rsa_sign($data . $precomputed, $owner['sprvkey']));
// Compliant format
$signature2 = base64url_encode(rsa_sign(str_replace('=', '', $data . $precomputed), $owner['sprvkey']));
// Old Status.net format
$signature3 = base64url_encode(rsa_sign($data, $owner['sprvkey']));
// At first try the non compliant method that works for GNU Social
$xmldata = array("me:env" => array("me:data" => $data,
"@attributes" => array("type" => $data_type),
"me:encoding" => $encoding,
"me:alg" => $algorithm,
"me:sig" => $signature,
"@attributes2" => array("key_id" => $keyhash)));
$namespaces = array("me" => "http://salmon-protocol.org/ns/magic-env");
$salmon = XML::fromArray($xmldata, $xml, false, $namespaces);
// slap them
post_url($url, $salmon, array(
'Content-type: application/magic-envelope+xml',
'Content-length: ' . strlen($salmon)
));
$a = get_app();
$return_code = $a->get_curl_code();
// check for success, e.g. 2xx
if ($return_code > 299) {
logger('GNU Social salmon failed. Falling back to compliant mode');
// Now try the compliant mode that normally isn't used for GNU Social
$xmldata = array("me:env" => array("me:data" => $data,
"@attributes" => array("type" => $data_type),
"me:encoding" => $encoding,
"me:alg" => $algorithm,
"me:sig" => $signature2,
"@attributes2" => array("key_id" => $keyhash)));
$namespaces = array("me" => "http://salmon-protocol.org/ns/magic-env");
$salmon = XML::fromArray($xmldata, $xml, false, $namespaces);
// slap them
post_url($url, $salmon, array(
'Content-type: application/magic-envelope+xml',
'Content-length: ' . strlen($salmon)
));
$return_code = $a->get_curl_code();
}
if ($return_code > 299) {
logger('compliant salmon failed. Falling back to old status.net');
// Last try. This will most likely fail as well.
$xmldata = array("me:env" => array("me:data" => $data,
"@attributes" => array("type" => $data_type),
"me:encoding" => $encoding,
"me:alg" => $algorithm,
"me:sig" => $signature3,
"@attributes2" => array("key_id" => $keyhash)));
$namespaces = array("me" => "http://salmon-protocol.org/ns/magic-env");
$salmon = XML::fromArray($xmldata, $xml, false, $namespaces);
// slap them
post_url($url, $salmon, array(
'Content-type: application/magic-envelope+xml',
'Content-length: ' . strlen($salmon))
);
$return_code = $a->get_curl_code();
}
logger('slapper for '.$url.' returned ' . $return_code);
if (! $return_code) {
return -1;
}
if (($return_code == 503) && (stristr($a->get_curl_headers(), 'retry-after'))) {
return -1;
}
return (($return_code >= 200) && ($return_code < 300)) ? 0 : 1;
}
}

View file

@ -5,11 +5,10 @@
namespace Friendica\Util; namespace Friendica\Util;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
use Friendica\Protocol\Email;
require_once 'include/email.php';
/** /**
* @breif class to handle emailing * @brief class to handle emailing
*/ */
class Emailer class Emailer
{ {
@ -38,8 +37,8 @@ class Emailer
$email_textonly = PConfig::get($params['uid'], "system", "email_textonly"); $email_textonly = PConfig::get($params['uid'], "system", "email_textonly");
} }
$fromName = email_header_encode(html_entity_decode($params['fromName'], ENT_QUOTES, 'UTF-8'), 'UTF-8'); $fromName = Email::encodeHeader(html_entity_decode($params['fromName'], ENT_QUOTES, 'UTF-8'), 'UTF-8');
$messageSubject = email_header_encode(html_entity_decode($params['messageSubject'], ENT_QUOTES, 'UTF-8'), 'UTF-8'); $messageSubject = Email::encodeHeader(html_entity_decode($params['messageSubject'], ENT_QUOTES, 'UTF-8'), 'UTF-8');
// generate a mime boundary // generate a mime boundary
$mimeBoundary =rand(0, 9)."-" $mimeBoundary =rand(0, 9)."-"

72
src/Util/Pidfile.php Normal file
View file

@ -0,0 +1,72 @@
<?php
/**
* @file src/Util/Pidfile.php
*/
namespace Friendica\Util;
/**
* @brief Pidfile class
*/
class Pidfile
{
private $file;
private $running;
/**
* @param string $dir path
* @param string $name filename
* @return void
*/
public function __construct($dir, $name)
{
$this->_file = "$dir/$name.pid";
if (file_exists($this->_file)) {
$pid = trim(@file_get_contents($this->file));
if (($pid != "") && posix_kill($pid, 0)) {
$this->running = true;
}
}
if (! $this->running) {
$pid = getmypid();
file_put_contents($this->file, $pid);
}
}
/**
* @return void
*/
public function __destruct()
{
if ((! $this->running) && file_exists($this->file)) {
@unlink($this->file);
}
}
/**
* @return boolean
*/
public static function isRunning()
{
return self::$running;
}
/**
* @return object
*/
public static function runningTime()
{
return time() - @filectime(self::$file);
}
/**
* @return boolean
*/
public static function kill()
{
if (file_exists(self::$file)) {
return posix_kill(file_get_contents(self::$file), SIGTERM);
}
}
}

View file

@ -153,115 +153,114 @@ Class Cron {
: '' : ''
); );
$contacts = q("SELECT `contact`.`id` FROM `user` $contacts = q("SELECT `contact`.`id`, `contact`.`nick`, `contact`.`name`, `contact`.`network`, `contact`.`archive`,
`contact`.`last-update`, `contact`.`priority`, `contact`.`rel`, `contact`.`subhub`
FROM `user`
STRAIGHT_JOIN `contact` STRAIGHT_JOIN `contact`
ON `contact`.`uid` = `user`.`uid` AND `contact`.`rel` IN (%d, %d) AND `contact`.`poll` != '' ON `contact`.`uid` = `user`.`uid` AND `contact`.`poll` != ''
AND `contact`.`network` IN ('%s', '%s', '%s', '%s', '%s', '%s') $sql_extra AND `contact`.`network` IN ('%s', '%s', '%s', '%s', '%s') $sql_extra
AND NOT `contact`.`self` AND NOT `contact`.`blocked` AND NOT `contact`.`readonly` AND NOT `contact`.`self` AND NOT `contact`.`blocked`
AND NOT `contact`.`archive` WHERE NOT `user`.`account_expired` AND NOT `user`.`account_removed` $abandon_sql",
WHERE NOT `user`.`account_expired` AND NOT `user`.`account_removed` $abandon_sql ORDER BY RAND()",
intval(CONTACT_IS_SHARING),
intval(CONTACT_IS_FRIEND),
dbesc(NETWORK_DFRN), dbesc(NETWORK_DFRN),
dbesc(NETWORK_ZOT),
dbesc(NETWORK_OSTATUS), dbesc(NETWORK_OSTATUS),
dbesc(NETWORK_DIASPORA),
dbesc(NETWORK_FEED), dbesc(NETWORK_FEED),
dbesc(NETWORK_MAIL), dbesc(NETWORK_MAIL)
dbesc(NETWORK_MAIL2)
); );
if (!DBM::is_result($contacts)) { if (!DBM::is_result($contacts)) {
return; return;
} }
foreach ($contacts as $c) { foreach ($contacts as $contact) {
$res = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", if ($manual_id) {
intval($c['id']) $contact['last-update'] = NULL_DATE;
);
if (!DBM::is_result($res)) {
continue;
} }
foreach ($res as $contact) { // Friendica and OStatus are checked once a day
if (in_array($contact['network'], array(NETWORK_DFRN, NETWORK_OSTATUS))) {
$xml = false; $contact['priority'] = 2;
if ($manual_id) {
$contact['last-update'] = NULL_DATE;
}
if (in_array($contact['network'], array(NETWORK_DFRN, NETWORK_ZOT, NETWORK_OSTATUS))) {
$contact['priority'] = 2;
}
if ($contact['subhub'] && in_array($contact['network'], array(NETWORK_DFRN, NETWORK_ZOT, NETWORK_OSTATUS))) {
/*
* We should be getting everything via a hub. But just to be sure, let's check once a day.
* (You can make this more or less frequent if desired by setting 'pushpoll_frequency' appropriately)
* This also lets us update our subscription to the hub, and add or replace hubs in case it
* changed. We will only update hubs once a day, regardless of 'pushpoll_frequency'.
*/
$poll_interval = Config::get('system', 'pushpoll_frequency');
$contact['priority'] = (($poll_interval !== false) ? intval($poll_interval) : 3);
}
if (($contact['priority'] >= 0) && !$force) {
$update = false;
$t = $contact['last-update'];
/*
* Based on $contact['priority'], should we poll this site now? Or later?
*/
switch ($contact['priority']) {
case 5:
if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 month")) {
$update = true;
}
break;
case 4:
if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 week")) {
$update = true;
}
break;
case 3:
if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 day")) {
$update = true;
}
break;
case 2:
if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 12 hour")) {
$update = true;
}
break;
case 1:
if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 hour")) {
$update = true;
}
break;
case 0:
default:
if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + ".$min_poll_interval." minute")) {
$update = true;
}
break;
}
if (!$update) {
continue;
}
}
logger("Polling " . $contact["network"] . " " . $contact["id"] . " " . $contact["nick"] . " " . $contact["name"]);
if (($contact['network'] == NETWORK_FEED) && ($contact['priority'] <= 3)) {
$priority = PRIORITY_MEDIUM;
} else {
$priority = PRIORITY_LOW;
}
Worker::add(array('priority' => $priority, 'dont_fork' => true), 'OnePoll', (int)$contact['id']);
} }
if ($contact['subhub'] && in_array($contact['network'], array(NETWORK_DFRN, NETWORK_OSTATUS))) {
/*
* We should be getting everything via a hub. But just to be sure, let's check once a day.
* (You can make this more or less frequent if desired by setting 'pushpoll_frequency' appropriately)
* This also lets us update our subscription to the hub, and add or replace hubs in case it
* changed. We will only update hubs once a day, regardless of 'pushpoll_frequency'.
*/
$poll_interval = Config::get('system', 'pushpoll_frequency');
$contact['priority'] = (!is_null($poll_interval) ? intval($poll_interval) : 3);
}
// Check Diaspora contacts or followers once a week
if (($contact["network"] == NETWORK_DIASPORA) || ($contact["rel"] == CONTACT_IS_FOLLOWER)) {
$contact['priority'] = 4;
}
// Check archived contacts once a month
if ($contact['archive']) {
$contact['priority'] = 5;
}
if (($contact['priority'] >= 0) && !$force) {
$update = false;
$t = $contact['last-update'];
/*
* Based on $contact['priority'], should we poll this site now? Or later?
*/
switch ($contact['priority']) {
case 5:
if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 month")) {
$update = true;
}
break;
case 4:
if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 week")) {
$update = true;
}
break;
case 3:
if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 day")) {
$update = true;
}
break;
case 2:
if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 12 hour")) {
$update = true;
}
break;
case 1:
if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 hour")) {
$update = true;
}
break;
case 0:
default:
if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + ".$min_poll_interval." minute")) {
$update = true;
}
break;
}
if (!$update) {
continue;
}
}
if (($contact['network'] == NETWORK_FEED) && ($contact['priority'] <= 3)) {
$priority = PRIORITY_MEDIUM;
} elseif ($contact['archive']) {
$priority = PRIORITY_NEGLIGIBLE;
} else {
$priority = PRIORITY_LOW;
}
logger("Polling " . $contact["network"] . " " . $contact["id"] . " " . $contact['priority'] . " " . $contact["nick"] . " " . $contact["name"]);
Worker::add(array('priority' => $priority, 'dont_fork' => true), 'OnePoll', (int)$contact['id']);
} }
} }
} }

View file

@ -1,4 +1,5 @@
<?php <?php
/** /**
* @file src/worker/CronJobs.php * @file src/worker/CronJobs.php
*/ */
@ -11,25 +12,27 @@ use Friendica\Core\Config;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Model\GlobalContact; use Friendica\Model\GlobalContact;
use Friendica\Network\Probe; use Friendica\Network\Probe;
use Friendica\Object\Contact;
use Friendica\Protocol\PortableContact; use Friendica\Protocol\PortableContact;
use dba; use dba;
class CronJobs { class CronJobs
public static function execute($command = ''){ {
public static function execute($command = '')
{
global $a; global $a;
require_once 'include/datetime.php'; require_once 'include/datetime.php';
require_once 'include/post_update.php'; require_once 'include/post_update.php';
require_once 'mod/nodeinfo.php'; require_once 'mod/nodeinfo.php';
require_once 'include/photos.php'; require_once 'include/photos.php';
require_once 'include/user.php';
// No parameter set? So return // No parameter set? So return
if ($command == '') { if ($command == '') {
return; return;
} }
logger("Starting cronjob ".$command, LOGGER_DEBUG); logger("Starting cronjob " . $command, LOGGER_DEBUG);
// Call possible post update functions // Call possible post update functions
// see include/post_update.php for more details // see include/post_update.php for more details
@ -78,7 +81,7 @@ class CronJobs {
return; return;
} }
logger("Xronjob ".$command." is unknown.", LOGGER_DEBUG); logger("Xronjob " . $command . " is unknown.", LOGGER_DEBUG);
return; return;
} }
@ -86,7 +89,8 @@ class CronJobs {
/** /**
* @brief Update the cached values for the number of photo albums per user * @brief Update the cached values for the number of photo albums per user
*/ */
private static function updatePhotoAlbums() { private static function updatePhotoAlbums()
{
$r = q("SELECT `uid` FROM `user` WHERE NOT `account_expired` AND NOT `account_removed`"); $r = q("SELECT `uid` FROM `user` WHERE NOT `account_expired` AND NOT `account_removed`");
if (!DBM::is_result($r)) { if (!DBM::is_result($r)) {
return; return;
@ -100,7 +104,8 @@ class CronJobs {
/** /**
* @brief Expire and remove user entries * @brief Expire and remove user entries
*/ */
private static function expireAndRemoveUsers() { private static function expireAndRemoveUsers()
{
// expire any expired accounts // expire any expired accounts
q("UPDATE user SET `account_expired` = 1 where `account_expired` = 0 q("UPDATE user SET `account_expired` = 1 where `account_expired` = 0
AND `account_expires_on` > '%s' AND `account_expires_on` > '%s'
@ -120,9 +125,9 @@ class CronJobs {
* *
* @param App $a * @param App $a
*/ */
private static function clearCache(App $a) { private static function clearCache(App $a)
{
$last = Config::get('system','cache_last_cleared'); $last = Config::get('system', 'cache_last_cleared');
if ($last) { if ($last) {
$next = $last + (3600); // Once per hour $next = $last + (3600); // Once per hour
@ -142,16 +147,16 @@ class CronJobs {
clear_cache(); clear_cache();
// clear cache for photos // clear cache for photos
clear_cache($a->get_basepath(), $a->get_basepath()."/photo"); clear_cache($a->get_basepath(), $a->get_basepath() . "/photo");
// clear smarty cache // clear smarty cache
clear_cache($a->get_basepath()."/view/smarty3/compiled", $a->get_basepath()."/view/smarty3/compiled"); clear_cache($a->get_basepath() . "/view/smarty3/compiled", $a->get_basepath() . "/view/smarty3/compiled");
// clear cache for image proxy // clear cache for image proxy
if (!Config::get("system", "proxy_disabled")) { if (!Config::get("system", "proxy_disabled")) {
clear_cache($a->get_basepath(), $a->get_basepath()."/proxy"); clear_cache($a->get_basepath(), $a->get_basepath() . "/proxy");
$cachetime = Config::get('system','proxy_cache_time'); $cachetime = Config::get('system', 'proxy_cache_time');
if (!$cachetime) { if (!$cachetime) {
$cachetime = PROXY_DEFAULT_TIME; $cachetime = PROXY_DEFAULT_TIME;
} }
@ -166,13 +171,13 @@ class CronJobs {
dba::delete('parsed_url', array("`created` < NOW() - INTERVAL 3 MONTH")); dba::delete('parsed_url', array("`created` < NOW() - INTERVAL 3 MONTH"));
// Maximum table size in megabyte // Maximum table size in megabyte
$max_tablesize = intval(Config::get('system','optimize_max_tablesize')) * 1000000; $max_tablesize = intval(Config::get('system', 'optimize_max_tablesize')) * 1000000;
if ($max_tablesize == 0) { if ($max_tablesize == 0) {
$max_tablesize = 100 * 1000000; // Default are 100 MB $max_tablesize = 100 * 1000000; // Default are 100 MB
} }
if ($max_tablesize > 0) { if ($max_tablesize > 0) {
// Minimum fragmentation level in percent // Minimum fragmentation level in percent
$fragmentation_level = intval(Config::get('system','optimize_fragmentation')) / 100; $fragmentation_level = intval(Config::get('system', 'optimize_fragmentation')) / 100;
if ($fragmentation_level == 0) { if ($fragmentation_level == 0) {
$fragmentation_level = 0.3; // Default value is 30% $fragmentation_level = 0.3; // Default value is 30%
} }
@ -194,7 +199,7 @@ class CronJobs {
// Calculate fragmentation // Calculate fragmentation
$fragmentation = $table["Data_free"] / ($table["Data_length"] + $table["Index_length"]); $fragmentation = $table["Data_free"] / ($table["Data_length"] + $table["Index_length"]);
logger("Table ".$table["Name"]." - Fragmentation level: ".round($fragmentation * 100, 2), LOGGER_DEBUG); logger("Table " . $table["Name"] . " - Fragmentation level: " . round($fragmentation * 100, 2), LOGGER_DEBUG);
// Don't optimize tables that needn't to be optimized // Don't optimize tables that needn't to be optimized
if ($fragmentation < $fragmentation_level) { if ($fragmentation < $fragmentation_level) {
@ -202,12 +207,12 @@ class CronJobs {
} }
// So optimize it // So optimize it
logger("Optimize Table ".$table["Name"], LOGGER_DEBUG); logger("Optimize Table " . $table["Name"], LOGGER_DEBUG);
q("OPTIMIZE TABLE `%s`", dbesc($table["Name"])); q("OPTIMIZE TABLE `%s`", dbesc($table["Name"]));
} }
} }
Config::set('system','cache_last_cleared', time()); Config::set('system', 'cache_last_cleared', time());
} }
/** /**
@ -215,8 +220,8 @@ class CronJobs {
* *
* @param App $a * @param App $a
*/ */
private static function repairDiaspora(App $a) { private static function repairDiaspora(App $a)
{
$starttime = time(); $starttime = time();
$r = q("SELECT `id`, `url` FROM `contact` $r = q("SELECT `id`, `url` FROM `contact`
@ -241,7 +246,7 @@ class CronJobs {
continue; continue;
} }
logger("Repair contact ".$contact["id"]." ".$contact["url"], LOGGER_DEBUG); logger("Repair contact " . $contact["id"] . " " . $contact["url"], LOGGER_DEBUG);
q("UPDATE `contact` SET `batch` = '%s', `notify` = '%s', `poll` = '%s', pubkey = '%s' WHERE `id` = %d", q("UPDATE `contact` SET `batch` = '%s', `notify` = '%s', `poll` = '%s', pubkey = '%s' WHERE `id` = %d",
dbesc($data["batch"]), dbesc($data["notify"]), dbesc($data["poll"]), dbesc($data["pubkey"]), dbesc($data["batch"]), dbesc($data["notify"]), dbesc($data["poll"]), dbesc($data["pubkey"]),
intval($contact["id"])); intval($contact["id"]));
@ -252,15 +257,15 @@ class CronJobs {
* @brief Do some repairs in database entries * @brief Do some repairs in database entries
* *
*/ */
private static function repairDatabase() { private static function repairDatabase()
{
// Sometimes there seem to be issues where the "self" contact vanishes. // Sometimes there seem to be issues where the "self" contact vanishes.
// We haven't found the origin of the problem by now. // We haven't found the origin of the problem by now.
$r = q("SELECT `uid` FROM `user` WHERE NOT EXISTS (SELECT `uid` FROM `contact` WHERE `contact`.`uid` = `user`.`uid` AND `contact`.`self`)"); $r = q("SELECT `uid` FROM `user` WHERE NOT EXISTS (SELECT `uid` FROM `contact` WHERE `contact`.`uid` = `user`.`uid` AND `contact`.`self`)");
if (DBM::is_result($r)) { if (DBM::is_result($r)) {
foreach ($r AS $user) { foreach ($r AS $user) {
logger('Create missing self contact for user '.$user['uid']); logger('Create missing self contact for user ' . $user['uid']);
user_create_self_contact($user['uid']); Contact::createSelfFromUserId($user['uid']);
} }
} }

View file

@ -17,19 +17,26 @@ class DBClean {
return; return;
} }
if ($stage == 0) {
self::forkCleanProcess();
} else {
self::removeOrphans($stage);
}
}
/**
* @brief Fork the different DBClean processes
*/
private static function forkCleanProcess() {
// Get the expire days for step 8 and 9 // Get the expire days for step 8 and 9
$days = Config::get('system', 'dbclean-expire-days', 0); $days = Config::get('system', 'dbclean-expire-days', 0);
if ($stage == 0) { for ($i = 1; $i <= 10; $i++) {
for ($i = 1; $i <= 9; $i++) { // Execute the background script for a step when it isn't finished.
// Execute the background script for a step when it isn't finished. // Execute step 8 and 9 only when $days is defined.
// Execute step 8 and 9 only when $days is defined. if (!Config::get('system', 'finished-dbclean-'.$i, false) && (($i < 8) || ($i > 9) || ($days > 0))) {
if (!Config::get('system', 'finished-dbclean-'.$i, false) && (($i < 8) || ($days > 0))) { Worker::add(PRIORITY_LOW, 'DBClean', $i);
Worker::add(PRIORITY_LOW, 'DBClean', $i);
}
} }
} else {
self::removeOrphans($stage);
} }
} }
@ -39,17 +46,18 @@ class DBClean {
* *
* Values for $stage: * Values for $stage:
* ------------------ * ------------------
* 1: Old global item entries from item table without user copy. * 1: Old global item entries from item table without user copy.
* 2: Items without parents. * 2: Items without parents.
* 3: Orphaned data from thread table. * 3: Orphaned data from thread table.
* 4: Orphaned data from notify table. * 4: Orphaned data from notify table.
* 5: Orphaned data from notify-threads table. * 5: Orphaned data from notify-threads table.
* 6: Orphaned data from sign table. * 6: Orphaned data from sign table.
* 7: Orphaned data from term table. * 7: Orphaned data from term table.
* 8: Expired threads. * 8: Expired threads.
* 9: Old global item entries from expired threads * 9: Old global item entries from expired threads.
* 10: Old conversations.
*/ */
private static function removeOrphans($stage = 0) { private static function removeOrphans($stage) {
global $db; global $db;
$count = 0; $count = 0;
@ -75,6 +83,7 @@ class DBClean {
$last_id = $orphan["id"]; $last_id = $orphan["id"];
dba::delete('item', array('id' => $orphan["id"])); dba::delete('item', array('id' => $orphan["id"]));
} }
Worker::add(PRIORITY_MEDIUM, 'DBClean', 1, $last_id);
} else { } else {
logger("No global item orphans found"); logger("No global item orphans found");
} }
@ -96,6 +105,7 @@ class DBClean {
$last_id = $orphan["id"]; $last_id = $orphan["id"];
dba::delete('item', array('id' => $orphan["id"])); dba::delete('item', array('id' => $orphan["id"]));
} }
Worker::add(PRIORITY_MEDIUM, 'DBClean', 2, $last_id);
} else { } else {
logger("No item orphans without parents found"); logger("No item orphans without parents found");
} }
@ -121,6 +131,7 @@ class DBClean {
$last_id = $orphan["iid"]; $last_id = $orphan["iid"];
dba::delete('thread', array('iid' => $orphan["iid"])); dba::delete('thread', array('iid' => $orphan["iid"]));
} }
Worker::add(PRIORITY_MEDIUM, 'DBClean', 3, $last_id);
} else { } else {
logger("No thread orphans found"); logger("No thread orphans found");
} }
@ -146,6 +157,7 @@ class DBClean {
$last_id = $orphan["id"]; $last_id = $orphan["id"];
dba::delete('notify', array('iid' => $orphan["iid"])); dba::delete('notify', array('iid' => $orphan["iid"]));
} }
Worker::add(PRIORITY_MEDIUM, 'DBClean', 4, $last_id);
} else { } else {
logger("No notify orphans found"); logger("No notify orphans found");
} }
@ -171,6 +183,7 @@ class DBClean {
$last_id = $orphan["id"]; $last_id = $orphan["id"];
dba::delete('notify-threads', array('id' => $orphan["id"])); dba::delete('notify-threads', array('id' => $orphan["id"]));
} }
Worker::add(PRIORITY_MEDIUM, 'DBClean', 5, $last_id);
} else { } else {
logger("No notify-threads orphans found"); logger("No notify-threads orphans found");
} }
@ -196,6 +209,7 @@ class DBClean {
$last_id = $orphan["id"]; $last_id = $orphan["id"];
dba::delete('sign', array('iid' => $orphan["iid"])); dba::delete('sign', array('iid' => $orphan["iid"]));
} }
Worker::add(PRIORITY_MEDIUM, 'DBClean', 6, $last_id);
} else { } else {
logger("No sign orphans found"); logger("No sign orphans found");
} }
@ -221,6 +235,7 @@ class DBClean {
$last_id = $orphan["tid"]; $last_id = $orphan["tid"];
dba::delete('term', array('oid' => $orphan["oid"])); dba::delete('term', array('oid' => $orphan["oid"]));
} }
Worker::add(PRIORITY_MEDIUM, 'DBClean', 7, $last_id);
} else { } else {
logger("No term orphans found"); logger("No term orphans found");
} }
@ -259,6 +274,7 @@ class DBClean {
$last_id = $thread["iid"]; $last_id = $thread["iid"];
dba::delete('thread', array('iid' => $thread["iid"])); dba::delete('thread', array('iid' => $thread["iid"]));
} }
Worker::add(PRIORITY_MEDIUM, 'DBClean', 8, $last_id);
} else { } else {
logger("No expired threads found"); logger("No expired threads found");
} }
@ -286,6 +302,7 @@ class DBClean {
$last_id = $orphan["id"]; $last_id = $orphan["id"];
dba::delete('item', array('id' => $orphan["id"])); dba::delete('item', array('id' => $orphan["id"]));
} }
Worker::add(PRIORITY_MEDIUM, 'DBClean', 9, $last_id);
} else { } else {
logger("No global item entries from expired threads"); logger("No global item entries from expired threads");
} }
@ -293,11 +310,28 @@ class DBClean {
logger("Done deleting ".$count." old global item entries from expired threads. Last ID: ".$last_id); logger("Done deleting ".$count." old global item entries from expired threads. Last ID: ".$last_id);
Config::set('system', 'dbclean-last-id-9', $last_id); Config::set('system', 'dbclean-last-id-9', $last_id);
} } elseif ($stage == 10) {
$last_id = Config::get('system', 'dbclean-last-id-10', 0);
// Call it again if not all entries were purged logger("Deleting old conversations. Last created: ".$last_id);
if (($stage != 0) && ($count > 0)) { $r = dba::p("SELECT `received`, `item-uri` FROM `conversation`
Worker::add(PRIORITY_MEDIUM, 'dbclean'); WHERE `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY
ORDER BY `received` LIMIT ".intval($limit));
$count = dba::num_rows($r);
if ($count > 0) {
logger("found old conversations: ".$count);
while ($orphan = dba::fetch($r)) {
$last_id = $orphan["received"];
dba::delete('conversation', array('item-uri' => $orphan["item-uri"]));
}
Worker::add(PRIORITY_MEDIUM, 'DBClean', 10, $last_id);
} else {
logger("No old conversations found");
}
dba::close($r);
logger("Done deleting ".$count." conversations. Last created: ".$last_id);
Config::set('system', 'dbclean-last-id-10', $last_id);
} }
} }
} }

View file

@ -12,13 +12,13 @@ use Friendica\Database\DBM;
use Friendica\Object\Contact; use Friendica\Object\Contact;
use Friendica\Protocol\Diaspora; use Friendica\Protocol\Diaspora;
use Friendica\Protocol\DFRN; use Friendica\Protocol\DFRN;
use Friendica\Protocol\Email;
require_once 'include/queue_fn.php'; require_once 'include/queue_fn.php';
require_once 'include/html2plain.php'; require_once 'include/html2plain.php';
require_once 'include/datetime.php'; require_once 'include/datetime.php';
require_once 'include/items.php'; require_once 'include/items.php';
require_once 'include/bbcode.php'; require_once 'include/bbcode.php';
require_once 'include/email.php';
/// @todo This is some ugly code that needs to be split into several methods /// @todo This is some ugly code that needs to be split into several methods
@ -376,7 +376,6 @@ class Delivery {
break; break;
case NETWORK_MAIL: case NETWORK_MAIL:
case NETWORK_MAIL2:
if (Config::get('system','dfrn_only')) { if (Config::get('system','dfrn_only')) {
break; break;
@ -418,36 +417,36 @@ class Delivery {
if ($r1 && $r1[0]['reply_to']) if ($r1 && $r1[0]['reply_to'])
$reply_to = $r1[0]['reply_to']; $reply_to = $r1[0]['reply_to'];
$subject = (($it['title']) ? email_header_encode($it['title'],'UTF-8') : t("\x28no subject\x29")) ; $subject = (($it['title']) ? Email::encodeHeader($it['title'],'UTF-8') : t("\x28no subject\x29")) ;
// only expose our real email address to true friends // only expose our real email address to true friends
if (($contact['rel'] == CONTACT_IS_FRIEND) && !$contact['blocked']) { if (($contact['rel'] == CONTACT_IS_FRIEND) && !$contact['blocked']) {
if ($reply_to) { if ($reply_to) {
$headers = 'From: '.email_header_encode($local_user[0]['username'],'UTF-8').' <'.$reply_to.'>'."\n"; $headers = 'From: '.Email::encodeHeader($local_user[0]['username'],'UTF-8').' <'.$reply_to.'>'."\n";
$headers .= 'Sender: '.$local_user[0]['email']."\n"; $headers .= 'Sender: '.$local_user[0]['email']."\n";
} else { } else {
$headers = 'From: '.email_header_encode($local_user[0]['username'],'UTF-8').' <'.$local_user[0]['email'].'>'."\n"; $headers = 'From: '.Email::encodeHeader($local_user[0]['username'],'UTF-8').' <'.$local_user[0]['email'].'>'."\n";
} }
} else { } else {
$headers = 'From: '. email_header_encode($local_user[0]['username'],'UTF-8') .' <'. t('noreply') .'@'.$a->get_hostname() .'>'. "\n"; $headers = 'From: '. Email::encodeHeader($local_user[0]['username'],'UTF-8') .' <'. t('noreply') .'@'.$a->get_hostname() .'>'. "\n";
} }
//if ($reply_to) //if ($reply_to)
// $headers .= 'Reply-to: '.$reply_to . "\n"; // $headers .= 'Reply-to: '.$reply_to . "\n";
$headers .= 'Message-Id: <'. iri2msgid($it['uri']).'>'. "\n"; $headers .= 'Message-Id: <'. Email::iri2msgid($it['uri']).'>'. "\n";
//logger("Mail: uri: ".$it['uri']." parent-uri ".$it['parent-uri'], LOGGER_DEBUG); //logger("Mail: uri: ".$it['uri']." parent-uri ".$it['parent-uri'], LOGGER_DEBUG);
//logger("Mail: Data: ".print_r($it, true), LOGGER_DEBUG); //logger("Mail: Data: ".print_r($it, true), LOGGER_DEBUG);
//logger("Mail: Data: ".print_r($it, true), LOGGER_DATA); //logger("Mail: Data: ".print_r($it, true), LOGGER_DATA);
if ($it['uri'] !== $it['parent-uri']) { if ($it['uri'] !== $it['parent-uri']) {
$headers .= "References: <".iri2msgid($it["parent-uri"]).">"; $headers .= "References: <".Email::iri2msgid($it["parent-uri"]).">";
// If Threading is enabled, write down the correct parent // If Threading is enabled, write down the correct parent
if (($it["thr-parent"] != "") && ($it["thr-parent"] != $it["parent-uri"])) if (($it["thr-parent"] != "") && ($it["thr-parent"] != $it["parent-uri"]))
$headers .= " <".iri2msgid($it["thr-parent"]).">"; $headers .= " <".Email::iri2msgid($it["thr-parent"]).">";
$headers .= "\n"; $headers .= "\n";
if (!$it['title']) { if (!$it['title']) {
@ -469,7 +468,7 @@ class Delivery {
if (strncasecmp($subject,'RE:',3)) if (strncasecmp($subject,'RE:',3))
$subject = 'Re: '.$subject; $subject = 'Re: '.$subject;
} }
email_send($addr, $subject, $headers, $it); Email::send($addr, $subject, $headers, $it);
} }
break; break;

View file

@ -11,15 +11,14 @@ use Friendica\Network\Probe;
use Friendica\Object\Contact; use Friendica\Object\Contact;
use Friendica\Protocol\Diaspora; use Friendica\Protocol\Diaspora;
use Friendica\Protocol\OStatus; use Friendica\Protocol\OStatus;
use Friendica\Protocol\Salmon;
use dba; use dba;
require_once 'include/queue_fn.php'; require_once 'include/queue_fn.php';
require_once 'include/html2plain.php'; require_once 'include/html2plain.php';
require_once 'include/salmon.php';
require_once 'include/datetime.php'; require_once 'include/datetime.php';
require_once 'include/items.php'; require_once 'include/items.php';
require_once 'include/bbcode.php'; require_once 'include/bbcode.php';
require_once 'include/email.php';
/* /*
* This file was at one time responsible for doing all deliveries, but this caused * This file was at one time responsible for doing all deliveries, but this caused
@ -448,7 +447,7 @@ class Notifier {
// It only makes sense to distribute answers to OStatus messages to Friendica and OStatus - but not Diaspora // It only makes sense to distribute answers to OStatus messages to Friendica and OStatus - but not Diaspora
$sql_extra = " AND `network` IN ('".NETWORK_OSTATUS."', '".NETWORK_DFRN."')"; $sql_extra = " AND `network` IN ('".NETWORK_OSTATUS."', '".NETWORK_DFRN."')";
} else { } else {
$sql_extra = " AND `network` IN ('".NETWORK_OSTATUS."', '".NETWORK_DFRN."', '".NETWORK_DIASPORA."', '".NETWORK_MAIL."', '".NETWORK_MAIL2."')"; $sql_extra = " AND `network` IN ('".NETWORK_OSTATUS."', '".NETWORK_DFRN."', '".NETWORK_DIASPORA."', '".NETWORK_MAIL."')";
} }
} else { } else {
$public_message = false; $public_message = false;
@ -506,11 +505,11 @@ class Notifier {
// They are especially used for notifications to OStatus users that don't follow us. // They are especially used for notifications to OStatus users that don't follow us.
if ($slap && count($url_recipients) && ($public_message || $push_notify) && $normal_mode) { if ($slap && count($url_recipients) && ($public_message || $push_notify) && $normal_mode) {
if (!Config::get('system','dfrn_only')) { if (!Config::get('system', 'dfrn_only')) {
foreach ($url_recipients as $url) { foreach ($url_recipients as $url) {
if ($url) { if ($url) {
logger('notifier: urldelivery: ' . $url); logger('notifier: urldelivery: ' . $url);
$deliver_status = slapper($owner,$url,$slap); $deliver_status = Salmon::slapper($owner, $url, $slap);
/// @TODO Redeliver/queue these items on failure, though there is no contact record /// @TODO Redeliver/queue these items on failure, though there is no contact record
} }
} }
@ -538,9 +537,8 @@ class Notifier {
} }
$r2 = q("SELECT `id`, `name`,`network` FROM `contact` $r2 = q("SELECT `id`, `name`,`network` FROM `contact`
WHERE `network` in ('%s', '%s') AND `uid` = %d AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `rel` != %d", WHERE `network` in ('%s') AND `uid` = %d AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `rel` != %d",
dbesc(NETWORK_DFRN), dbesc(NETWORK_DFRN),
dbesc(NETWORK_MAIL2),
intval($owner['uid']), intval($owner['uid']),
intval(CONTACT_IS_SHARING) intval(CONTACT_IS_SHARING)
); );

View file

@ -8,6 +8,7 @@ use Friendica\Core\Config;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Object\Contact; use Friendica\Object\Contact;
use Friendica\Protocol\Email;
use Friendica\Protocol\PortableContact; use Friendica\Protocol\PortableContact;
use dba; use dba;
@ -20,10 +21,9 @@ Class OnePoll
require_once 'include/datetime.php'; require_once 'include/datetime.php';
require_once 'include/items.php'; require_once 'include/items.php';
require_once 'include/email.php';
require_once 'include/queue_fn.php'; require_once 'include/queue_fn.php';
logger('onepoll: start'); logger('start');
$manual_id = 0; $manual_id = 0;
$generation = 0; $generation = 0;
@ -36,36 +36,18 @@ Class OnePoll
} }
if (!$contact_id) { if (!$contact_id) {
logger('onepoll: no contact'); logger('no contact');
return; return;
} }
$d = datetime_convert(); $d = datetime_convert();
// Only poll from those with suitable relationships, $contact = dba::select('contact', [], ['id' => $contact_id], ['limit' => 1]);
// and which have a polling address and ignore Diaspora since if (!DBM::is_result($contact)) {
// we are unable to match those posts with a Diaspora GUID and prevent duplicates.
$contacts = q("SELECT `contact`.* FROM `contact`
WHERE (`rel` = %d OR `rel` = %d) AND `poll` != ''
AND NOT `network` IN ('%s', '%s')
AND `contact`.`id` = %d
AND `self` = 0 AND `contact`.`blocked` = 0 AND `contact`.`readonly` = 0
AND `contact`.`archive` = 0 LIMIT 1",
intval(CONTACT_IS_SHARING),
intval(CONTACT_IS_FRIEND),
dbesc(NETWORK_FACEBOOK),
dbesc(NETWORK_PUMPIO),
intval($contact_id)
);
if (!count($contacts)) {
logger('Contact not found or cannot be used.'); logger('Contact not found or cannot be used.');
return; return;
} }
$contact = $contacts[0];
$importer_uid = $contact['uid']; $importer_uid = $contact['uid'];
// load current friends if possible. // load current friends if possible.
@ -81,18 +63,25 @@ Class OnePoll
} }
} }
/// @TODO Check why we don't poll the Diaspora feed at the moment (some guid problem in the items?) // Diaspora users, archived users and followers are only checked if they still exist.
/// @TODO Check whether this is possible with Redmatrix if ($contact['archive'] || ($contact["network"] == NETWORK_DIASPORA) || ($contact["rel"] == CONTACT_IS_FOLLOWER)) {
if ($contact["network"] == NETWORK_DIASPORA) { $last_updated = PortableContact::lastUpdated($contact["url"]);
if (PortableContact::updateNeeded($contact["created"], $contact["last-item"], $contact["failure_update"], $contact["success_update"])) { $updated = datetime_convert();
$last_updated = PortableContact::lastUpdated($contact["url"]); if ($last_updated) {
$updated = datetime_convert(); logger('Contact '.$contact['id'].' had last update on '.$last_updated, LOGGER_DEBUG);
if ($last_updated) {
$fields = array('last-item' => $last_updated, 'last-update' => $updated, 'success_update' => $updated); // The last public item can be older than the last item we got
dba::update('contact', $fields, array('id' => $contact['id'])); if ($last_updated < $contact['last-item']) {
} else { $last_updated = $contact['last-item'];
dba::update('contact', array('last-update' => $updated, 'failure_update' => $updated), array('id' => $contact['id']));
} }
$fields = array('last-item' => $last_updated, 'last-update' => $updated, 'success_update' => $updated);
self::updateContact($contact, $fields);
Contact::unmarkForArchival($contact);
} else {
self::updateContact($contact, array('last-update' => $updated, 'failure_update' => $updated));
Contact::markForArchival($contact);
logger('Contact '.$contact['id'].' is marked for archival', LOGGER_DEBUG);
} }
return; return;
} }
@ -102,8 +91,8 @@ Class OnePoll
$t = $contact['last-update']; $t = $contact['last-update'];
if ($contact['subhub']) { if ($contact['subhub']) {
$poll_interval = Config::get('system', 'pushpoll_frequency'); $poll_interval = Config::get('system', 'pushpoll_frequency', 3);
$contact['priority'] = (($poll_interval !== false) ? intval($poll_interval) : 3); $contact['priority'] = intval($poll_interval);
$hub_update = false; $hub_update = false;
if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 day")) { if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 day")) {
@ -122,12 +111,18 @@ Class OnePoll
if (($contact['network'] === NETWORK_OSTATUS) || ($contact['network'] === NETWORK_DIASPORA) || ($contact['network'] === NETWORK_DFRN)) { if (($contact['network'] === NETWORK_OSTATUS) || ($contact['network'] === NETWORK_DIASPORA) || ($contact['network'] === NETWORK_DFRN)) {
if (!PortableContact::reachable($contact['url'])) { if (!PortableContact::reachable($contact['url'])) {
logger("Skipping probably dead contact ".$contact['url']); logger("Skipping probably dead contact ".$contact['url']);
// set the last-update so we don't keep polling
dba::update('contact', ['last-update' => datetime_convert()], ['id' => $contact['id']]);
return; return;
} }
if (!update_contact($contact["id"])) { if (!update_contact($contact["id"])) {
Contact::markForArchival($contact); Contact::markForArchival($contact);
logger('Contact is marked dead'); logger('Contact is marked dead');
// set the last-update so we don't keep polling
dba::update('contact', ['last-update' => datetime_convert()], ['id' => $contact['id']]);
return; return;
} else { } else {
Contact::unmarkForArchival($contact); Contact::unmarkForArchival($contact);
@ -136,6 +131,9 @@ Class OnePoll
if ($importer_uid == 0) { if ($importer_uid == 0) {
logger('Ignore public contacts'); logger('Ignore public contacts');
// set the last-update so we don't keep polling
dba::update('contact', ['last-update' => datetime_convert()], ['id' => $contact['id']]);
return; return;
} }
@ -145,12 +143,15 @@ Class OnePoll
if (!DBM::is_result($r)) { if (!DBM::is_result($r)) {
logger('No self contact for user '.$importer_uid); logger('No self contact for user '.$importer_uid);
// set the last-update so we don't keep polling
dba::update('contact', ['last-update' => datetime_convert()], ['id' => $contact['id']]);
return; return;
} }
$importer = $r[0]; $importer = $r[0];
logger("onepoll: poll: ({$contact['id']}) IMPORTER: {$importer['name']}, CONTACT: {$contact['name']}"); logger("poll: ({$contact['network']}-{$contact['id']}) IMPORTER: {$importer['name']}, CONTACT: {$contact['name']}");
if ($contact['network'] === NETWORK_DFRN) { if ($contact['network'] === NETWORK_DFRN) {
$idtosend = $orig_id = (($contact['dfrn-id']) ? $contact['dfrn-id'] : $contact['issued-id']); $idtosend = $orig_id = (($contact['dfrn-id']) ? $contact['dfrn-id'] : $contact['issued-id']);
@ -179,6 +180,9 @@ Class OnePoll
$ret = z_fetch_url($url); $ret = z_fetch_url($url);
if ($ret['errno'] == CURLE_OPERATION_TIMEDOUT) { if ($ret['errno'] == CURLE_OPERATION_TIMEDOUT) {
// set the last-update so we don't keep polling
dba::update('contact', ['last-update' => datetime_convert()], ['id' => $contact['id']]);
Contact::markForArchival($contact);
return; return;
} }
@ -186,7 +190,7 @@ Class OnePoll
$html_code = $a->get_curl_code(); $html_code = $a->get_curl_code();
logger('onepoll: handshake with url ' . $url . ' returns xml: ' . $handshake_xml, LOGGER_DATA); logger('handshake with url ' . $url . ' returns xml: ' . $handshake_xml, LOGGER_DATA);
if (!strlen($handshake_xml) || ($html_code >= 400) || !$html_code) { if (!strlen($handshake_xml) || ($html_code >= 400) || !$html_code) {
@ -200,8 +204,7 @@ Class OnePoll
// set the last-update so we don't keep polling // set the last-update so we don't keep polling
$fields = array('last-update' => datetime_convert(), 'failure_update' => datetime_convert()); $fields = array('last-update' => datetime_convert(), 'failure_update' => datetime_convert());
dba::update('contact', $fields, array('id' => $contact['id'])); self::updateContact($contact, $fields);
return; return;
} }
@ -211,8 +214,7 @@ Class OnePoll
Contact::markForArchival($contact); Contact::markForArchival($contact);
$fields = array('last-update' => datetime_convert(), 'failure_update' => datetime_convert()); $fields = array('last-update' => datetime_convert(), 'failure_update' => datetime_convert());
dba::update('contact', $fields, array('id' => $contact['id'])); self::updateContact($contact, $fields);
return; return;
} }
@ -225,7 +227,7 @@ Class OnePoll
// we may not be friends anymore. Will keep trying for one month. // we may not be friends anymore. Will keep trying for one month.
// set the last-update so we don't keep polling // set the last-update so we don't keep polling
$fields = array('last-update' => datetime_convert(), 'failure_update' => datetime_convert()); $fields = array('last-update' => datetime_convert(), 'failure_update' => datetime_convert());
dba::update('contact', $fields, array('id' => $contact['id'])); self::updateContact($contact, $fields);
Contact::markForArchival($contact); Contact::markForArchival($contact);
} elseif ($contact['term-date'] > NULL_DATE) { } elseif ($contact['term-date'] > NULL_DATE) {
@ -234,6 +236,8 @@ Class OnePoll
} }
if ((intval($res->status) != 0) || !strlen($res->challenge) || !strlen($res->dfrn_id)) { if ((intval($res->status) != 0) || !strlen($res->challenge) || !strlen($res->dfrn_id)) {
// set the last-update so we don't keep polling
dba::update('contact', ['last-update' => datetime_convert()], ['id' => $contact['id']]);
return; return;
} }
@ -264,8 +268,12 @@ Class OnePoll
} }
if ($final_dfrn_id != $orig_id) { if ($final_dfrn_id != $orig_id) {
logger('ID did not decode: ' . $contact['id'] . ' orig: ' . $orig_id . ' final: ' . $final_dfrn_id);
// did not decode properly - cannot trust this site // did not decode properly - cannot trust this site
logger('ID did not decode: ' . $contact['id'] . ' orig: ' . $orig_id . ' final: ' . $final_dfrn_id);
// set the last-update so we don't keep polling
dba::update('contact', ['last-update' => datetime_convert()], ['id' => $contact['id']]);
Contact::markForArchival($contact);
return; return;
} }
@ -298,25 +306,33 @@ Class OnePoll
// Are we allowed to import from this person? // Are we allowed to import from this person?
if ($contact['rel'] == CONTACT_IS_FOLLOWER || $contact['blocked'] || $contact['readonly']) { if ($contact['rel'] == CONTACT_IS_FOLLOWER || $contact['blocked'] || $contact['readonly']) {
// set the last-update so we don't keep polling
dba::update('contact', ['last-update' => datetime_convert()], ['id' => $contact['id']]);
return; return;
} }
$cookiejar = tempnam(get_temppath(), 'cookiejar-onepoll-'); $cookiejar = tempnam(get_temppath(), 'cookiejar-onepoll-');
$ret = z_fetch_url($contact['poll'], false, $redirects, array('cookiejar' => $cookiejar)); $ret = z_fetch_url($contact['poll'], false, $redirects, array('cookiejar' => $cookiejar));
unlink($cookiejar);
if ($ret['errno'] == CURLE_OPERATION_TIMEDOUT) { if ($ret['errno'] == CURLE_OPERATION_TIMEDOUT) {
// set the last-update so we don't keep polling
dba::update('contact', ['last-update' => datetime_convert()], ['id' => $contact['id']]);
Contact::markForArchival($contact);
return; return;
} }
$xml = $ret['body']; $xml = $ret['body'];
unlink($cookiejar); } elseif ($contact['network'] === NETWORK_MAIL) {
} elseif ($contact['network'] === NETWORK_MAIL || $contact['network'] === NETWORK_MAIL2) {
logger("Mail: Fetching for ".$contact['addr'], LOGGER_DEBUG); logger("Mail: Fetching for ".$contact['addr'], LOGGER_DEBUG);
$mail_disabled = ((function_exists('imap_open') && (! Config::get('system', 'imap_disabled'))) ? 0 : 1); $mail_disabled = ((function_exists('imap_open') && (! Config::get('system', 'imap_disabled'))) ? 0 : 1);
if ($mail_disabled) { if ($mail_disabled) {
// set the last-update so we don't keep polling
dba::update('contact', ['last-update' => datetime_convert()], ['id' => $contact['id']]);
Contact::markForArchival($contact);
return; return;
} }
@ -328,10 +344,10 @@ Class OnePoll
$condition = array("`server` != '' AND `uid` = ?", $importer_uid); $condition = array("`server` != '' AND `uid` = ?", $importer_uid);
$mailconf = dba::select('mailacct', array(), $condition, array('limit' => 1)); $mailconf = dba::select('mailacct', array(), $condition, array('limit' => 1));
if (DBM::is_result($x) && DBM::is_result($mailconf)) { if (DBM::is_result($x) && DBM::is_result($mailconf)) {
$mailbox = construct_mailbox_name($mailconf); $mailbox = Email::constructMailboxName($mailconf);
$password = ''; $password = '';
openssl_private_decrypt(hex2bin($mailconf['pass']), $password, $x['prvkey']); openssl_private_decrypt(hex2bin($mailconf['pass']), $password, $x['prvkey']);
$mbox = email_connect($mailbox, $mailconf['user'], $password); $mbox = Email::connect($mailbox, $mailconf['user'], $password);
unset($password); unset($password);
logger("Mail: Connect to " . $mailconf['user']); logger("Mail: Connect to " . $mailconf['user']);
if ($mbox) { if ($mbox) {
@ -344,14 +360,14 @@ Class OnePoll
} }
if ($mbox) { if ($mbox) {
$msgs = email_poll($mbox, $contact['addr']); $msgs = Email::poll($mbox, $contact['addr']);
if (count($msgs)) { if (count($msgs)) {
logger("Mail: Parsing ".count($msgs)." mails from ".$contact['addr']." for ".$mailconf['user'], LOGGER_DEBUG); logger("Mail: Parsing ".count($msgs)." mails from ".$contact['addr']." for ".$mailconf['user'], LOGGER_DEBUG);
$metas = email_msg_meta($mbox,implode(',', $msgs)); $metas = Email::messageMeta($mbox, implode(',', $msgs));
if (count($metas) != count($msgs)) { if (count($metas) != count($msgs)) {
logger("onepoll: for " . $mailconf['user'] . " there are ". count($msgs) . " messages but received " . count($metas) . " metas", LOGGER_DEBUG); logger("for " . $mailconf['user'] . " there are ". count($msgs) . " messages but received " . count($metas) . " metas", LOGGER_DEBUG);
} else { } else {
$msgs = array_combine($msgs, $metas); $msgs = array_combine($msgs, $metas);
@ -361,10 +377,9 @@ Class OnePoll
$datarray = array(); $datarray = array();
$datarray['verb'] = ACTIVITY_POST; $datarray['verb'] = ACTIVITY_POST;
$datarray['object-type'] = ACTIVITY_OBJ_NOTE; $datarray['object-type'] = ACTIVITY_OBJ_NOTE;
// $meta = email_msg_meta($mbox, $msg_uid); // $meta = Email::messageMeta($mbox, $msg_uid);
// $headers = email_msg_headers($mbox, $msg_uid);
$datarray['uri'] = msgid2iri(trim($meta->message_id, '<>')); $datarray['uri'] = Email::msgid2iri(trim($meta->message_id, '<>'));
// Have we seen it before? // Have we seen it before?
$fields = array('deleted', 'id'); $fields = array('deleted', 'id');
@ -416,7 +431,7 @@ Class OnePoll
$refs_arr = explode(' ', $raw_refs); $refs_arr = explode(' ', $raw_refs);
if (count($refs_arr)) { if (count($refs_arr)) {
for ($x = 0; $x < count($refs_arr); $x ++) { for ($x = 0; $x < count($refs_arr); $x ++) {
$refs_arr[$x] = "'" . msgid2iri(str_replace(array('<', '>', ' '),array('', '', ''),dbesc($refs_arr[$x]))) . "'"; $refs_arr[$x] = "'" . Email::msgid2iri(str_replace(array('<', '>', ' '),array('', '', ''),dbesc($refs_arr[$x]))) . "'";
} }
} }
$qstr = implode(',', $refs_arr); $qstr = implode(',', $refs_arr);
@ -466,7 +481,7 @@ Class OnePoll
$datarray['parent-uri'] = $datarray['uri']; $datarray['parent-uri'] = $datarray['uri'];
} }
$r = email_get_msg($mbox, $msg_uid, $reply); $r = Email::getMessage($mbox, $msg_uid, $reply);
if (!$r) { if (!$r) {
logger("Mail: can't fetch msg ".$msg_uid." for ".$mailconf['user']); logger("Mail: can't fetch msg ".$msg_uid." for ".$mailconf['user']);
continue; continue;
@ -560,8 +575,8 @@ Class OnePoll
logger('post_handshake: response from ' . $url . ' did not contain XML.'); logger('post_handshake: response from ' . $url . ' did not contain XML.');
$fields = array('last-update' => datetime_convert(), 'failure_update' => datetime_convert()); $fields = array('last-update' => datetime_convert(), 'failure_update' => datetime_convert());
dba::update('contact', $fields, array('id' => $contact['id'])); self::updateContact($contact, $fields);
Contact::markForArchival($contact);
return; return;
} }
@ -605,13 +620,15 @@ Class OnePoll
$updated = datetime_convert(); $updated = datetime_convert();
dba::update('contact', array('last-update' => $updated, 'success_update' => $updated), array('id' => $contact['id'])); self::updateContact($contact, array('last-update' => $updated, 'success_update' => $updated));
dba::update('gcontact', array('last_contact' => $updated), array('nurl' => $contact['nurl'])); dba::update('gcontact', array('last_contact' => $updated), array('nurl' => $contact['nurl']));
Contact::unmarkForArchival($contact);
} elseif (in_array($contact["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, NETWORK_FEED))) { } elseif (in_array($contact["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, NETWORK_FEED))) {
$updated = datetime_convert(); $updated = datetime_convert();
dba::update('contact', array('last-update' => $updated, 'failure_update' => $updated), array('id' => $contact['id'])); self::updateContact($contact, array('last-update' => $updated, 'failure_update' => $updated));
dba::update('gcontact', array('last_failure' => $updated), array('nurl' => $contact['nurl'])); dba::update('gcontact', array('last_failure' => $updated), array('nurl' => $contact['nurl']));
Contact::markForArchival($contact);
} else { } else {
dba::update('contact', array('last-update' => $updated), array('id' => $contact['id'])); dba::update('contact', array('last-update' => $updated), array('id' => $contact['id']));
} }
@ -626,4 +643,15 @@ Class OnePoll
return $subject; return $subject;
} }
/**
* @brief Updates a personal contact entry and the public contact entry
*
* @param array $contact The personal contact entry
* @param array $fields The fields that are updated
*/
private static function updateContact($contact, $fields) {
dba::update('contact', $fields, array('id' => $contact['id']));
dba::update('contact', $fields, array('uid' => 0, 'nurl' => $contact['nurl']));
}
} }

View file

@ -1,9 +1,7 @@
<?php <?php
/** /**
* @file src/Worker/Queue.php * @file src/Worker/Queue.php
*/ */
namespace Friendica\Worker; namespace Friendica\Worker;
use Friendica\Core\Cache; use Friendica\Core\Cache;
@ -13,13 +11,13 @@ use Friendica\Database\DBM;
use Friendica\Protocol\Diaspora; use Friendica\Protocol\Diaspora;
use Friendica\Protocol\DFRN; use Friendica\Protocol\DFRN;
use Friendica\Protocol\PortableContact; use Friendica\Protocol\PortableContact;
use Friendica\Protocol\Salmon;
use dba; use dba;
require_once 'include/queue_fn.php'; require_once 'include/queue_fn.php';
require_once 'include/datetime.php'; require_once 'include/datetime.php';
require_once 'include/items.php'; require_once 'include/items.php';
require_once 'include/bbcode.php'; require_once 'include/bbcode.php';
require_once 'include/salmon.php';
class Queue class Queue
{ {
@ -141,7 +139,7 @@ class Queue
case NETWORK_OSTATUS: case NETWORK_OSTATUS:
if ($contact['notify']) { if ($contact['notify']) {
logger('queue: slapdelivery: item ' . $q_item['id'] . ' for ' . $contact['name'] . ' <' . $contact['url'] . '>'); logger('queue: slapdelivery: item ' . $q_item['id'] . ' for ' . $contact['name'] . ' <' . $contact['url'] . '>');
$deliver_status = slapper($owner, $contact['notify'], $data); $deliver_status = Salmon::slapper($owner, $contact['notify'], $data);
if ($deliver_status == (-1)) { if ($deliver_status == (-1)) {
update_queue_time($q_item['id']); update_queue_time($q_item['id']);

View file

@ -1,6 +1,6 @@
<?php <?php
define('UPDATE_VERSION' , 1235); define('UPDATE_VERSION' , 1236);
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
@ -1472,9 +1472,6 @@ function update_1164() {
$r = q("UPDATE `item` SET `network`='%s' WHERE `contact-id` IN (SELECT `id` FROM`contact` WHERE `network` = '%s' AND `contact`.`uid` = `item`.`uid`)", $r = q("UPDATE `item` SET `network`='%s' WHERE `contact-id` IN (SELECT `id` FROM`contact` WHERE `network` = '%s' AND `contact`.`uid` = `item`.`uid`)",
NETWORK_DFRN, NETWORK_DFRN); NETWORK_DFRN, NETWORK_DFRN);
$r = q("UPDATE `item` SET `network`='%s' WHERE `contact-id` IN (SELECT `id` FROM`contact` WHERE `network` = '%s' AND `contact`.`uid` = `item`.`uid`)",
NETWORK_ZOT, NETWORK_ZOT);
$r = q("UPDATE `item` SET `network`='%s' WHERE `contact-id` IN (SELECT `id` FROM`contact` WHERE `network` = '%s' AND `contact`.`uid` = `item`.`uid`)", $r = q("UPDATE `item` SET `network`='%s' WHERE `contact-id` IN (SELECT `id` FROM`contact` WHERE `network` = '%s' AND `contact`.`uid` = `item`.`uid`)",
NETWORK_OSTATUS, NETWORK_OSTATUS); NETWORK_OSTATUS, NETWORK_OSTATUS);
@ -1487,9 +1484,6 @@ function update_1164() {
$r = q("UPDATE `item` SET `network`='%s' WHERE `contact-id` IN (SELECT `id` FROM`contact` WHERE `network` = '%s' AND `contact`.`uid` = `item`.`uid`)", $r = q("UPDATE `item` SET `network`='%s' WHERE `contact-id` IN (SELECT `id` FROM`contact` WHERE `network` = '%s' AND `contact`.`uid` = `item`.`uid`)",
NETWORK_MAIL, NETWORK_MAIL); NETWORK_MAIL, NETWORK_MAIL);
$r = q("UPDATE `item` SET `network`='%s' WHERE `contact-id` IN (SELECT `id` FROM`contact` WHERE `network` = '%s' AND `contact`.`uid` = `item`.`uid`)",
NETWORK_MAIL2, NETWORK_MAIL2);
$r = q("UPDATE `item` SET `network`='%s' WHERE `contact-id` IN (SELECT `id` FROM`contact` WHERE `network` = '%s' AND `contact`.`uid` = `item`.`uid`)", $r = q("UPDATE `item` SET `network`='%s' WHERE `contact-id` IN (SELECT `id` FROM`contact` WHERE `network` = '%s' AND `contact`.`uid` = `item`.`uid`)",
NETWORK_FACEBOOK, NETWORK_FACEBOOK); NETWORK_FACEBOOK, NETWORK_FACEBOOK);

0
util/config Normal file → Executable file
View file

0
util/createdoxygen.php Normal file → Executable file
View file

View file

@ -1,6 +1,5 @@
#!/usr/bin/env php #!/usr/bin/env php
<?php <?php
/** /**
* @brief tool to block an account from the node * @brief tool to block an account from the node
* *
@ -17,49 +16,39 @@
* Author: Tobias Diekershoff * Author: Tobias Diekershoff
* *
* License: AGPLv3 or later, same as Friendica * License: AGPLv3 or later, same as Friendica
**/ */
if ($argc != 2 || $argv[1] == "-h" || $argv[1] == "--help" || $argv[1] == "-?") { if ($argc != 2 || $argv[1] == "-h" || $argv[1] == "--help" || $argv[1] == "-?") {
echo "Usage: ".$argv[0]." [-h|profile_url]\r\n"; echo "Usage: " . $argv[0] . " [-h|profile_url]\r\n";
echo " -h, -?, --help ... show this help\r\n"; echo " -h, -?, --help ... show this help\r\n";
echo " profile_url ...... The URL of the profile you want to silence\r\n"; echo " profile_url ...... The URL of the profile you want to silence\r\n";
echo "\r\n"; echo "\r\n";
echo "Example: block bob@example.com\r\n"; echo "Example: block bob@example.com\r\n";
echo "$> ".$argv[0]." https://example.com/profiles/bob\r\n"; echo "$> " . $argv[0] . " https://example.com/profiles/bob\r\n";
echo "\r\n"; echo "\r\n";
exit(0); exit(0);
} }
use Friendica\Database\DBM; use Friendica\BaseObject;
use Friendica\Network\Probe; use Friendica\Object\Contact;
require_once 'boot.php'; require_once 'boot.php';
require_once 'include/dba.php'; require_once 'include/dba.php';
require_once 'include/text.php'; require_once 'include/text.php';
$a = get_app();
require_once '.htconfig.php';
$a = get_app();;
BaseObject::setApp($a);
require_once '.htconfig.php';
dba::connect($db_host, $db_user, $db_pass, $db_data); dba::connect($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data); unset($db_host, $db_user, $db_pass, $db_data);
/** $contact_id = Contact::getIdForURL($argv[1], 0);
* 1. make nurl from last parameter if (!$contact_id) {
* 2. check DB (contact) if there is a contact with uid=0 and that nurl, get the ID echo t('Could not find any contact entry for this URL (%s)', $nurl);
* 3. set the flag hidden=1 for the contact entry with the found ID
**/
$net = Probe::uri($argv[1]);
if (in_array($net['network'], array(NETWORK_PHANTOM, NETWORK_MAIL))) {
echo 'This account seems not to exist.';
echo "\r\n"; echo "\r\n";
exit(1); exit(1);
} }
$nurl = normalise_link($net['url']); Contact::block($contact_id);
$r = dba::select('contact', array('id'), array('nurl' => $nurl, 'uid' => 0), array('limit' => 1)); echo t('The contact has been blocked from the node');
if (DBM::is_result($r)) { echo "\r\n";
dba::update('contact', array('blocked' => true), array('id' => $r['id'])); exit(0);
echo "NOTICE: The account should be blocked from the node now\r\n";
} else {
echo "NOTICE: Could not find any entry for this URL (".$nurl.")\r\n";
}
?>

0
util/vagrant_provision.sh Normal file → Executable file
View file

0
util/vagrant_vhost.sh Normal file → Executable file
View file

0
view/smarty3/.gitignore vendored Executable file → Normal file
View file

View file

@ -0,0 +1,63 @@
<script>
function selectall(cls) {
$('.' + cls).prop('checked', true);
return false;
}
function selectnone(cls) {
$('.' + cls).prop('checked', false);
return false;
}
</script>
<div id="adminpage">
<h1>{{$title}} - {{$page}}</h1>
<p>{{$description}}</p>
<form action="{{$baseurl}}/admin/contactblock" method="post">
<input type="hidden" name="form_security_token" value="{{$form_security_token}}">
<h3>{{$h_contacts}}</h3>
{{if $contacts}}
<table id="contactblock">
<thead>
<tr>
<th></th>
{{foreach $th_contacts as $th}}
<th>
{{$th}}
</th>
{{/foreach}}
<th></th>
</tr>
</thead>
<tbody>
{{foreach $contacts as $contact}}
<tr>
<td class="checkbox"><input type="checkbox" class="contacts_ckbx" id="id_contact_{{$contact.id}}" name="contacts[]" value="{{$contact.id}}"/></td>
<td><img class="icon" src="{{$contact.micro}}" alt="{{$contact.nickname}}" title="{{$contact.nickname}}"></td>
<td class="name">{{$contact.name}}</td>
<td class="addr">{{$contact.addr}}</td>
<td class="addr"><a href="{{$contact.url}}" title="{{$contact.nickname}}" >{{$contact.url}}</a></td>
</tr>
{{/foreach}}
</tbody>
</table>
<p><a href="#" onclick="return selectall('contacts_ckbx');">{{$select_all}}</a> | <a href="#" onclick="return selectnone('contacts_ckbx');">{{$select_none}}</a></p>
{{$paginate}}
<div class="submit"><input type="submit" name="page_contactblock_unblock" value="{{$unblock|escape:'html'}}" /></div>
{{else}}
<p>{{$no_data|escape:'html'}}</p>
{{/if}}
</form>
<h3>{{$h_newblock}}</h3>
<form action="{{$baseurl}}/admin/contactblock" method="post">
<input type="hidden" name="form_security_token" value="{{$form_security_token}}">
<table id="contactblock">
<tbody>
<tr>
<td>{{include file="field_input.tpl" field=$contacturl}}</td>
</tr>
</tbody>
</table>
<div class="submit"><input type="submit" name="page_contactblock_block" value="{{$submit|escape:'html'}}" /></div>
</form>
</div>

View file

@ -4,10 +4,9 @@
<p id="dfrn-request-intro"> <p id="dfrn-request-intro">
{{$page_desc}}<br /> {{$page_desc}}<br />
<ul id="dfrn-request-networks"> <ul id="dfrn-request-networks">
<li><a href="http://friendica.com" title="{{$friendica}}">{{$friendica}}</a></li> <li><a href="http://friendi.ca" title="{{$friendica}}">{{$friendica}}</a></li>
<li><a href="http://joindiaspora.com" title="{{$diaspora}}">{{$diaspora}}</a> {{$diasnote}}</li> <li><a href="https://diasporafoundation.org" title="{{$diaspora}}">{{$diaspora}}</a> {{$diasnote}}</li>
<li><a href="http://ostatus.org" title="{{$public_net}}" >{{$statusnet}}</a></li> <li><a href="https://gnu.io/social/" title="{{$statusnet}}" >{{$statusnet}}</a></li>
{{if $emailnet}}<li>{{$emailnet}}</li>{{/if}}
</ul> </ul>
</p> </p>
<p> <p>

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