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

This commit is contained in:
Andy H 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/pgettext.php';
require_once 'include/nav.php';
require_once 'include/features.php';
require_once 'include/identity.php';
require_once 'update.php';
require_once 'include/dbstructure.php';
@ -45,7 +44,7 @@ define('FRIENDICA_PLATFORM', 'Friendica');
define('FRIENDICA_CODENAME', 'Asparagus');
define('FRIENDICA_VERSION', '3.6-dev');
define('DFRN_PROTOCOL_VERSION', '2.23');
define('DB_UPDATE_VERSION', 1235);
define('DB_UPDATE_VERSION', 1236);
/**
* @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_ZOT', 'zot!'); // Zot!
define('NETWORK_OSTATUS', 'stat'); // status.net, identi.ca, GNU-social, other OStatus implementations
define('NETWORK_ZOT', 'zot!'); // Zot! - Currently unsupported
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_DIASPORA', 'dspr'); // Diaspora
define('NETWORK_MAIL', 'mail'); // IMAP/POP
define('NETWORK_MAIL2', 'mai2'); // extended IMAP/POP
define('NETWORK_FACEBOOK', 'face'); // Facebook API
define('NETWORK_LINKEDIN', 'lnkd'); // LinkedIn
define('NETWORK_XMPP', 'xmpp'); // XMPP
define('NETWORK_MYSPACE', 'mysp'); // MySpace
define('NETWORK_XMPP', 'xmpp'); // XMPP - Currently unsupported
define('NETWORK_MYSPACE', 'mysp'); // MySpace - Currently unsupported
define('NETWORK_GPLUS', 'goog'); // Google+
define('NETWORK_PUMPIO', 'pump'); // pump.io
define('NETWORK_TWITTER', 'twit'); // Twitter
define('NETWORK_DIASPORA2', 'dspc'); // Diaspora connector
define('NETWORK_STATUSNET', 'stac'); // Statusnet connector
define('NETWORK_APPNET', 'apdn'); // app.net
define('NETWORK_NEWS', 'nntp'); // Network News Transfer Protocol
define('NETWORK_ICALENDAR', 'ical'); // iCalendar
define('NETWORK_PNUT', 'pnut'); // pnut.io
define('NETWORK_APPNET', 'apdn'); // app.net - Dead protocol
define('NETWORK_NEWS', 'nntp'); // Network News Transfer Protocol - Currently unsupported
define('NETWORK_ICALENDAR', 'ical'); // iCalendar - Currently unsupported
define('NETWORK_PNUT', 'pnut'); // pnut.io - Currently unsupported
define('NETWORK_PHANTOM', 'unkn'); // Place holder
/**
* @}
@ -290,7 +288,6 @@ $netgroup_ids = array(
NETWORK_FEED => (-4),
NETWORK_DIASPORA => (-5),
NETWORK_MAIL => (-6),
NETWORK_MAIL2 => (-7),
NETWORK_FACEBOOK => (-8),
NETWORK_LINKEDIN => (-9),
NETWORK_XMPP => (-10),
@ -689,7 +686,7 @@ function update_db(App $a)
// Compare the current structure with the defined structure
$t = Config::get('database', 'dbupdate_' . DB_UPDATE_VERSION);
if ($t !== false) {
if (!is_null($t)) {
return;
}
@ -745,7 +742,7 @@ function run_update_function($x)
// delete the config entry to try again.
$t = Config::get('database', 'update_' . $x);
if ($t !== false) {
if (!is_null($t)) {
return false;
}
Config::set('database', 'update_' . $x, time());

View file

@ -1,6 +1,6 @@
-- ------------------------------------------
-- 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,
`received` datetime NOT NULL DEFAULT '0001-01-01 00:00:00',
PRIMARY KEY(`item-uri`),
INDEX `conversation-uri` (`conversation-uri`)
INDEX `conversation-uri` (`conversation-uri`),
INDEX `received` (`received`)
) DEFAULT COLLATE utf8mb4_general_ci;
--
@ -273,29 +274,6 @@ CREATE TABLE IF NOT EXISTS `fcontact` (
UNIQUE INDEX `url` (`url`(190))
) 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
--
@ -557,22 +535,6 @@ CREATE TABLE IF NOT EXISTS `item` (
INDEX `uid_ownerlink` (`uid`,`owner-link`(190))
) 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
--
@ -947,23 +909,6 @@ CREATE TABLE IF NOT EXISTS `sign` (
UNIQUE INDEX `iid` (`iid`)
) 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
--

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.
* **hsts** (Boolean) - Enables the sending of HTTP Strict Transport Security headers
* **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.
* **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".

View file

@ -1,10 +1,9 @@
<?php
/**
* @file include/acl_selectors.php
*/
use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\Config;
use Friendica\Database\DBM;
use Friendica\Model\GlobalContact;
@ -12,10 +11,8 @@ use Friendica\Object\Contact;
require_once "include/contact_selectors.php";
require_once "include/contact_widgets.php";
require_once "include/features.php";
require_once "mod/proxy.php";
/**
* @package acl_selectors
*/
@ -380,7 +377,7 @@ function populate_acl($user = null, $show_jotnets = false) {
'$aclModalTitle' => t('Permissions'),
'$aclModalDismiss' => t('Close'),
'$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`
AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND `success_update` >= `failure_update`
AND `network` IN ('%s','%s','%s') $sql_extra2" ,
AND `network` IN ('%s', '%s') $sql_extra2" ,
intval(local_user()),
dbesc(NETWORK_DFRN),
dbesc(NETWORK_ZOT),
dbesc(NETWORK_DIASPORA)
);
$contact_count = (int)$r[0]['c'];
@ -593,12 +589,11 @@ function acl_lookup(App $a, $out_type = 'json') {
} elseif ($type == 'm') {
$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`
AND `success_update` >= `failure_update` AND `network` IN ('%s','%s','%s')
AND `success_update` >= `failure_update` AND `network` IN ('%s', '%s')
$sql_extra2
ORDER BY `name` ASC ",
intval(local_user()),
dbesc(NETWORK_DFRN),
dbesc(NETWORK_ZOT),
dbesc(NETWORK_DIASPORA)
);
} elseif ($type == 'a') {

View file

@ -6,12 +6,14 @@
* @todo Automatically detect if incoming data is HTML or BBCode
*/
use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\System;
use Friendica\Core\Config;
use Friendica\Core\NotificationsManager;
use Friendica\Core\Worker;
use Friendica\Database\DBM;
use Friendica\Model\User;
use Friendica\Network\FKOAuth1;
use Friendica\Network\HTTPException;
use Friendica\Network\HTTPException\BadRequestException;
use Friendica\Network\HTTPException\ForbiddenException;
@ -29,7 +31,6 @@ use Friendica\Util\XML;
require_once 'include/bbcode.php';
require_once 'include/datetime.php';
require_once 'include/conversation.php';
require_once 'include/oauth.php';
require_once 'include/html2plain.php';
require_once 'mod/share.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)
{
$oauth1 = new FKOAuth1();
// login with oauth
try {
$oauth = new FKOAuth1();
list($consumer,$token) = $oauth->verify_request(OAuthRequest::from_request());
list($consumer, $token) = $oauth1->verify_request(OAuthRequest::from_request());
if (!is_null($token)) {
$oauth->loginUser($token->uid);
$oauth1->loginUser($token->uid);
call_hooks('logged_in', $a->user);
return;
}
@ -3363,9 +3364,9 @@ api_register_func('api/direct_messages', 'api_direct_messages_inbox', true);
function api_oauth_request_token($type)
{
$oauth1 = new FKOAuth1();
try {
$oauth = new FKOAuth1();
$r = $oauth->fetch_request_token(OAuthRequest::from_request());
$r = $oauth1->fetch_request_token(OAuthRequest::from_request());
} catch (Exception $e) {
echo "error=" . OAuthUtil::urlencode_rfc3986($e->getMessage());
killme();
@ -3376,9 +3377,9 @@ function api_oauth_request_token($type)
function api_oauth_access_token($type)
{
$oauth1 = new FKOAuth1();
try {
$oauth = new FKOAuth1();
$r = $oauth->fetch_access_token(OAuthRequest::from_request());
$r = $oauth1->fetch_access_token(OAuthRequest::from_request());
} catch (Exception $e) {
echo "error=". OAuthUtil::urlencode_rfc3986($e->getMessage());
killme();
@ -5100,7 +5101,7 @@ function api_friendica_profile_show($type)
$profileid = (x($_REQUEST, 'profile_id') ? $_REQUEST['profile_id'] : 0);
// 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');
// 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_XMPP => t('XMPP/IM'),
NETWORK_MYSPACE => t('MySpace'),
NETWORK_MAIL2 => t('Email'),
NETWORK_GPLUS => t('Google+'),
NETWORK_PUMPIO => t('pump.io'),
NETWORK_TWITTER => t('Twitter'),

View file

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

View file

@ -3,6 +3,7 @@
* @file include/conversation.php
*/
use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\Config;
use Friendica\Core\PConfig;
use Friendica\Core\System;
@ -915,7 +916,7 @@ function conversation(App $a, $items, $mode, $update, $preview = false) {
'$mode' => $mode,
'$user' => $a->user,
'$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;
@ -1305,7 +1306,7 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false) {
'$title' => $x['title'],
'$placeholdertitle' => t('Set title'),
'$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'),
'$permset' => t('Permission settings'),
'$shortpermset' => t('permissions'),
@ -1321,7 +1322,7 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false) {
'$lockstate' => $x['lockstate'],
'$bang' => $x['bang'],
'$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,
'$notes_cid' => $notes_cid,
'$sourceapp' => t($a->sourcename),

View file

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

View file

@ -1104,7 +1104,8 @@ class dba {
*
* $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 == '') {
return false;
}
@ -1115,17 +1116,7 @@ class dba {
$select_fields = "*";
}
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))."` = ?";
}
} else {
$condition_string = "";
}
$condition_string = self::buildCondition($condition);
$param_string = '';
$single_row = false;
@ -1147,6 +1138,11 @@ class dba {
$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']) {
$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

View file

@ -1,5 +1,7 @@
<?php
/**
* @file include/dbstructure.php
*/
use Friendica\App;
use Friendica\Core\System;
use Friendica\Core\Config;
@ -77,30 +79,10 @@ function update_fail($update_id, $error_message) {
'to_email' => $admin['email'],
'preamble' => $preamble,
'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
logger("CRITICAL: Database structure update failed: ".$retval);
}
@ -849,6 +831,7 @@ function db_definition() {
"indexes" => array(
"PRIMARY" => array("item-uri"),
"conversation-uri" => array("conversation-uri"),
"received" => array("received"),
)
);
$database["event"] = array(
@ -905,29 +888,6 @@ function db_definition() {
"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(
"fields" => array(
"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)"),
)
);
$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(
"fields" => array(
"id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
@ -1579,23 +1523,6 @@ function db_definition() {
"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(
"fields" => array(
"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\Util\Emailer;
require_once 'include/email.php';
require_once 'include/bbcode.php';
require_once 'include/html2bbcode.php';

View file

@ -5,6 +5,7 @@
*/
use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\PConfig;
use Friendica\Core\System;
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
* 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;
}
@ -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
* 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;
}

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

View file

@ -4,6 +4,7 @@
*/
use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Content\ForumManager;
use Friendica\Core\Cache;
use Friendica\Core\Config;
@ -309,7 +310,7 @@ function profile_sidebar($profile, $block = 0)
}
// 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'));
$r = q(
"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['menu'] = array(
'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
if (feature_enabled($uid, 'forumlist_profile')) {
if (Feature::isEnabled($uid, 'forumlist_profile')) {
$profile['forumlist'] = array( t('Forums:'), ForumManager::profileAdvanced($uid));
}

View file

@ -4,6 +4,7 @@
*/
use Friendica\App;
use Friendica\ParseUrl;
use Friendica\Content\Feature;
use Friendica\Core\Config;
use Friendica\Core\PConfig;
use Friendica\Core\Worker;
@ -17,12 +18,10 @@ use Friendica\Util\Lock;
require_once 'include/bbcode.php';
require_once 'include/oembed.php';
require_once 'include/salmon.php';
require_once 'include/crypto.php';
require_once 'include/tags.php';
require_once 'include/files.php';
require_once 'include/text.php';
require_once 'include/email.php';
require_once 'include/threads.php';
require_once 'include/plaintext.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
*/
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"])));
@ -1680,8 +1692,8 @@ function new_follower($importer, $contact, $datarray, $item, $sharing = false) {
dbesc($name),
dbesc($nick),
dbesc($photo),
dbesc(($sharing) ? NETWORK_ZOT : NETWORK_OSTATUS),
intval(($sharing) ? CONTACT_IS_SHARING : CONTACT_IS_FOLLOWER)
dbesc(NETWORK_OSTATUS),
intval(CONTACT_IS_FOLLOWER)
);
$r = q("SELECT `id`, `network` FROM `contact` WHERE `uid` = %d AND `url` = '%s' AND `pending` = 1 LIMIT 1",
intval($importer['uid']),
@ -2221,7 +2233,6 @@ function drop_item($id, $interactive = true) {
// Now delete them
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));
}
@ -2357,7 +2368,7 @@ function posted_dates($uid, $wall) {
function posted_date_widget($url, $uid, $wall) {
$o = '';
if (! feature_enabled($uid, 'archives')) {
if (! Feature::isEnabled($uid, 'archives')) {
return $o;
}

View file

@ -1,6 +1,9 @@
<?php
/**
* @file include/nav.php
*/
use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\Config;
use Friendica\Core\System;
use Friendica\Database\DBM;
@ -190,7 +193,7 @@ function nav_info(App $a)
$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'));
}
@ -206,7 +209,7 @@ function nav_info(App $a)
// Provide a banner/logo/whatever
$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>';
}

View file

@ -126,8 +126,8 @@ function z_fetch_url($url, $binary = false, &$redirects = 0, $opts = array())
if (x($opts, 'timeout')) {
@curl_setopt($ch, CURLOPT_TIMEOUT, $opts['timeout']);
} else {
$curl_time = intval(Config::get('system', 'curl_timeout'));
@curl_setopt($ch, CURLOPT_TIMEOUT, (($curl_time !== false) ? $curl_time : 60));
$curl_time = Config::get('system', 'curl_timeout', 60);
@curl_setopt($ch, CURLOPT_TIMEOUT, intval($curl_time));
}
// 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)) {
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
} else {
$curl_time = intval(Config::get('system', 'curl_timeout'));
curl_setopt($ch, CURLOPT_TIMEOUT, (($curl_time !== false) ? $curl_time : 60));
$curl_time = Config::get('system', 'curl_timeout', 60);
curl_setopt($ch, CURLOPT_TIMEOUT, intval($curl_time));
}
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
if (! function_exists('t')) {
function t($s) {
/**
* @brief Return the localized version of the provided string with optional string interpolation
*
* 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();
if (x($a->strings,$s)) {
if (x($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')){
function tt($singular, $plural, $count){
return $s;
}
/**
* @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;
$a = get_app();
if (x($a->strings,$singular)) {
if (x($a->strings, $singular)) {
$t = $a->strings[$singular];
$f = 'string_plural_select_' . str_replace('-','_',$lang);
if (! function_exists($f))
$f = 'string_plural_select_default';
$k = $f($count);
return is_array($t)?$t[$k]:$t;
if (is_array($t)) {
$plural_function = 'string_plural_select_' . str_replace('-', '_', $lang);
if (function_exists($plural_function)) {
$plural_function = 'string_plural_select_default';
}
$i = $plural_function($count);
$s = $t[$i];
} else {
$s = $t;
}
} elseif (string_plural_select_default($count)) {
$s = $plural;
} else {
$s = $singular;
}
if ($count!=1){
return $plural;
} else {
return $singular;
}
}}
$s = @sprintf($s, $count);
return $s;
}
// provide a fallback which will not collide with
// a function defined in any language file
if (! function_exists('string_plural_select_default')) {
function string_plural_select_default($n) {
return ($n != 1);
}}
function string_plural_select_default($n)
{
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
/**
* @file include/tags.php
*/
use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\System;
use Friendica\Database\DBM;
use Friendica\Object\Contact;
@ -302,7 +305,7 @@ function tagcloud_wall_widget($limit = 50) {
return "";
}
if(feature_enabled($a->profile['profile_uid'], 'tagadelic')) {
if(Feature::isEnabled($a->profile['profile_uid'], 'tagadelic')) {
$owner_id = Contact::getIdForURL($a->profile['url']);
if(!$owner_id) {

View file

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

View file

@ -198,12 +198,6 @@ function import_account(App $a, $file) {
case NETWORK_DIASPORA:
// send relocate message (below)
break;
case NETWORK_ZOT:
/// @TODO handle zot network
break;
case NETWORK_MAIL2:
/// @TODO ?
break;
case NETWORK_FEED:
case NETWORK_MAIL:
// 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
* of the profile owner
*/
use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\Config;
use Friendica\Core\PConfig;
use Friendica\Core\System;
@ -301,7 +301,7 @@ function cal_content(App $a) {
// Test permissions
// 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);
goaway('cal/' . $nick);
}

View file

@ -559,7 +559,7 @@ function contacts_content(App $a) {
}
$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"]));
@ -586,7 +586,7 @@ function contacts_content(App $a) {
'3' => t('Fetch 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));
if ($contact['network'] == NETWORK_DFRN)
@ -994,7 +994,7 @@ function _contact_detail_for_template($rr){
*/
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();
// 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.
* 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`
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 30 MINUTE ",
dbesc(NETWORK_MAIL2)
AND `intro`.`datetime` < UTC_TIMESTAMP() - INTERVAL 30 MINUTE "
);
if (DBM::is_result($r)) {
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'])) : '');
$url = trim($_POST['dfrn_url']);
@ -351,125 +322,25 @@ function dfrn_request_post(App $a) {
$hcard = '';
if($email_follow) {
// Detect the network
$data = Probe::uri($url);
$network = $data["network"];
if(! validate_email($url)) {
notice( t('Invalid email address.') . EOL);
return;
// 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;
}
$addr = $url;
$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.
$url = substr($url,5);
} else {
// Detect the network
$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;
$network = NETWORK_DFRN;
}
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:");
// 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(
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()
@ -877,7 +727,7 @@ function dfrn_request_content(App $a) {
$o = replace_macros($tpl,array(
'$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:'),
'$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']),
@ -886,12 +736,11 @@ function dfrn_request_content(App $a) {
'$add_note' => t('Add a personal note:'),
'$page_desc' => $page_desc,
'$friendica' => t('Friendica'),
'$statusnet' => t('StatusNet/Federated Social Web'),
'$diaspora' => t('Diaspora'),
'$statusnet' => t('GNU Social (Pleroma, Mastodon)'),
'$diaspora' => t('Diaspora (Socialhome, Hubzilla)'),
'$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:'),
'$invite_desc' => $invite_desc,
'$emailnet' => $emailnet,
'$submit' => t('Submit Request'),
'$cancel' => t('Cancel'),
'$nickname' => $a->argv[1],

View file

@ -1,6 +1,9 @@
<?php
/**
* @file mod/editpost.php
*/
use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\Config;
use Friendica\Core\System;
use Friendica\Database\DBM;
@ -131,7 +134,7 @@ function editpost_content(App $a) {
'$title' => htmlspecialchars($itm[0]['title']),
'$placeholdertitle' => t('Set title'),
'$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'),
'$lockstate' => $lockstate,
'$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']);
}
//$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');
echo replace_macros($tpl, array(
'$zhost' => $a->get_hostname(),
'$zroot' => System::baseUrl(),
'$domain' => System::baseUrl(),
'$zot_post' => System::baseUrl() . '/post',
'$bigkey' => salmon_key(Config::get('system','site_pubkey')),
));
exit();

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

@ -318,7 +318,7 @@ function check_php(&$phpath, &$checks) {
$help = "";
if (!$passed) {
$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;
$tpl = get_markup_template('field_input.tpl');
$help .= replace_macros($tpl, array(

View file

@ -1,18 +1,15 @@
<?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\Core\Config;
use Friendica\Core\PConfig;
use Friendica\Core\System;
require_once('include/email.php');
use Friendica\Protocol\Email;
function invite_post(App $a) {
@ -78,7 +75,7 @@ function invite_post(App $a) {
$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,
"From: " . $a->user['email'] . "\n"
. 'Content-type: text/plain; charset=UTF-8' . "\n"

View file

@ -1,4 +1,7 @@
<?php
/**
* @file mod/item.php
*/
/*
* 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
* posting categories go through item_store() instead of this function.
*/
use Friendica\App;
use Friendica\Core\Config;
use Friendica\Core\System;
@ -24,11 +26,11 @@ use Friendica\Model\GlobalContact;
use Friendica\Network\Probe;
use Friendica\Object\Contact;
use Friendica\Protocol\Diaspora;
use Friendica\Protocol\Email;
use Friendica\Util\Emailer;
require_once 'include/crypto.php';
require_once 'include/enotify.php';
require_once 'include/email.php';
require_once 'include/tags.php';
require_once 'include/files.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 .= t('Please contact the sender by replying to this post if you do not wish to receive these messages.') . EOL;
if (!$datarray['title']=='') {
$subject = email_header_encode($datarray['title'], 'UTF-8');
$subject = Email::encodeHeader($datarray['title'], 'UTF-8');
} 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 />';
$html = prepare_body($datarray);

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

View file

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

View file

@ -3,6 +3,7 @@
* @file mod/network.php
*/
use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Content\ForumManager;
use Friendica\Core\System;
use Friendica\Core\Config;
@ -156,8 +157,8 @@ function network_init(App $a) {
$a->page['aside'] = '';
}
$a->page['aside'] .= (feature_enabled(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(),'groups') ? group_side('network/0','network','standard',$group_id) : '');
$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'] .= networks_widget('network',(x($_GET, 'nets') ? $_GET['nets'] : ''));
$a->page['aside'] .= saved_searches($search);
@ -166,7 +167,7 @@ function network_init(App $a) {
function saved_searches($search) {
if (!feature_enabled(local_user(),'savedsearch')) {
if (!Feature::isEnabled(local_user(),'savedsearch')) {
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(
'label' => t('Personal'),
'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(
'label' => t('New'),
'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(
'label' => t('Shared Links'),
'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(
'label' => t('Starred'),
'url' => str_replace('/new', '', $cmd) . ((x($_GET,'cid')) ? '/?f=&cid=' . $_GET['cid'] : '/?f=') . '&star=1',

View file

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

View file

@ -3,6 +3,7 @@
* @file mod/photos.php
*/
use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\System;
use Friendica\Core\Config;
use Friendica\Core\Worker;
@ -895,7 +896,7 @@ function photos_post(App $a) {
/// @TODO merge these 2 if() into one?
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']);
$lon = getGps($exif['GPS']['GPSLongitude'], $exif['GPS']['GPSLongitudeRef']);
}
@ -1584,7 +1585,7 @@ function photos_content(App $a) {
$likebuttons = replace_macros($like_tpl, array(
'$id' => $link_item['id'],
'$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'),
'$return_path' => $a->query_string,
));
@ -1735,7 +1736,7 @@ function photos_content(App $a) {
$response_verbs = array('like');
if (feature_enabled($owner_uid, 'dislike')) {
if (Feature::isEnabled($owner_uid, 'dislike')) {
$response_verbs[] = 'dislike';
}
$responses = get_responses($conv_responses,$response_verbs, '', $link_item);

View file

@ -3,6 +3,7 @@
* @file include/ping.php
*/
use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Content\ForumManager;
use Friendica\Core\Cache;
use Friendica\Core\System;
@ -149,7 +150,7 @@ function ping_init(App $a)
}
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
$group_counts = groups_count_unseen();
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();
if (DBM::is_result($forums_counts)) {
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
*/
use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\Config;
use Friendica\Core\PConfig;
use Friendica\Core\System;
@ -673,10 +674,10 @@ function profiles_content(App $a) {
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_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_action' => t('Profile Actions'),
@ -754,7 +755,7 @@ function profiles_content(App $a) {
return $o;
} else {
// 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",
local_user()
);

View file

@ -1,7 +1,7 @@
<?php
/**
* Diaspora endpoint
* @file mod/receive.php
* @brief Diaspora endpoint
*/
use Friendica\App;
@ -9,10 +9,14 @@ use Friendica\Core\Config;
use Friendica\Database\DBM;
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'));
if (!$enabled) {
logger('mod-diaspora: disabled');
@ -44,7 +48,7 @@ function receive_post(App $a) {
if (!$xml) {
$postdata = file_get_contents("php://input");
if ($postdata == '') {
if ($postdata == '') {
http_status_exit(500);
}
@ -80,4 +84,3 @@ function receive_post(App $a) {
http_status_exit(($ret) ? 200 : 500);
// NOTREACHED
}

View file

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

View file

@ -6,11 +6,10 @@ use Friendica\Core\System;
use Friendica\Core\Worker;
use Friendica\Database\DBM;
require_once('include/enotify.php');
require_once('include/user.php');
function user_allow($hash) {
require_once 'include/enotify.php';
function user_allow($hash)
{
$a = get_app();
$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;
}
@ -26,7 +25,7 @@ function user_allow($hash) {
intval($register[0]['uid'])
);
if (! DBM::is_result($user)) {
if (!DBM::is_result($user)) {
killme();
}
@ -44,14 +43,14 @@ function user_allow($hash) {
);
if (DBM::is_result($r) && $r[0]['net-publish']) {
$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);
}
}
push_lang($register[0]['language']);
send_register_open_eml(
User::sendRegisterOpenEmail(
$user[0]['email'],
$a->config['sitename'],
System::baseUrl(),
@ -60,20 +59,17 @@ function user_allow($hash) {
pop_lang();
if($res) {
info( t('Account approved.') . EOL );
if ($res) {
info(t('Account approved.') . EOL);
return true;
}
}
// This does not have to go through user_remove() and save the nickname
// permanently against re-registration, as the person was not yet
// 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",
dbesc($hash)
);
@ -91,23 +87,22 @@ function user_deny($hash) {
notice(sprintf(t('Registration revoked for %s'), $user[0]['username']) . EOL);
return true;
}
function regmod_content(App $a) {
function regmod_content(App $a)
{
global $lang;
$_SESSION['return_url'] = $a->cmd;
if (! local_user()) {
info( t('Please login.') . EOL);
if (!local_user()) {
info(t('Please login.') . EOL);
$o .= '<br /><br />' . login(($a->config['register_policy'] == REGISTER_CLOSED) ? 0 : 1);
return $o;
}
if ((!is_site_admin()) || (x($_SESSION,'submanage') && intval($_SESSION['submanage']))) {
notice( t('Permission denied.') . EOL);
if ((!is_site_admin()) || (x($_SESSION, 'submanage') && intval($_SESSION['submanage']))) {
notice(t('Permission denied.') . EOL);
return '';
}
@ -115,20 +110,18 @@ function regmod_content(App $a) {
killme();
}
$cmd = $a->argv[1];
$cmd = $a->argv[1];
$hash = $a->argv[2];
if ($cmd === 'deny') {
user_deny($hash);
goaway(System::baseUrl()."/admin/users/");
goaway(System::baseUrl() . "/admin/users/");
killme();
}
if ($cmd === 'allow') {
user_allow($hash);
goaway(System::baseUrl()."/admin/users/");
goaway(System::baseUrl() . "/admin/users/");
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\Database\DBM;
use Friendica\Protocol\OStatus;
use Friendica\Protocol\Salmon;
require_once 'include/salmon.php';
require_once 'include/crypto.php';
require_once 'include/items.php';
require_once 'include/follow.php';
@ -103,7 +103,7 @@ function salmon_post(App $a) {
logger('mod-salmon: Fetching key for ' . $author_link);
$key = get_salmon_key($author_link,$keyhash);
$key = Salmon::getKey($author_link, $keyhash);
if(! $key) {
logger('mod-salmon: Could not retrieve author key.');

View file

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

View file

@ -3,6 +3,7 @@
* @file mod/settings.php
*/
use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\System;
use Friendica\Core\Worker;
use Friendica\Core\Config;
@ -10,6 +11,7 @@ use Friendica\Core\PConfig;
use Friendica\Database\DBM;
use Friendica\Model\GlobalContact;
use Friendica\Model\User;
use Friendica\Protocol\Email;
require_once 'include/group.php';
@ -51,7 +53,7 @@ function settings_init(App $a) {
),
);
if (get_features()) {
if (Feature::get()) {
$tabs[] = array(
'label' => t('Additional features'),
'url' => 'settings/features',
@ -259,12 +261,12 @@ function settings_post(App $a) {
);
if (DBM::is_result($r)) {
$eacct = $r[0];
require_once('include/email.php');
$mb = construct_mailbox_name($eacct);
$mb = Email::constructMailboxName($eacct);
if (strlen($eacct['server'])) {
$dcrpass = '';
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);
if (!$mbox) {
$failed = true;
@ -347,7 +349,6 @@ function settings_post(App $a) {
}
}
$r = q("UPDATE `user` SET `theme` = '%s' WHERE `uid` = %d",
dbesc($theme),
intval(local_user())
@ -369,7 +370,6 @@ function settings_post(App $a) {
call_hooks('settings_post', $_POST);
if (x($_POST, 'password') || x($_POST, 'confirm')) {
$newpass = $_POST['password'];
$confirm = $_POST['confirm'];
@ -384,9 +384,8 @@ function settings_post(App $a) {
$err = true;
}
// check if the old password was supplied correctly before
// changing it to the new value
if (User::authenticate(intval(local_user()), $_POST['opassword'])) {
// check if the old password was supplied correctly before changing it to the new value
if (!User::authenticate(intval(local_user()), $_POST['opassword'])) {
notice(t('Wrong password.') . EOL);
$err = true;
}
@ -397,14 +396,14 @@ function settings_post(App $a) {
dbesc($password),
intval(local_user())
);
if ($r)
if ($r) {
info(t('Password changed.') . EOL);
else
} else {
notice(t('Password update failed. Please try again.') . EOL);
}
}
}
$username = ((x($_POST, 'username')) ? notags(trim($_POST['username'])) : '');
$email = ((x($_POST, 'email')) ? notags(trim($_POST['email'])) : '');
$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')) {
$arr = array();
$features = get_features();
$features = Feature::get();
foreach ($features as $fname => $fdata) {
$arr[$fname] = array();
$arr[$fname][0] = $fdata[0];
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,
'$hcard_url' => System::baseUrl() . '/hcard/' . $r['nickname'],
'$atom' => System::baseUrl() . '/dfrn_poll/' . $r['nickname'],
'$zot_post' => System::baseUrl() . '/post/' . $r['nickname'],
'$poco_url' => System::baseUrl() . '/poco/' . $r['nickname'],
'$photo' => System::baseUrl() . '/photo/profile/' . $r['uid'] . '.jpg',
'$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;
use Friendica\App;
use Friendica\Content\Feature;
use Friendica\Core\System;
use Friendica\Database\DBM;
use dba;
@ -82,7 +83,7 @@ class ForumManager
*/
public static function widget($uid, $cid = 0)
{
if (! intval(feature_enabled(local_user(), 'forumlist_widget'))) {
if (! intval(Feature::isEnabled(local_user(), 'forumlist_widget'))) {
return;
}
@ -141,7 +142,7 @@ class ForumManager
*/
public static function profileAdvanced($uid)
{
$profile = intval(feature_enabled($uid, 'forumlist_profile'));
$profile = intval(Feature::isEnabled($uid, 'forumlist_profile'));
if (! $profile) {
return;
}

View file

@ -7,19 +7,41 @@
namespace Friendica\Model;
use Friendica\Core\Config;
use Friendica\Core\System;
use Friendica\Core\Worker;
use Friendica\Database\DBM;
use Friendica\Object\Contact;
use Friendica\Object\Photo;
use dba;
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/text.php';
/**
* @brief This class handles User related functions
*/
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)
{
if (is_object($user_info)) {
@ -66,6 +88,424 @@ class User
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
* @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\Database\DBM;
use Friendica\Object\Profile;
use Friendica\Protocol\Email;
use Friendica\Util\XML;
use dba;
@ -22,7 +23,6 @@ use DomXPath;
use DOMDocument;
require_once 'include/feed.php';
require_once 'include/email.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));
if (DBM::is_result($x) && DBM::is_result($r)) {
$mailbox = construct_mailbox_name($r[0]);
$mailbox = Email::constructMailboxName($r[0]);
$password = '';
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) {
return false;
}
}
$msgs = email_poll($mbox, $uri);
$msgs = Email::poll($mbox, $uri);
logger('searching '.$uri.', '.count($msgs).' messages found.', LOGGER_DEBUG);
if (!count($msgs)) {
@ -1546,7 +1546,7 @@ class Probe
$data["notify"] = 'smtp '.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)) {
$adr = imap_rfc822_parse_adrlist($x[0]->from, '');
} elseif (stristr($x[0]->to, $uri)) {

View file

@ -17,6 +17,7 @@ use Friendica\Object\Photo;
use Friendica\Protocol\Diaspora;
use Friendica\Protocol\DFRN;
use Friendica\Protocol\OStatus;
use Friendica\Protocol\Salmon;
use dba;
require_once 'boot.php';
@ -27,6 +28,52 @@ require_once 'include/text.php';
*/
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
*
@ -71,8 +118,7 @@ class Contact extends BaseObject
$slap = OStatus::salmon($item, $user);
if ((x($contact, 'notify')) && (strlen($contact['notify']))) {
require_once 'include/salmon.php';
slapper($user, $contact['notify'], $slap);
Salmon::slapper($user, $contact['notify'], $slap);
}
} elseif ($contact['network'] === NETWORK_DIASPORA) {
Diaspora::sendUnshare($user, $contact);
@ -95,8 +141,8 @@ class Contact extends BaseObject
*/
public static function markForArchival(array $contact)
{
// Contact already archived, nothing to do
if ($contact['archive']) {
// Contact already archived or "self" contact? => nothing to do
if ($contact['archive'] || $contact['self']) {
return;
}
@ -104,7 +150,7 @@ class Contact extends BaseObject
dba::update('contact', array('term-date' => datetime_convert()), array('id' => $contact['id']));
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 {
/* @todo
@ -123,7 +169,7 @@ class Contact extends BaseObject
dba::update('contact', array('archive' => 1), array('id' => $contact['id']));
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)
{
$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);
// 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 int $uid User id of contact owner

View file

@ -5,6 +5,7 @@
namespace Friendica\Object;
use Friendica\BaseObject;
use Friendica\Content\Feature;
use Friendica\Core\Config;
use Friendica\Core\PConfig;
use Friendica\Database\DBM;
@ -161,7 +162,7 @@ class Item extends BaseObject
$drop = array(
'dropping' => $dropping,
'pagedrop' => ((feature_enabled($conv->getProfileOwner(), 'multi_delete')) ? $item['pagedrop'] : ''),
'pagedrop' => ((Feature::isEnabled($conv->getProfileOwner(), 'multi_delete')) ? $item['pagedrop'] : ''),
'select' => t('Select'),
'delete' => t('Delete'),
);
@ -279,7 +280,7 @@ class Item extends BaseObject
}
$tagger = '';
if (feature_enabled($conv->getProfileOwner(), 'commtag')) {
if (Feature::isEnabled($conv->getProfileOwner(), 'commtag')) {
$tagger = array(
'add' => t("add tag"),
'class' => "",
@ -293,7 +294,7 @@ class Item extends BaseObject
if ($conv->isWritable()) {
$buttons = array(
'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) {
$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_name' => htmlentities($owner_name_e),
'plink' => get_plink($item),
'edpost' => ((feature_enabled($conv->getProfileOwner(), 'edit_posts')) ? $edpost : ''),
'edpost' => ((Feature::isEnabled($conv->getProfileOwner(), 'edit_posts')) ? $edpost : ''),
'isstarred' => $isstarred,
'star' => ((feature_enabled($conv->getProfileOwner(), 'star_posts')) ? $star : ''),
'ignore' => ((feature_enabled($conv->getProfileOwner(), 'ignore_posts')) ? $ignore : ''),
'star' => ((Feature::isEnabled($conv->getProfileOwner(), 'star_posts')) ? $star : ''),
'ignore' => ((Feature::isEnabled($conv->getProfileOwner(), 'ignore_posts')) ? $ignore : ''),
'tagger' => $tagger,
'filer' => ((feature_enabled($conv->getProfileOwner(), 'filing')) ? $filer : ''),
'filer' => ((Feature::isEnabled($conv->getProfileOwner(), 'filing')) ? $filer : ''),
'drop' => $drop,
'vote' => $buttons,
'like' => $responses['like']['output'],
@ -791,7 +792,7 @@ class Item extends BaseObject
'$edimg' => t('Image'),
'$edurl' => t('Link'),
'$edvideo' => t('Video'),
'$preview' => ((feature_enabled($conv->getProfileOwner(), 'preview')) ? t('Preview') : ''),
'$preview' => ((Feature::isEnabled($conv->getProfileOwner(), 'preview')) ? t('Preview') : ''),
'$indent' => $indent,
'$sourceapp' => t($a->sourcename),
'$ww' => (($conv->getMode() === 'network') ? $ww : ''),

View file

@ -1339,10 +1339,6 @@ class Diaspora
if ($r) {
$cid = $r[0]["id"];
$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 {
$cid = $contact["id"];
$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
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
$current = $contact;
unset($current['name-date']);

View file

@ -1343,14 +1343,17 @@ class PortableContact
// Disvover Mastodon servers
if (!Config::get('system', 'ostatus_disabled')) {
$serverdata = fetch_url("https://instances.mastodon.xyz/instances.json");
if ($serverdata) {
$servers = json_decode($serverdata);
foreach ($servers as $server) {
$url = (is_null($server->https_score) ? 'http' : 'https').'://'.$server->name;
Worker::add(PRIORITY_LOW, "DiscoverPoCo", "server", $url);
$accesstoken = Config::get('system', 'instances_social_key');
if (!empty($accesstoken)) {
$api = 'https://instances.social/api/1.0/instances/list?count=0';
$header = array('Authorization: Bearer '.$accesstoken);
$serverdata = z_fetch_url($api, false, $redirects, ['headers' => $header]);
if ($serverdata['success']) {
$servers = json_decode($serverdata['body']);
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;
use Friendica\Core\PConfig;
require_once 'include/email.php';
use Friendica\Protocol\Email;
/**
* @breif class to handle emailing
* @brief class to handle emailing
*/
class Emailer
{
@ -38,8 +37,8 @@ class Emailer
$email_textonly = PConfig::get($params['uid'], "system", "email_textonly");
}
$fromName = email_header_encode(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');
$fromName = Email::encodeHeader(html_entity_decode($params['fromName'], ENT_QUOTES, 'UTF-8'), 'UTF-8');
$messageSubject = Email::encodeHeader(html_entity_decode($params['messageSubject'], ENT_QUOTES, 'UTF-8'), 'UTF-8');
// generate a mime boundary
$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`
ON `contact`.`uid` = `user`.`uid` AND `contact`.`rel` IN (%d, %d) AND `contact`.`poll` != ''
AND `contact`.`network` IN ('%s', '%s', '%s', '%s', '%s', '%s') $sql_extra
AND NOT `contact`.`self` AND NOT `contact`.`blocked` AND NOT `contact`.`readonly`
AND NOT `contact`.`archive`
WHERE NOT `user`.`account_expired` AND NOT `user`.`account_removed` $abandon_sql ORDER BY RAND()",
intval(CONTACT_IS_SHARING),
intval(CONTACT_IS_FRIEND),
ON `contact`.`uid` = `user`.`uid` AND `contact`.`poll` != ''
AND `contact`.`network` IN ('%s', '%s', '%s', '%s', '%s') $sql_extra
AND NOT `contact`.`self` AND NOT `contact`.`blocked`
WHERE NOT `user`.`account_expired` AND NOT `user`.`account_removed` $abandon_sql",
dbesc(NETWORK_DFRN),
dbesc(NETWORK_ZOT),
dbesc(NETWORK_OSTATUS),
dbesc(NETWORK_DIASPORA),
dbesc(NETWORK_FEED),
dbesc(NETWORK_MAIL),
dbesc(NETWORK_MAIL2)
dbesc(NETWORK_MAIL)
);
if (!DBM::is_result($contacts)) {
return;
}
foreach ($contacts as $c) {
foreach ($contacts as $contact) {
$res = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1",
intval($c['id'])
);
if (!DBM::is_result($res)) {
continue;
if ($manual_id) {
$contact['last-update'] = NULL_DATE;
}
foreach ($res as $contact) {
$xml = false;
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']);
// Friendica and OStatus are checked once a day
if (in_array($contact['network'], array(NETWORK_DFRN, NETWORK_OSTATUS))) {
$contact['priority'] = 2;
}
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
/**
* @file src/worker/CronJobs.php
*/
@ -11,25 +12,27 @@ use Friendica\Core\Config;
use Friendica\Database\DBM;
use Friendica\Model\GlobalContact;
use Friendica\Network\Probe;
use Friendica\Object\Contact;
use Friendica\Protocol\PortableContact;
use dba;
class CronJobs {
public static function execute($command = ''){
class CronJobs
{
public static function execute($command = '')
{
global $a;
require_once 'include/datetime.php';
require_once 'include/post_update.php';
require_once 'mod/nodeinfo.php';
require_once 'include/photos.php';
require_once 'include/user.php';
// No parameter set? So return
if ($command == '') {
return;
}
logger("Starting cronjob ".$command, LOGGER_DEBUG);
logger("Starting cronjob " . $command, LOGGER_DEBUG);
// Call possible post update functions
// see include/post_update.php for more details
@ -78,7 +81,7 @@ class CronJobs {
return;
}
logger("Xronjob ".$command." is unknown.", LOGGER_DEBUG);
logger("Xronjob " . $command . " is unknown.", LOGGER_DEBUG);
return;
}
@ -86,7 +89,8 @@ class CronJobs {
/**
* @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`");
if (!DBM::is_result($r)) {
return;
@ -100,7 +104,8 @@ class CronJobs {
/**
* @brief Expire and remove user entries
*/
private static function expireAndRemoveUsers() {
private static function expireAndRemoveUsers()
{
// expire any expired accounts
q("UPDATE user SET `account_expired` = 1 where `account_expired` = 0
AND `account_expires_on` > '%s'
@ -120,9 +125,9 @@ class CronJobs {
*
* @param App $a
*/
private static function clearCache(App $a) {
$last = Config::get('system','cache_last_cleared');
private static function clearCache(App $a)
{
$last = Config::get('system', 'cache_last_cleared');
if ($last) {
$next = $last + (3600); // Once per hour
@ -142,16 +147,16 @@ class CronJobs {
clear_cache();
// 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_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
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) {
$cachetime = PROXY_DEFAULT_TIME;
}
@ -166,13 +171,13 @@ class CronJobs {
dba::delete('parsed_url', array("`created` < NOW() - INTERVAL 3 MONTH"));
// 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) {
$max_tablesize = 100 * 1000000; // Default are 100 MB
}
if ($max_tablesize > 0) {
// 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) {
$fragmentation_level = 0.3; // Default value is 30%
}
@ -194,7 +199,7 @@ class CronJobs {
// Calculate fragmentation
$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
if ($fragmentation < $fragmentation_level) {
@ -202,12 +207,12 @@ class CronJobs {
}
// So optimize it
logger("Optimize Table ".$table["Name"], LOGGER_DEBUG);
logger("Optimize Table " . $table["Name"], LOGGER_DEBUG);
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
*/
private static function repairDiaspora(App $a) {
private static function repairDiaspora(App $a)
{
$starttime = time();
$r = q("SELECT `id`, `url` FROM `contact`
@ -241,7 +246,7 @@ class CronJobs {
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",
dbesc($data["batch"]), dbesc($data["notify"]), dbesc($data["poll"]), dbesc($data["pubkey"]),
intval($contact["id"]));
@ -252,15 +257,15 @@ class CronJobs {
* @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.
// 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`)");
if (DBM::is_result($r)) {
foreach ($r AS $user) {
logger('Create missing self contact for user '.$user['uid']);
user_create_self_contact($user['uid']);
logger('Create missing self contact for user ' . $user['uid']);
Contact::createSelfFromUserId($user['uid']);
}
}

View file

@ -17,19 +17,26 @@ class DBClean {
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
$days = Config::get('system', 'dbclean-expire-days', 0);
if ($stage == 0) {
for ($i = 1; $i <= 9; $i++) {
// Execute the background script for a step when it isn't finished.
// Execute step 8 and 9 only when $days is defined.
if (!Config::get('system', 'finished-dbclean-'.$i, false) && (($i < 8) || ($days > 0))) {
Worker::add(PRIORITY_LOW, 'DBClean', $i);
}
for ($i = 1; $i <= 10; $i++) {
// Execute the background script for a step when it isn't finished.
// Execute step 8 and 9 only when $days is defined.
if (!Config::get('system', 'finished-dbclean-'.$i, false) && (($i < 8) || ($i > 9) || ($days > 0))) {
Worker::add(PRIORITY_LOW, 'DBClean', $i);
}
} else {
self::removeOrphans($stage);
}
}
@ -39,17 +46,18 @@ class DBClean {
*
* Values for $stage:
* ------------------
* 1: Old global item entries from item table without user copy.
* 2: Items without parents.
* 3: Orphaned data from thread table.
* 4: Orphaned data from notify table.
* 5: Orphaned data from notify-threads table.
* 6: Orphaned data from sign table.
* 7: Orphaned data from term table.
* 8: Expired threads.
* 9: Old global item entries from expired threads
* 1: Old global item entries from item table without user copy.
* 2: Items without parents.
* 3: Orphaned data from thread table.
* 4: Orphaned data from notify table.
* 5: Orphaned data from notify-threads table.
* 6: Orphaned data from sign table.
* 7: Orphaned data from term table.
* 8: 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;
$count = 0;
@ -75,6 +83,7 @@ class DBClean {
$last_id = $orphan["id"];
dba::delete('item', array('id' => $orphan["id"]));
}
Worker::add(PRIORITY_MEDIUM, 'DBClean', 1, $last_id);
} else {
logger("No global item orphans found");
}
@ -96,6 +105,7 @@ class DBClean {
$last_id = $orphan["id"];
dba::delete('item', array('id' => $orphan["id"]));
}
Worker::add(PRIORITY_MEDIUM, 'DBClean', 2, $last_id);
} else {
logger("No item orphans without parents found");
}
@ -121,6 +131,7 @@ class DBClean {
$last_id = $orphan["iid"];
dba::delete('thread', array('iid' => $orphan["iid"]));
}
Worker::add(PRIORITY_MEDIUM, 'DBClean', 3, $last_id);
} else {
logger("No thread orphans found");
}
@ -146,6 +157,7 @@ class DBClean {
$last_id = $orphan["id"];
dba::delete('notify', array('iid' => $orphan["iid"]));
}
Worker::add(PRIORITY_MEDIUM, 'DBClean', 4, $last_id);
} else {
logger("No notify orphans found");
}
@ -171,6 +183,7 @@ class DBClean {
$last_id = $orphan["id"];
dba::delete('notify-threads', array('id' => $orphan["id"]));
}
Worker::add(PRIORITY_MEDIUM, 'DBClean', 5, $last_id);
} else {
logger("No notify-threads orphans found");
}
@ -196,6 +209,7 @@ class DBClean {
$last_id = $orphan["id"];
dba::delete('sign', array('iid' => $orphan["iid"]));
}
Worker::add(PRIORITY_MEDIUM, 'DBClean', 6, $last_id);
} else {
logger("No sign orphans found");
}
@ -221,6 +235,7 @@ class DBClean {
$last_id = $orphan["tid"];
dba::delete('term', array('oid' => $orphan["oid"]));
}
Worker::add(PRIORITY_MEDIUM, 'DBClean', 7, $last_id);
} else {
logger("No term orphans found");
}
@ -259,6 +274,7 @@ class DBClean {
$last_id = $thread["iid"];
dba::delete('thread', array('iid' => $thread["iid"]));
}
Worker::add(PRIORITY_MEDIUM, 'DBClean', 8, $last_id);
} else {
logger("No expired threads found");
}
@ -286,6 +302,7 @@ class DBClean {
$last_id = $orphan["id"];
dba::delete('item', array('id' => $orphan["id"]));
}
Worker::add(PRIORITY_MEDIUM, 'DBClean', 9, $last_id);
} else {
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);
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
if (($stage != 0) && ($count > 0)) {
Worker::add(PRIORITY_MEDIUM, 'dbclean');
logger("Deleting old conversations. Last created: ".$last_id);
$r = dba::p("SELECT `received`, `item-uri` FROM `conversation`
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\Protocol\Diaspora;
use Friendica\Protocol\DFRN;
use Friendica\Protocol\Email;
require_once 'include/queue_fn.php';
require_once 'include/html2plain.php';
require_once 'include/datetime.php';
require_once 'include/items.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
@ -376,7 +376,6 @@ class Delivery {
break;
case NETWORK_MAIL:
case NETWORK_MAIL2:
if (Config::get('system','dfrn_only')) {
break;
@ -418,36 +417,36 @@ class Delivery {
if ($r1 && $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
if (($contact['rel'] == CONTACT_IS_FRIEND) && !$contact['blocked']) {
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";
} 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 {
$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)
// $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: Data: ".print_r($it, true), LOGGER_DEBUG);
//logger("Mail: Data: ".print_r($it, true), LOGGER_DATA);
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 (($it["thr-parent"] != "") && ($it["thr-parent"] != $it["parent-uri"]))
$headers .= " <".iri2msgid($it["thr-parent"]).">";
$headers .= " <".Email::iri2msgid($it["thr-parent"]).">";
$headers .= "\n";
if (!$it['title']) {
@ -469,7 +468,7 @@ class Delivery {
if (strncasecmp($subject,'RE:',3))
$subject = 'Re: '.$subject;
}
email_send($addr, $subject, $headers, $it);
Email::send($addr, $subject, $headers, $it);
}
break;

View file

@ -11,15 +11,14 @@ use Friendica\Network\Probe;
use Friendica\Object\Contact;
use Friendica\Protocol\Diaspora;
use Friendica\Protocol\OStatus;
use Friendica\Protocol\Salmon;
use dba;
require_once 'include/queue_fn.php';
require_once 'include/html2plain.php';
require_once 'include/salmon.php';
require_once 'include/datetime.php';
require_once 'include/items.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
@ -448,7 +447,7 @@ class Notifier {
// 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."')";
} 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 {
$public_message = false;
@ -506,11 +505,11 @@ class Notifier {
// 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 (!Config::get('system','dfrn_only')) {
if (!Config::get('system', 'dfrn_only')) {
foreach ($url_recipients as $url) {
if ($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
}
}
@ -538,9 +537,8 @@ class Notifier {
}
$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_MAIL2),
intval($owner['uid']),
intval(CONTACT_IS_SHARING)
);

View file

@ -8,6 +8,7 @@ use Friendica\Core\Config;
use Friendica\Core\PConfig;
use Friendica\Database\DBM;
use Friendica\Object\Contact;
use Friendica\Protocol\Email;
use Friendica\Protocol\PortableContact;
use dba;
@ -20,10 +21,9 @@ Class OnePoll
require_once 'include/datetime.php';
require_once 'include/items.php';
require_once 'include/email.php';
require_once 'include/queue_fn.php';
logger('onepoll: start');
logger('start');
$manual_id = 0;
$generation = 0;
@ -36,36 +36,18 @@ Class OnePoll
}
if (!$contact_id) {
logger('onepoll: no contact');
logger('no contact');
return;
}
$d = datetime_convert();
// Only poll from those with suitable relationships,
// and which have a polling address and ignore Diaspora since
// 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)) {
$contact = dba::select('contact', [], ['id' => $contact_id], ['limit' => 1]);
if (!DBM::is_result($contact)) {
logger('Contact not found or cannot be used.');
return;
}
$contact = $contacts[0];
$importer_uid = $contact['uid'];
// 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?)
/// @TODO Check whether this is possible with Redmatrix
if ($contact["network"] == NETWORK_DIASPORA) {
if (PortableContact::updateNeeded($contact["created"], $contact["last-item"], $contact["failure_update"], $contact["success_update"])) {
$last_updated = PortableContact::lastUpdated($contact["url"]);
$updated = datetime_convert();
if ($last_updated) {
$fields = array('last-item' => $last_updated, 'last-update' => $updated, 'success_update' => $updated);
dba::update('contact', $fields, array('id' => $contact['id']));
} else {
dba::update('contact', array('last-update' => $updated, 'failure_update' => $updated), array('id' => $contact['id']));
// Diaspora users, archived users and followers are only checked if they still exist.
if ($contact['archive'] || ($contact["network"] == NETWORK_DIASPORA) || ($contact["rel"] == CONTACT_IS_FOLLOWER)) {
$last_updated = PortableContact::lastUpdated($contact["url"]);
$updated = datetime_convert();
if ($last_updated) {
logger('Contact '.$contact['id'].' had last update on '.$last_updated, LOGGER_DEBUG);
// The last public item can be older than the last item we got
if ($last_updated < $contact['last-item']) {
$last_updated = $contact['last-item'];
}
$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;
}
@ -102,8 +91,8 @@ Class OnePoll
$t = $contact['last-update'];
if ($contact['subhub']) {
$poll_interval = Config::get('system', 'pushpoll_frequency');
$contact['priority'] = (($poll_interval !== false) ? intval($poll_interval) : 3);
$poll_interval = Config::get('system', 'pushpoll_frequency', 3);
$contact['priority'] = intval($poll_interval);
$hub_update = false;
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 (!PortableContact::reachable($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;
}
if (!update_contact($contact["id"])) {
Contact::markForArchival($contact);
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;
} else {
Contact::unmarkForArchival($contact);
@ -136,6 +131,9 @@ Class OnePoll
if ($importer_uid == 0) {
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;
}
@ -145,12 +143,15 @@ Class OnePoll
if (!DBM::is_result($r)) {
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;
}
$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) {
$idtosend = $orig_id = (($contact['dfrn-id']) ? $contact['dfrn-id'] : $contact['issued-id']);
@ -179,6 +180,9 @@ Class OnePoll
$ret = z_fetch_url($url);
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;
}
@ -186,7 +190,7 @@ Class OnePoll
$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) {
@ -200,8 +204,7 @@ Class OnePoll
// set the last-update so we don't keep polling
$fields = array('last-update' => datetime_convert(), 'failure_update' => datetime_convert());
dba::update('contact', $fields, array('id' => $contact['id']));
self::updateContact($contact, $fields);
return;
}
@ -211,8 +214,7 @@ Class OnePoll
Contact::markForArchival($contact);
$fields = array('last-update' => datetime_convert(), 'failure_update' => datetime_convert());
dba::update('contact', $fields, array('id' => $contact['id']));
self::updateContact($contact, $fields);
return;
}
@ -225,7 +227,7 @@ Class OnePoll
// we may not be friends anymore. Will keep trying for one month.
// set the last-update so we don't keep polling
$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);
} elseif ($contact['term-date'] > NULL_DATE) {
@ -234,6 +236,8 @@ Class OnePoll
}
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;
}
@ -264,8 +268,12 @@ Class OnePoll
}
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
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;
}
@ -298,25 +306,33 @@ Class OnePoll
// Are we allowed to import from this person?
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;
}
$cookiejar = tempnam(get_temppath(), 'cookiejar-onepoll-');
$ret = z_fetch_url($contact['poll'], false, $redirects, array('cookiejar' => $cookiejar));
unlink($cookiejar);
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;
}
$xml = $ret['body'];
unlink($cookiejar);
} elseif ($contact['network'] === NETWORK_MAIL || $contact['network'] === NETWORK_MAIL2) {
} elseif ($contact['network'] === NETWORK_MAIL) {
logger("Mail: Fetching for ".$contact['addr'], LOGGER_DEBUG);
$mail_disabled = ((function_exists('imap_open') && (! Config::get('system', 'imap_disabled'))) ? 0 : 1);
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;
}
@ -328,10 +344,10 @@ Class OnePoll
$condition = array("`server` != '' AND `uid` = ?", $importer_uid);
$mailconf = dba::select('mailacct', array(), $condition, array('limit' => 1));
if (DBM::is_result($x) && DBM::is_result($mailconf)) {
$mailbox = construct_mailbox_name($mailconf);
$mailbox = Email::constructMailboxName($mailconf);
$password = '';
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);
logger("Mail: Connect to " . $mailconf['user']);
if ($mbox) {
@ -344,14 +360,14 @@ Class OnePoll
}
if ($mbox) {
$msgs = email_poll($mbox, $contact['addr']);
$msgs = Email::poll($mbox, $contact['addr']);
if (count($msgs)) {
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)) {
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 {
$msgs = array_combine($msgs, $metas);
@ -361,10 +377,9 @@ Class OnePoll
$datarray = array();
$datarray['verb'] = ACTIVITY_POST;
$datarray['object-type'] = ACTIVITY_OBJ_NOTE;
// $meta = email_msg_meta($mbox, $msg_uid);
// $headers = email_msg_headers($mbox, $msg_uid);
// $meta = Email::messageMeta($mbox, $msg_uid);
$datarray['uri'] = msgid2iri(trim($meta->message_id, '<>'));
$datarray['uri'] = Email::msgid2iri(trim($meta->message_id, '<>'));
// Have we seen it before?
$fields = array('deleted', 'id');
@ -416,7 +431,7 @@ Class OnePoll
$refs_arr = explode(' ', $raw_refs);
if (count($refs_arr)) {
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);
@ -466,7 +481,7 @@ Class OnePoll
$datarray['parent-uri'] = $datarray['uri'];
}
$r = email_get_msg($mbox, $msg_uid, $reply);
$r = Email::getMessage($mbox, $msg_uid, $reply);
if (!$r) {
logger("Mail: can't fetch msg ".$msg_uid." for ".$mailconf['user']);
continue;
@ -560,8 +575,8 @@ Class OnePoll
logger('post_handshake: response from ' . $url . ' did not contain XML.');
$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;
}
@ -605,13 +620,15 @@ Class OnePoll
$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']));
Contact::unmarkForArchival($contact);
} elseif (in_array($contact["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, NETWORK_FEED))) {
$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']));
Contact::markForArchival($contact);
} else {
dba::update('contact', array('last-update' => $updated), array('id' => $contact['id']));
}
@ -626,4 +643,15 @@ Class OnePoll
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
/**
* @file src/Worker/Queue.php
*/
namespace Friendica\Worker;
use Friendica\Core\Cache;
@ -13,13 +11,13 @@ use Friendica\Database\DBM;
use Friendica\Protocol\Diaspora;
use Friendica\Protocol\DFRN;
use Friendica\Protocol\PortableContact;
use Friendica\Protocol\Salmon;
use dba;
require_once 'include/queue_fn.php';
require_once 'include/datetime.php';
require_once 'include/items.php';
require_once 'include/bbcode.php';
require_once 'include/salmon.php';
class Queue
{
@ -141,7 +139,7 @@ class Queue
case NETWORK_OSTATUS:
if ($contact['notify']) {
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)) {
update_queue_time($q_item['id']);

View file

@ -1,6 +1,6 @@
<?php
define('UPDATE_VERSION' , 1235);
define('UPDATE_VERSION' , 1236);
use Friendica\Core\Config;
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`)",
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`)",
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`)",
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`)",
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
<?php
/**
* @brief tool to block an account from the node
*
@ -17,49 +16,39 @@
* Author: Tobias Diekershoff
*
* License: AGPLv3 or later, same as Friendica
**/
*/
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 " profile_url ...... The URL of the profile you want to silence\r\n";
echo "\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";
exit(0);
}
use Friendica\Database\DBM;
use Friendica\Network\Probe;
use Friendica\BaseObject;
use Friendica\Object\Contact;
require_once 'boot.php';
require_once 'include/dba.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);
unset($db_host, $db_user, $db_pass, $db_data);
/**
* 1. make nurl from last parameter
* 2. check DB (contact) if there is a contact with uid=0 and that nurl, get the ID
* 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.';
$contact_id = Contact::getIdForURL($argv[1], 0);
if (!$contact_id) {
echo t('Could not find any contact entry for this URL (%s)', $nurl);
echo "\r\n";
exit(1);
}
$nurl = normalise_link($net['url']);
$r = dba::select('contact', array('id'), array('nurl' => $nurl, 'uid' => 0), array('limit' => 1));
if (DBM::is_result($r)) {
dba::update('contact', array('blocked' => true), array('id' => $r['id']));
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";
}
?>
Contact::block($contact_id);
echo t('The contact has been blocked from the node');
echo "\r\n";
exit(0);

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">
{{$page_desc}}<br />
<ul id="dfrn-request-networks">
<li><a href="http://friendica.com" title="{{$friendica}}">{{$friendica}}</a></li>
<li><a href="http://joindiaspora.com" title="{{$diaspora}}">{{$diaspora}}</a> {{$diasnote}}</li>
<li><a href="http://ostatus.org" title="{{$public_net}}" >{{$statusnet}}</a></li>
{{if $emailnet}}<li>{{$emailnet}}</li>{{/if}}
<li><a href="http://friendi.ca" title="{{$friendica}}">{{$friendica}}</a></li>
<li><a href="https://diasporafoundation.org" title="{{$diaspora}}">{{$diaspora}}</a> {{$diasnote}}</li>
<li><a href="https://gnu.io/social/" title="{{$statusnet}}" >{{$statusnet}}</a></li>
</ul>
</p>
<p>

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