mirror of
https://git.sekbaer.de/Friendica/friendica.git
synced 2025-06-12 01:54:26 +02:00
Add Install Mode
- merged `friendica/develop` to `nupplaPhil/install_mode` - content merged `mod/install.php` to `src/Class/`
This commit is contained in:
commit
1ab965c944
128 changed files with 34290 additions and 33303 deletions
|
@ -49,7 +49,7 @@ class ForumManager
|
|||
"SELECT `contact`.`id`, `contact`.`url`, `contact`.`name`, `contact`.`micro`, `contact`.`thumb`
|
||||
FROM `contact`
|
||||
WHERE `network`= 'dfrn' AND $select AND `uid` = ?
|
||||
AND NOT `blocked` AND NOT `hidden` AND NOT `pending` AND NOT `archive`
|
||||
AND NOT `blocked` AND NOT `pending` AND NOT `archive`
|
||||
AND `success_update` > `failure_update`
|
||||
$order ",
|
||||
$uid
|
||||
|
|
|
@ -28,23 +28,23 @@ class Nav
|
|||
if (!(x($a->page, 'nav'))) {
|
||||
$a->page['nav'] = '';
|
||||
}
|
||||
|
||||
|
||||
$a->page['htmlhead'] .= replace_macros(get_markup_template('nav_head.tpl'), []);
|
||||
|
||||
|
||||
/*
|
||||
* Placeholder div for popup panel
|
||||
*/
|
||||
|
||||
|
||||
$a->page['nav'] .= '<div id="panel" style="display: none;"></div>' ;
|
||||
|
||||
|
||||
$nav_info = self::getInfo($a);
|
||||
|
||||
|
||||
/*
|
||||
* Build the page
|
||||
*/
|
||||
|
||||
|
||||
$tpl = get_markup_template('nav.tpl');
|
||||
|
||||
|
||||
$a->page['nav'] .= replace_macros($tpl, [
|
||||
'$baseurl' => System::baseUrl(),
|
||||
'$sitelocation' => $nav_info['sitelocation'],
|
||||
|
@ -57,10 +57,10 @@ class Nav
|
|||
'$clear_notifs' => L10n::t('Clear notifications'),
|
||||
'$search_hint' => L10n::t('@name, !forum, #tags, content')
|
||||
]);
|
||||
|
||||
|
||||
Addon::callHooks('page_header', $a->page['nav']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepares a list of navigation links
|
||||
*
|
||||
|
@ -75,27 +75,27 @@ class Nav
|
|||
private static function getInfo(App $a)
|
||||
{
|
||||
$ssl_state = ((local_user()) ? true : false);
|
||||
|
||||
|
||||
/*
|
||||
* Our network is distributed, and as you visit friends some of the
|
||||
* sites look exactly the same - it isn't always easy to know where you are.
|
||||
* Display the current site location as a navigation aid.
|
||||
*/
|
||||
|
||||
|
||||
$myident = ((is_array($a->user) && isset($a->user['nickname'])) ? $a->user['nickname'] . '@' : '');
|
||||
|
||||
|
||||
$sitelocation = $myident . substr(System::baseUrl($ssl_state), strpos(System::baseUrl($ssl_state), '//') + 2);
|
||||
|
||||
|
||||
// nav links: array of array('href', 'text', 'extra css classes', 'title')
|
||||
$nav = [];
|
||||
|
||||
|
||||
// Display login or logout
|
||||
$nav['usermenu'] = [];
|
||||
$userinfo = null;
|
||||
|
||||
|
||||
if (local_user()) {
|
||||
$nav['logout'] = ['logout', L10n::t('Logout'), '', L10n::t('End this session')];
|
||||
|
||||
|
||||
// user menu
|
||||
$nav['usermenu'][] = ['profile/' . $a->user['nickname'], L10n::t('Status'), '', L10n::t('Your posts and conversations')];
|
||||
$nav['usermenu'][] = ['profile/' . $a->user['nickname'] . '?tab=profile', L10n::t('Profile'), '', L10n::t('Your profile page')];
|
||||
|
@ -103,7 +103,7 @@ class Nav
|
|||
$nav['usermenu'][] = ['videos/' . $a->user['nickname'], L10n::t('Videos'), '', L10n::t('Your videos')];
|
||||
$nav['usermenu'][] = ['events/', L10n::t('Events'), '', L10n::t('Your events')];
|
||||
$nav['usermenu'][] = ['notes/', L10n::t('Personal notes'), '', L10n::t('Your personal notes')];
|
||||
|
||||
|
||||
// user info
|
||||
$contact = dba::selectFirst('contact', ['micro'], ['uid' => $a->user['uid'], 'self' => true]);
|
||||
$userinfo = [
|
||||
|
@ -113,120 +113,117 @@ class Nav
|
|||
} else {
|
||||
$nav['login'] = ['login', L10n::t('Login'), ($a->module == 'login' ? 'selected' : ''), L10n::t('Sign in')];
|
||||
}
|
||||
|
||||
|
||||
// "Home" should also take you home from an authenticated remote profile connection
|
||||
$homelink = Profile::getMyURL();
|
||||
if (! $homelink) {
|
||||
$homelink = ((x($_SESSION, 'visitor_home')) ? $_SESSION['visitor_home'] : '');
|
||||
}
|
||||
|
||||
|
||||
if (($a->module != 'home') && (! (local_user()))) {
|
||||
$nav['home'] = [$homelink, L10n::t('Home'), '', L10n::t('Home Page')];
|
||||
}
|
||||
|
||||
|
||||
if (($a->config['register_policy'] == REGISTER_OPEN) && (! local_user()) && (! remote_user())) {
|
||||
$nav['register'] = ['register', L10n::t('Register'), '', L10n::t('Create an account')];
|
||||
}
|
||||
|
||||
|
||||
$help_url = 'help';
|
||||
|
||||
|
||||
if (!Config::get('system', 'hide_help')) {
|
||||
$nav['help'] = [$help_url, L10n::t('Help'), '', L10n::t('Help and documentation')];
|
||||
}
|
||||
|
||||
|
||||
if (count($a->apps) > 0) {
|
||||
$nav['apps'] = ['apps', L10n::t('Apps'), '', L10n::t('Addon applications, utilities, games')];
|
||||
}
|
||||
|
||||
|
||||
if (local_user() || !Config::get('system', 'local_search')) {
|
||||
$nav['search'] = ['search', L10n::t('Search'), '', L10n::t('Search site content')];
|
||||
|
||||
|
||||
$nav['searchoption'] = [
|
||||
L10n::t('Full Text'),
|
||||
L10n::t('Tags'),
|
||||
L10n::t('Contacts')
|
||||
];
|
||||
|
||||
|
||||
if (Config::get('system', 'poco_local_search')) {
|
||||
$nav['searchoption'][] = L10n::t('Forums');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$gdirpath = 'directory';
|
||||
|
||||
|
||||
if (strlen(Config::get('system', 'singleuser'))) {
|
||||
$gdir = Config::get('system', 'directory');
|
||||
if (strlen($gdir)) {
|
||||
$gdirpath = Profile::zrl($gdir, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (local_user() || Config::get('system', 'community_page_style') != CP_NO_COMMUNITY_PAGE) {
|
||||
|
||||
if ((local_user() || Config::get('system', 'community_page_style') != CP_NO_COMMUNITY_PAGE) &&
|
||||
!(Config::get('system', 'community_page_style') == CP_NO_INTERNAL_COMMUNITY)) {
|
||||
$nav['community'] = ['community', L10n::t('Community'), '', L10n::t('Conversations on this and other servers')];
|
||||
}
|
||||
|
||||
|
||||
if (local_user()) {
|
||||
$nav['events'] = ['events', L10n::t('Events'), '', L10n::t('Events and Calendar')];
|
||||
}
|
||||
|
||||
|
||||
$nav['directory'] = [$gdirpath, L10n::t('Directory'), '', L10n::t('People directory')];
|
||||
|
||||
|
||||
$nav['about'] = ['friendica', L10n::t('Information'), '', L10n::t('Information about this friendica instance')];
|
||||
|
||||
|
||||
// The following nav links are only show to logged in users
|
||||
if (local_user()) {
|
||||
$nav['network'] = ['network', L10n::t('Network'), '', L10n::t('Conversations from your friends')];
|
||||
$nav['net_reset'] = ['network/0?f=&order=comment&nets=all', L10n::t('Network Reset'), '', L10n::t('Load Network page with no filters')];
|
||||
|
||||
|
||||
$nav['home'] = ['profile/' . $a->user['nickname'], L10n::t('Home'), '', L10n::t('Your posts and conversations')];
|
||||
|
||||
if (in_array($_SESSION['page_flags'], [PAGE_NORMAL, PAGE_SOAPBOX, PAGE_FREELOVE, PAGE_PRVGROUP])) {
|
||||
// only show friend requests for normal pages. Other page types have automatic friendship.
|
||||
if (in_array($_SESSION['page_flags'], [PAGE_NORMAL, PAGE_SOAPBOX, PAGE_PRVGROUP])) {
|
||||
$nav['introductions'] = ['notifications/intros', L10n::t('Introductions'), '', L10n::t('Friend Requests')];
|
||||
}
|
||||
if (in_array($_SESSION['page_flags'], [PAGE_NORMAL, PAGE_SOAPBOX, PAGE_FREELOVE])) {
|
||||
$nav['notifications'] = ['notifications', L10n::t('Notifications'), '', L10n::t('Notifications')];
|
||||
$nav['notifications']['all'] = ['notifications/system', L10n::t('See all notifications'), '', ''];
|
||||
$nav['notifications']['mark'] = ['', L10n::t('Mark as seen'), '', L10n::t('Mark all system notifications seen')];
|
||||
}
|
||||
|
||||
// Don't show notifications for public communities
|
||||
if ($_SESSION['page_flags'] != PAGE_COMMUNITY) {
|
||||
$nav['introductions'] = ['notifications/intros', L10n::t('Introductions'), '', L10n::t('Friend Requests')];
|
||||
$nav['notifications'] = ['notifications', L10n::t('Notifications'), '', L10n::t('Notifications')];
|
||||
$nav['notifications']['all'] = ['notifications/system', L10n::t('See all notifications'), '', ''];
|
||||
$nav['notifications']['mark'] = ['', L10n::t('Mark as seen'), '', L10n::t('Mark all system notifications seen')];
|
||||
}
|
||||
|
||||
|
||||
$nav['messages'] = ['message', L10n::t('Messages'), '', L10n::t('Private mail')];
|
||||
$nav['messages']['inbox'] = ['message', L10n::t('Inbox'), '', L10n::t('Inbox')];
|
||||
$nav['messages']['outbox'] = ['message/sent', L10n::t('Outbox'), '', L10n::t('Outbox')];
|
||||
$nav['messages']['new'] = ['message/new', L10n::t('New Message'), '', L10n::t('New Message')];
|
||||
|
||||
|
||||
if (is_array($a->identities) && count($a->identities) > 1) {
|
||||
$nav['manage'] = ['manage', L10n::t('Manage'), '', L10n::t('Manage other pages')];
|
||||
}
|
||||
|
||||
|
||||
$nav['delegations'] = ['delegate', L10n::t('Delegations'), '', L10n::t('Delegate Page Management')];
|
||||
|
||||
|
||||
$nav['settings'] = ['settings', L10n::t('Settings'), '', L10n::t('Account settings')];
|
||||
|
||||
|
||||
if (Feature::isEnabled(local_user(), 'multi_profiles')) {
|
||||
$nav['profiles'] = ['profiles', L10n::t('Profiles'), '', L10n::t('Manage/Edit Profiles')];
|
||||
}
|
||||
|
||||
|
||||
$nav['contacts'] = ['contacts', L10n::t('Contacts'), '', L10n::t('Manage/edit friends and contacts')];
|
||||
}
|
||||
|
||||
|
||||
// Show the link to the admin configuration page if user is admin
|
||||
if (is_site_admin()) {
|
||||
$nav['admin'] = ['admin/', L10n::t('Admin'), '', L10n::t('Site setup and configuration')];
|
||||
}
|
||||
|
||||
|
||||
$nav['navigation'] = ['navigation/', L10n::t('Navigation'), '', L10n::t('Site map')];
|
||||
|
||||
|
||||
// Provide a banner/logo/whatever
|
||||
$banner = Config::get('system', 'banner');
|
||||
if (is_null($banner)) {
|
||||
$banner = '<a href="https://friendi.ca"><img id="logo-img" src="images/friendica-32.png" alt="logo" /></a><span id="logo-text"><a href="https://friendi.ca">Friendica</a></span>';
|
||||
}
|
||||
|
||||
|
||||
Addon::callHooks('nav_info', $nav);
|
||||
|
||||
|
||||
return [
|
||||
'sitelocation' => $sitelocation,
|
||||
'nav' => $nav,
|
||||
|
@ -234,7 +231,7 @@ class Nav
|
|||
'userinfo' => $userinfo,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a menu item in navbar as selected
|
||||
*/
|
||||
|
|
|
@ -343,159 +343,20 @@ class BBCode extends BaseObject
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a message into plaintext for connectors to other networks
|
||||
* @brief Converts a BBCode text into plaintext
|
||||
*
|
||||
* @param array $b The message array that is about to be posted
|
||||
* @param int $limit The maximum number of characters when posting to that network
|
||||
* @param bool $includedlinks Has an attached link to be included into the message?
|
||||
* @param int $htmlmode This triggers the behaviour of the bbcode conversion
|
||||
* @param string $target_network Name of the network where the post should go to.
|
||||
* @param bool $keep_urls Whether to keep URLs in the resulting plaintext
|
||||
*
|
||||
* @return string The converted message
|
||||
* @return string
|
||||
*/
|
||||
public static function toPlaintext($b, $limit = 0, $includedlinks = false, $htmlmode = 2, $target_network = "")
|
||||
public static function toPlaintext($text, $keep_urls = true)
|
||||
{
|
||||
// Remove the hash tags
|
||||
$URLSearchString = "^\[\]";
|
||||
$body = preg_replace("/([#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $b["body"]);
|
||||
|
||||
// Add an URL element if the text contains a raw link
|
||||
$body = preg_replace("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url]$2[/url]', $body);
|
||||
|
||||
// Remove the abstract
|
||||
$body = self::stripAbstract($body);
|
||||
|
||||
// At first look at data that is attached via "type-..." stuff
|
||||
// This will hopefully replaced with a dedicated bbcode later
|
||||
//$post = self::getAttachedData($b["body"]);
|
||||
$post = self::getAttachedData($body, $b);
|
||||
|
||||
if (($b["title"] != "") && ($post["text"] != "")) {
|
||||
$post["text"] = trim($b["title"]."\n\n".$post["text"]);
|
||||
} elseif ($b["title"] != "") {
|
||||
$post["text"] = trim($b["title"]);
|
||||
$naked_text = preg_replace('/\[(.+?)\]/','', $text);
|
||||
if (!$keep_urls) {
|
||||
$naked_text = preg_replace('#https?\://[^\s<]+[^\s\.\)]#i', '', $naked_text);
|
||||
}
|
||||
|
||||
$abstract = "";
|
||||
|
||||
// Fetch the abstract from the given target network
|
||||
if ($target_network != "") {
|
||||
$default_abstract = self::getAbstract($b["body"]);
|
||||
$abstract = self::getAbstract($b["body"], $target_network);
|
||||
|
||||
// If we post to a network with no limit we only fetch
|
||||
// an abstract exactly for this network
|
||||
if (($limit == 0) && ($abstract == $default_abstract)) {
|
||||
$abstract = "";
|
||||
}
|
||||
} else {// Try to guess the correct target network
|
||||
switch ($htmlmode) {
|
||||
case 8:
|
||||
$abstract = self::getAbstract($b["body"], NETWORK_TWITTER);
|
||||
break;
|
||||
case 7:
|
||||
$abstract = self::getAbstract($b["body"], NETWORK_STATUSNET);
|
||||
break;
|
||||
case 6:
|
||||
$abstract = self::getAbstract($b["body"], NETWORK_APPNET);
|
||||
break;
|
||||
default: // We don't know the exact target.
|
||||
// We fetch an abstract since there is a posting limit.
|
||||
if ($limit > 0) {
|
||||
$abstract = self::getAbstract($b["body"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($abstract != "") {
|
||||
$post["text"] = $abstract;
|
||||
|
||||
if ($post["type"] == "text") {
|
||||
$post["type"] = "link";
|
||||
$post["url"] = $b["plink"];
|
||||
}
|
||||
}
|
||||
|
||||
$html = self::convert($post["text"].$post["after"], false, $htmlmode);
|
||||
$msg = HTML::toPlaintext($html, 0, true);
|
||||
$msg = trim(html_entity_decode($msg, ENT_QUOTES, 'UTF-8'));
|
||||
|
||||
$link = "";
|
||||
if ($includedlinks) {
|
||||
if ($post["type"] == "link") {
|
||||
$link = $post["url"];
|
||||
} elseif ($post["type"] == "text") {
|
||||
$link = $post["url"];
|
||||
} elseif ($post["type"] == "video") {
|
||||
$link = $post["url"];
|
||||
} elseif ($post["type"] == "photo") {
|
||||
$link = $post["image"];
|
||||
}
|
||||
|
||||
if (($msg == "") && isset($post["title"])) {
|
||||
$msg = trim($post["title"]);
|
||||
}
|
||||
|
||||
if (($msg == "") && isset($post["description"])) {
|
||||
$msg = trim($post["description"]);
|
||||
}
|
||||
|
||||
// If the link is already contained in the post, then it neeedn't to be added again
|
||||
// But: if the link is beyond the limit, then it has to be added.
|
||||
if (($link != "") && strstr($msg, $link)) {
|
||||
$pos = strpos($msg, $link);
|
||||
|
||||
// Will the text be shortened in the link?
|
||||
// Or is the link the last item in the post?
|
||||
if (($limit > 0) && ($pos < $limit) && (($pos + 23 > $limit) || ($pos + strlen($link) == strlen($msg)))) {
|
||||
$msg = trim(str_replace($link, "", $msg));
|
||||
} elseif (($limit == 0) || ($pos < $limit)) {
|
||||
// The limit has to be increased since it will be shortened - but not now
|
||||
// Only do it with Twitter (htmlmode = 8)
|
||||
if (($limit > 0) && (strlen($link) > 23) && ($htmlmode == 8)) {
|
||||
$limit = $limit - 23 + strlen($link);
|
||||
}
|
||||
|
||||
$link = "";
|
||||
|
||||
if ($post["type"] == "text") {
|
||||
unset($post["url"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($limit > 0) {
|
||||
// Reduce multiple spaces
|
||||
// When posted to a network with limited space, we try to gain space where possible
|
||||
while (strpos($msg, " ") !== false) {
|
||||
$msg = str_replace(" ", " ", $msg);
|
||||
}
|
||||
|
||||
// Twitter is using its own limiter, so we always assume that shortened links will have this length
|
||||
if (iconv_strlen($link, "UTF-8") > 0) {
|
||||
$limit = $limit - 23;
|
||||
}
|
||||
|
||||
if (iconv_strlen($msg, "UTF-8") > $limit) {
|
||||
if (($post["type"] == "text") && isset($post["url"])) {
|
||||
$post["url"] = $b["plink"];
|
||||
} elseif (!isset($post["url"])) {
|
||||
$limit = $limit - 23;
|
||||
$post["url"] = $b["plink"];
|
||||
// Which purpose has this line? It is now uncommented, but left as a reminder
|
||||
//} elseif (strpos($b["body"], "[share") !== false) {
|
||||
// $post["url"] = $b["plink"];
|
||||
} elseif (PConfig::get($b["uid"], "system", "no_intelligent_shortening")) {
|
||||
$post["url"] = $b["plink"];
|
||||
}
|
||||
$msg = Plaintext::shorten($msg, $limit);
|
||||
}
|
||||
}
|
||||
|
||||
$post["text"] = trim($msg);
|
||||
|
||||
return($post);
|
||||
return $naked_text;
|
||||
}
|
||||
|
||||
public static function scaleExternalImages($srctext, $include_link = true, $scale_replace = false)
|
||||
|
@ -1947,7 +1808,7 @@ class BBCode extends BaseObject
|
|||
* @param string $addon The addon for which the abstract is meant for
|
||||
* @return string The abstract
|
||||
*/
|
||||
private static function getAbstract($text, $addon = "")
|
||||
public static function getAbstract($text, $addon = "")
|
||||
{
|
||||
$abstract = "";
|
||||
$abstracts = [];
|
||||
|
|
|
@ -55,19 +55,24 @@ class Widget
|
|||
}
|
||||
}
|
||||
|
||||
return replace_macros(get_markup_template('peoplefind.tpl'), array(
|
||||
'$findpeople' => L10n::t('Find People'),
|
||||
'$desc' => L10n::t('Enter name or interest'),
|
||||
'$label' => L10n::t('Connect/Follow'),
|
||||
'$hint' => L10n::t('Examples: Robert Morgenstein, Fishing'),
|
||||
'$findthem' => L10n::t('Find'),
|
||||
'$suggest' => L10n::t('Friend Suggestions'),
|
||||
'$similar' => L10n::t('Similar Interests'),
|
||||
'$random' => L10n::t('Random Profile'),
|
||||
'$inv' => L10n::t('Invite Friends'),
|
||||
'$directory' => L10n::t('View Global Directory'),
|
||||
'$global_dir' => $global_dir
|
||||
));
|
||||
$nv = [];
|
||||
$nv['findpeople'] = L10n::t('Find People');
|
||||
$nv['desc'] = L10n::t('Enter name or interest');
|
||||
$nv['label'] = L10n::t('Connect/Follow');
|
||||
$nv['hint'] = L10n::t('Examples: Robert Morgenstein, Fishing');
|
||||
$nv['findthem'] = L10n::t('Find');
|
||||
$nv['suggest'] = L10n::t('Friend Suggestions');
|
||||
$nv['similar'] = L10n::t('Similar Interests');
|
||||
$nv['random'] = L10n::t('Random Profile');
|
||||
$nv['inv'] = L10n::t('Invite Friends');
|
||||
$nv['directory'] = L10n::t('Global Directory');
|
||||
$nv['global_dir'] = $global_dir;
|
||||
$nv['local_directory'] = L10n::t('Local Directory');
|
||||
|
||||
$aside = [];
|
||||
$aside['$nv'] = $nv;
|
||||
|
||||
return replace_macros(get_markup_template('peoplefind.tpl'), $aside);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -246,7 +246,7 @@ class Addon
|
|||
} else {
|
||||
// remove orphan hooks
|
||||
$condition = ['hook' => $name, 'file' => $hook[0], 'function' => $hook[1]];
|
||||
dba::delete('hook', $condition);
|
||||
dba::delete('hook', $condition, ['cascade' => false]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ class Console extends \Asika\SimpleConsole\Console
|
|||
'extract' => __NAMESPACE__ . '\Console\Extract',
|
||||
'globalcommunityblock' => __NAMESPACE__ . '\Console\GlobalCommunityBlock',
|
||||
'globalcommunitysilence' => __NAMESPACE__ . '\Console\GlobalCommunitySilence',
|
||||
'archivecontact' => __NAMESPACE__ . '\Console\ArchiveContact',
|
||||
'autoinstall' => __NAMESPACE__ . '\Console\AutomaticInstallation',
|
||||
'maintenance' => __NAMESPACE__ . '\Console\Maintenance',
|
||||
'newpassword' => __NAMESPACE__ . '\Console\NewPassword',
|
||||
|
@ -42,6 +43,7 @@ Commands:
|
|||
extract Generate translation string file for the Friendica project (deprecated)
|
||||
globalcommunityblock Block remote profile from interacting with this node
|
||||
globalcommunitysilence Silence remote profile from global community page
|
||||
archivecontact Archive a contact when you know that it isn't existing anymore
|
||||
help Show help about a command, e.g (bin/console help config)
|
||||
autoinstall Starts automatic installation of friendica based on values from htconfig.php
|
||||
maintenance Set maintenance mode for this node
|
||||
|
|
79
src/Core/Console/ArchiveContact.php
Normal file
79
src/Core/Console/ArchiveContact.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Core\Console;
|
||||
|
||||
use Friendica\Core\L10n;
|
||||
use dba;
|
||||
|
||||
/**
|
||||
* @brief tool to archive a contact on the server
|
||||
*
|
||||
* With this tool you can archive a contact when you know that it isn't existing anymore.
|
||||
* Normally this does happen automatically after a few days.
|
||||
*
|
||||
* License: AGPLv3 or later, same as Friendica
|
||||
*
|
||||
*/
|
||||
class ArchiveContact extends \Asika\SimpleConsole\Console
|
||||
{
|
||||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
protected function getHelp()
|
||||
{
|
||||
$help = <<<HELP
|
||||
console archivecontact - archive a contact
|
||||
Usage
|
||||
bin/console archivecontact <profile_url> [-h|--help|-?] [-v]
|
||||
|
||||
Description
|
||||
Archive a contact when you know that it isn't existing anymore. Normally this does happen automatically after a few days.
|
||||
|
||||
Options
|
||||
-h|--help|-? Show help information
|
||||
-v Show more debug information.
|
||||
HELP;
|
||||
return $help;
|
||||
}
|
||||
|
||||
protected function doExecute()
|
||||
{
|
||||
$a = get_app();
|
||||
|
||||
if ($this->getOption('v')) {
|
||||
$this->out('Class: ' . __CLASS__);
|
||||
$this->out('Arguments: ' . var_export($this->args, true));
|
||||
$this->out('Options: ' . var_export($this->options, true));
|
||||
}
|
||||
|
||||
if (count($this->args) == 0) {
|
||||
$this->out($this->getHelp());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (count($this->args) > 1) {
|
||||
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
|
||||
}
|
||||
|
||||
require_once '.htconfig.php';
|
||||
$result = \dba::connect($db_host, $db_user, $db_pass, $db_data);
|
||||
unset($db_host, $db_user, $db_pass, $db_data);
|
||||
|
||||
if (!$result) {
|
||||
throw new \RuntimeException('Unable to connect to database');
|
||||
}
|
||||
|
||||
$nurl = normalise_link($this->getArgument(0));
|
||||
if (!dba::exists('contact', ['nurl' => $nurl, 'archive' => false])) {
|
||||
throw new \RuntimeException(L10n::t('Could not find any unarchived contact entry for this URL (%s)', $nurl));
|
||||
}
|
||||
if (dba::update('contact', ['archive' => true], ['nurl' => $nurl])) {
|
||||
$condition = ["`cid` IN (SELECT `id` FROM `contact` WHERE `archive`)"];
|
||||
dba::delete('queue', $condition);
|
||||
$this->out(L10n::t('The contact entries have been archived'));
|
||||
} else {
|
||||
throw new \RuntimeException('The contact archival failed.');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -423,7 +423,7 @@ class Contact extends BaseObject
|
|||
// Fetch the data from the gcontact table
|
||||
if (!DBM::is_result($r)) {
|
||||
$s = dba::p("SELECT 0 AS `id`, 0 AS `cid`, `id` AS `gid`, 0 AS `zid`, 0 AS `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, '' AS `xmpp`,
|
||||
`keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, `community` AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`
|
||||
`keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, 0 AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`
|
||||
FROM `gcontact` WHERE `nurl` = ?", normalise_link($url));
|
||||
$r = dba::inArray($s);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
namespace Friendica\Model;
|
||||
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Content\Text;
|
||||
use Friendica\Core\Addon;
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Core\L10n;
|
||||
|
@ -838,6 +839,101 @@ class Item extends BaseObject
|
|||
return $current_post;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Distributes public items to the receivers
|
||||
*
|
||||
* @param integer $itemid Item ID that should be added
|
||||
*/
|
||||
public static function distribute($itemid)
|
||||
{
|
||||
$condition = ["`id` IN (SELECT `parent` FROM `item` WHERE `id` = ?)", $itemid];
|
||||
$parent = dba::selectFirst('item', ['owner-id'], $condition);
|
||||
if (!DBM::is_result($parent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only distribute public items from native networks
|
||||
$condition = ['id' => $itemid, 'uid' => 0,
|
||||
'network' => [NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, ""],
|
||||
'visible' => true, 'deleted' => false, 'moderated' => false, 'private' => false];
|
||||
$item = dba::selectFirst('item', [], ['id' => $itemid]);
|
||||
if (!DBM::is_result($item)) {
|
||||
return;
|
||||
}
|
||||
|
||||
unset($item['id']);
|
||||
unset($item['parent']);
|
||||
unset($item['mention']);
|
||||
unset($item['wall']);
|
||||
unset($item['origin']);
|
||||
unset($item['starred']);
|
||||
unset($item['rendered-hash']);
|
||||
unset($item['rendered-html']);
|
||||
|
||||
$users = [];
|
||||
|
||||
$condition = ["`nurl` IN (SELECT `nurl` FROM `contact` WHERE `id` = ?) AND `uid` != 0 AND NOT `blocked` AND NOT `readonly` AND `rel` IN (?, ?)",
|
||||
$parent['owner-id'], CONTACT_IS_SHARING, CONTACT_IS_FRIEND];
|
||||
$contacts = dba::select('contact', ['uid'], $condition);
|
||||
while ($contact = dba::fetch($contacts)) {
|
||||
$users[$contact['uid']] = $contact['uid'];
|
||||
}
|
||||
|
||||
if ($item['uri'] != $item['parent-uri']) {
|
||||
$parents = dba::select('item', ['uid'], ["`uri` = ? AND `uid` != 0", $item['parent-uri']]);
|
||||
while ($parent = dba::fetch($parents)) {
|
||||
$users[$parent['uid']] = $parent['uid'];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($users as $uid) {
|
||||
self::storeForUser($itemid, $item, $uid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Store public items for the receivers
|
||||
*
|
||||
* @param integer $itemid Item ID that should be added
|
||||
* @param array $item The item entry that will be stored
|
||||
* @param integer $uid The user that will receive the item entry
|
||||
*/
|
||||
private static function storeForUser($itemid, $item, $uid)
|
||||
{
|
||||
$item['uid'] = $uid;
|
||||
$item['origin'] = 0;
|
||||
$item['wall'] = 0;
|
||||
if ($item['uri'] == $item['parent-uri']) {
|
||||
$item['contact-id'] = Contact::getIdForURL($item['owner-link'], $uid);
|
||||
} else {
|
||||
$item['contact-id'] = Contact::getIdForURL($item['author-link'], $uid);
|
||||
}
|
||||
|
||||
if (empty($item['contact-id'])) {
|
||||
$self = dba::selectFirst('contact', ['id'], ['self' => true, 'uid' => $uid]);
|
||||
if (!DBM::is_result($self)) {
|
||||
return;
|
||||
}
|
||||
$item['contact-id'] = $self['id'];
|
||||
}
|
||||
|
||||
if (in_array($item['type'], ["net-comment", "wall-comment"])) {
|
||||
$item['type'] = 'remote-comment';
|
||||
} elseif ($item['type'] == 'wall') {
|
||||
$item['type'] = 'remote';
|
||||
}
|
||||
|
||||
/// @todo Handling of "event-id"
|
||||
|
||||
$distributed = self::insert($item, false, false, true);
|
||||
|
||||
if (!$distributed) {
|
||||
logger("Distributed public item " . $itemid . " for user " . $uid . " wasn't stored", LOGGER_DEBUG);
|
||||
} else {
|
||||
logger("Distributed public item " . $itemid . " for user " . $uid . " with id " . $distributed, LOGGER_DEBUG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add a shadow entry for a given item id that is a thread starter
|
||||
*
|
||||
|
@ -849,8 +945,8 @@ class Item extends BaseObject
|
|||
*/
|
||||
public static function addShadow($itemid)
|
||||
{
|
||||
$fields = ['uid', 'wall', 'private', 'moderated', 'visible', 'contact-id', 'deleted', 'network', 'author-id', 'owner-id'];
|
||||
$condition = ["`id` = ? AND (`parent` = ? OR `parent` = 0)", $itemid, $itemid];
|
||||
$fields = ['uid', 'private', 'moderated', 'visible', 'deleted', 'network'];
|
||||
$condition = ['id' => $itemid, 'parent' => [0, $itemid]];
|
||||
$item = dba::selectFirst('item', $fields, $condition);
|
||||
|
||||
if (!DBM::is_result($item)) {
|
||||
|
@ -872,35 +968,22 @@ class Item extends BaseObject
|
|||
return;
|
||||
}
|
||||
|
||||
// Only do these checks if the post isn't a wall post
|
||||
if (!$item["wall"]) {
|
||||
// Check, if hide-friends is activated - then don't do a shadow entry
|
||||
if (dba::exists('profile', ['is-default' => true, 'uid' => $item['uid'], 'hide-friends' => true])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the contact is hidden or blocked
|
||||
if (!dba::exists('contact', ['hidden' => false, 'blocked' => false, 'id' => $item['contact-id']])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Only add a shadow, if the profile isn't hidden
|
||||
if (dba::exists('user', ['uid' => $item['uid'], 'hidewall' => true])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$item = dba::selectFirst('item', [], ['id' => $itemid]);
|
||||
|
||||
if (DBM::is_result($item) && ($item["allow_cid"] == '') && ($item["allow_gid"] == '') &&
|
||||
if (DBM::is_result($item) && ($item["allow_cid"] == '') && ($item["allow_gid"] == '') &&
|
||||
($item["deny_cid"] == '') && ($item["deny_gid"] == '')) {
|
||||
|
||||
if (!dba::exists('item', ['uri' => $item['uri'], 'uid' => 0])) {
|
||||
// Preparing public shadow (removing user specific data)
|
||||
unset($item['id']);
|
||||
$item['uid'] = 0;
|
||||
$item['origin'] = 0;
|
||||
$item['wall'] = 0;
|
||||
unset($item['id']);
|
||||
unset($item['parent']);
|
||||
unset($item['wall']);
|
||||
unset($item['mention']);
|
||||
unset($item['origin']);
|
||||
unset($item['starred']);
|
||||
unset($item['rendered-hash']);
|
||||
unset($item['rendered-html']);
|
||||
if ($item['uri'] == $item['parent-uri']) {
|
||||
$item['contact-id'] = Contact::getIdForURL($item['owner-link']);
|
||||
} else {
|
||||
|
@ -954,11 +1037,20 @@ class Item extends BaseObject
|
|||
return;
|
||||
}
|
||||
|
||||
// Save "origin" and "parent" state
|
||||
$origin = $item['origin'];
|
||||
$parent = $item['parent'];
|
||||
|
||||
// Preparing public shadow (removing user specific data)
|
||||
unset($item['id']);
|
||||
$item['uid'] = 0;
|
||||
$item['origin'] = 0;
|
||||
$item['wall'] = 0;
|
||||
unset($item['id']);
|
||||
unset($item['parent']);
|
||||
unset($item['wall']);
|
||||
unset($item['mention']);
|
||||
unset($item['origin']);
|
||||
unset($item['starred']);
|
||||
unset($item['rendered-hash']);
|
||||
unset($item['rendered-html']);
|
||||
$item['contact-id'] = Contact::getIdForURL($item['author-link']);
|
||||
|
||||
if (in_array($item['type'], ["net-comment", "wall-comment"])) {
|
||||
|
@ -970,6 +1062,14 @@ class Item extends BaseObject
|
|||
$public_shadow = self::insert($item, false, false, true);
|
||||
|
||||
logger("Stored public shadow for comment ".$item['uri']." under id ".$public_shadow, LOGGER_DEBUG);
|
||||
|
||||
// If this was a comment to a Diaspora post we don't get our comment back.
|
||||
// This means that we have to distribute the comment by ourselves.
|
||||
if ($origin) {
|
||||
if (dba::exists('item', ['id' => $parent, 'network' => NETWORK_DIASPORA])) {
|
||||
self::distribute($public_shadow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -977,35 +1077,35 @@ class Item extends BaseObject
|
|||
* if possible and not already present.
|
||||
* Expects "body" element to exist in $arr.
|
||||
*/
|
||||
private static function addLanguageInPostopts(&$arr)
|
||||
private static function addLanguageInPostopts(&$item)
|
||||
{
|
||||
if (x($arr, 'postopts')) {
|
||||
if (strstr($arr['postopts'], 'lang=')) {
|
||||
if (!empty($item['postopts'])) {
|
||||
if (strstr($item['postopts'], 'lang=')) {
|
||||
// do not override
|
||||
return;
|
||||
}
|
||||
$postopts = $arr['postopts'];
|
||||
$postopts = $item['postopts'];
|
||||
} else {
|
||||
$postopts = "";
|
||||
}
|
||||
|
||||
$naked_body = preg_replace('/\[(.+?)\]/','', $arr['body']);
|
||||
$l = new Text_LanguageDetect();
|
||||
$lng = $l->detect($naked_body, 3);
|
||||
$naked_body = Text\BBCode::toPlaintext($item['body'], false);
|
||||
|
||||
if (sizeof($lng) > 0) {
|
||||
if ($postopts != "") {
|
||||
$languages = (new Text_LanguageDetect())->detect($naked_body, 3);
|
||||
|
||||
if (sizeof($languages) > 0) {
|
||||
if ($postopts != '') {
|
||||
$postopts .= '&'; // arbitrary separator, to be reviewed
|
||||
}
|
||||
|
||||
$postopts .= 'lang=';
|
||||
$sep = "";
|
||||
|
||||
foreach ($lng as $language => $score) {
|
||||
foreach ($languages as $language => $score) {
|
||||
$postopts .= $sep . $language . ";" . $score;
|
||||
$sep = ':';
|
||||
}
|
||||
$arr['postopts'] = $postopts;
|
||||
$item['postopts'] = $postopts;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
176
src/Model/ItemContent.php
Normal file
176
src/Model/ItemContent.php
Normal file
|
@ -0,0 +1,176 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file src/Model/ItemContent.php
|
||||
*/
|
||||
|
||||
namespace Friendica\Model;
|
||||
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Content\Text;
|
||||
use Friendica\Core\PConfig;
|
||||
|
||||
require_once 'boot.php';
|
||||
require_once 'include/items.php';
|
||||
require_once 'include/text.php';
|
||||
|
||||
class ItemContent extends BaseObject
|
||||
{
|
||||
/**
|
||||
* @brief Convert a message into plaintext for connectors to other networks
|
||||
*
|
||||
* @param array $item The message array that is about to be posted
|
||||
* @param int $limit The maximum number of characters when posting to that network
|
||||
* @param bool $includedlinks Has an attached link to be included into the message?
|
||||
* @param int $htmlmode This controls the behavior of the BBCode conversion
|
||||
* @param string $target_network Name of the network where the post should go to.
|
||||
*
|
||||
* @see \Friendica\Content\Text\BBCode::getAttachedData
|
||||
*
|
||||
* @return array Same array structure than \Friendica\Content\Text\BBCode::getAttachedData
|
||||
*/
|
||||
public static function getPlaintextPost($item, $limit = 0, $includedlinks = false, $htmlmode = 2, $target_network = '')
|
||||
{
|
||||
// Remove hashtags
|
||||
$URLSearchString = '^\[\]';
|
||||
$body = preg_replace("/([#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $item['body']);
|
||||
|
||||
// Add an URL element if the text contains a raw link
|
||||
$body = preg_replace('/([^\]\=\'"]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism',
|
||||
'$1[url]$2[/url]', $body);
|
||||
|
||||
// Remove the abstract
|
||||
$body = Text\BBCode::stripAbstract($body);
|
||||
|
||||
// At first look at data that is attached via "type-..." stuff
|
||||
// This will hopefully replaced with a dedicated bbcode later
|
||||
//$post = self::getAttachedData($b['body']);
|
||||
$post = Text\BBCode::getAttachedData($body, $item);
|
||||
|
||||
if (($item['title'] != '') && ($post['text'] != '')) {
|
||||
$post['text'] = trim($item['title'] . "\n\n" . $post['text']);
|
||||
} elseif ($item['title'] != '') {
|
||||
$post['text'] = trim($item['title']);
|
||||
}
|
||||
|
||||
$abstract = '';
|
||||
|
||||
// Fetch the abstract from the given target network
|
||||
if ($target_network != '') {
|
||||
$default_abstract = Text\BBCode::getAbstract($item['body']);
|
||||
$abstract = Text\BBCode::getAbstract($item['body'], $target_network);
|
||||
|
||||
// If we post to a network with no limit we only fetch
|
||||
// an abstract exactly for this network
|
||||
if (($limit == 0) && ($abstract == $default_abstract)) {
|
||||
$abstract = '';
|
||||
}
|
||||
} else {// Try to guess the correct target network
|
||||
switch ($htmlmode) {
|
||||
case 8:
|
||||
$abstract = Text\BBCode::getAbstract($item['body'], NETWORK_TWITTER);
|
||||
break;
|
||||
case 7:
|
||||
$abstract = Text\BBCode::getAbstract($item['body'], NETWORK_STATUSNET);
|
||||
break;
|
||||
case 6:
|
||||
$abstract = Text\BBCode::getAbstract($item['body'], NETWORK_APPNET);
|
||||
break;
|
||||
default: // We don't know the exact target.
|
||||
// We fetch an abstract since there is a posting limit.
|
||||
if ($limit > 0) {
|
||||
$abstract = Text\BBCode::getAbstract($item['body']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($abstract != '') {
|
||||
$post['text'] = $abstract;
|
||||
|
||||
if ($post['type'] == 'text') {
|
||||
$post['type'] = 'link';
|
||||
$post['url'] = $item['plink'];
|
||||
}
|
||||
}
|
||||
|
||||
$html = Text\BBCode::convert($post['text'] . $post['after'], false, $htmlmode);
|
||||
$msg = Text\HTML::toPlaintext($html, 0, true);
|
||||
$msg = trim(html_entity_decode($msg, ENT_QUOTES, 'UTF-8'));
|
||||
|
||||
$link = '';
|
||||
if ($includedlinks) {
|
||||
if ($post['type'] == 'link') {
|
||||
$link = $post['url'];
|
||||
} elseif ($post['type'] == 'text') {
|
||||
$link = $post['url'];
|
||||
} elseif ($post['type'] == 'video') {
|
||||
$link = $post['url'];
|
||||
} elseif ($post['type'] == 'photo') {
|
||||
$link = $post['image'];
|
||||
}
|
||||
|
||||
if (($msg == '') && isset($post['title'])) {
|
||||
$msg = trim($post['title']);
|
||||
}
|
||||
|
||||
if (($msg == '') && isset($post['description'])) {
|
||||
$msg = trim($post['description']);
|
||||
}
|
||||
|
||||
// If the link is already contained in the post, then it neeedn't to be added again
|
||||
// But: if the link is beyond the limit, then it has to be added.
|
||||
if (($link != '') && strstr($msg, $link)) {
|
||||
$pos = strpos($msg, $link);
|
||||
|
||||
// Will the text be shortened in the link?
|
||||
// Or is the link the last item in the post?
|
||||
if (($limit > 0) && ($pos < $limit) && (($pos + 23 > $limit) || ($pos + strlen($link) == strlen($msg)))) {
|
||||
$msg = trim(str_replace($link, '', $msg));
|
||||
} elseif (($limit == 0) || ($pos < $limit)) {
|
||||
// The limit has to be increased since it will be shortened - but not now
|
||||
// Only do it with Twitter (htmlmode = 8)
|
||||
if (($limit > 0) && (strlen($link) > 23) && ($htmlmode == 8)) {
|
||||
$limit = $limit - 23 + strlen($link);
|
||||
}
|
||||
|
||||
$link = '';
|
||||
|
||||
if ($post['type'] == 'text') {
|
||||
unset($post['url']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($limit > 0) {
|
||||
// Reduce multiple spaces
|
||||
// When posted to a network with limited space, we try to gain space where possible
|
||||
while (strpos($msg, ' ') !== false) {
|
||||
$msg = str_replace(' ', ' ', $msg);
|
||||
}
|
||||
|
||||
// Twitter is using its own limiter, so we always assume that shortened links will have this length
|
||||
if (iconv_strlen($link, 'UTF-8') > 0) {
|
||||
$limit = $limit - 23;
|
||||
}
|
||||
|
||||
if (iconv_strlen($msg, 'UTF-8') > $limit) {
|
||||
if (($post['type'] == 'text') && isset($post['url'])) {
|
||||
$post['url'] = $item['plink'];
|
||||
} elseif (!isset($post['url'])) {
|
||||
$limit = $limit - 23;
|
||||
$post['url'] = $item['plink'];
|
||||
} elseif (strpos($item['body'], '[share') !== false) {
|
||||
$post['url'] = $item['plink'];
|
||||
} elseif (PConfig::get($item['uid'], 'system', 'no_intelligent_shortening')) {
|
||||
$post['url'] = $item['plink'];
|
||||
}
|
||||
$msg = Text\Plaintext::shorten($msg, $limit);
|
||||
}
|
||||
}
|
||||
|
||||
$post['text'] = trim($msg);
|
||||
|
||||
return $post;
|
||||
}
|
||||
}
|
|
@ -92,14 +92,14 @@ class Profile
|
|||
{
|
||||
$user = dba::selectFirst('user', ['uid'], ['nickname' => $nickname]);
|
||||
|
||||
if (!$user && !count($user) && !count($profiledata)) {
|
||||
if (!DBM::is_result($user) && empty($profiledata)) {
|
||||
logger('profile error: ' . $a->query_string, LOGGER_DEBUG);
|
||||
notice(L10n::t('Requested account is not available.') . EOL);
|
||||
$a->error = 404;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!x($a->page, 'aside')) {
|
||||
if (empty($a->page['aside'])) {
|
||||
$a->page['aside'] = '';
|
||||
}
|
||||
|
||||
|
@ -157,10 +157,6 @@ class Profile
|
|||
require_once $theme_info_file;
|
||||
}
|
||||
|
||||
if (!x($a->page, 'aside')) {
|
||||
$a->page['aside'] = '';
|
||||
}
|
||||
|
||||
if (local_user() && local_user() == $a->profile['uid'] && $profiledata) {
|
||||
$a->page['aside'] .= replace_macros(
|
||||
get_markup_template('profile_edlink.tpl'),
|
||||
|
@ -644,26 +640,26 @@ class Profile
|
|||
$classtoday = '';
|
||||
|
||||
$s = dba::p(
|
||||
"SELECT *
|
||||
"SELECT `event`.*
|
||||
FROM `event`
|
||||
WHERE `event`.`uid` = ?
|
||||
AND `event`.`type` != 'birthday'
|
||||
AND `event`.`start` < ?
|
||||
AND `event`.`start` >= ?
|
||||
AND NOT EXISTS (
|
||||
SELECT `id`
|
||||
FROM `item`
|
||||
WHERE `item`.`uid` = `event`.`uid`
|
||||
INNER JOIN `item`
|
||||
ON `item`.`uid` = `event`.`uid`
|
||||
AND `item`.`parent-uri` = `event`.`uri`
|
||||
AND `item`.`verb` = ?
|
||||
AND `item`.`visible`
|
||||
AND NOT `item`.`deleted`
|
||||
)
|
||||
WHERE `event`.`uid` = ?
|
||||
AND `event`.`type` != 'birthday'
|
||||
AND `event`.`start` < ?
|
||||
AND `event`.`start` >= ?
|
||||
AND `item`.`author-id` = ?
|
||||
AND (`item`.`verb` = ? OR `item`.`verb` = ?)
|
||||
AND `item`.`visible`
|
||||
AND NOT `item`.`deleted`
|
||||
ORDER BY `event`.`start` ASC",
|
||||
local_user(),
|
||||
DateTimeFormat::utc('now + 7 days'),
|
||||
DateTimeFormat::utc('now - 1 days'),
|
||||
ACTIVITY_ATTENDNO
|
||||
public_contact(),
|
||||
ACTIVITY_ATTEND,
|
||||
ACTIVITY_ATTENDMAYBE
|
||||
);
|
||||
|
||||
$r = [];
|
||||
|
@ -954,7 +950,7 @@ class Profile
|
|||
];
|
||||
}
|
||||
|
||||
if ((!$is_owner) && ((count($a->profile)) || (!$a->profile['hide-friends']))) {
|
||||
if (!$is_owner && empty($a->profile['hide-friends'])) {
|
||||
$tabs[] = [
|
||||
'label' => L10n::t('Contacts'),
|
||||
'url' => System::baseUrl() . '/viewcontacts/' . $nickname,
|
||||
|
|
|
@ -78,7 +78,7 @@ class Post extends BaseObject
|
|||
}
|
||||
|
||||
// Prepare the children
|
||||
if (count($data['children'])) {
|
||||
if (!empty($data['children'])) {
|
||||
foreach ($data['children'] as $item) {
|
||||
// Only add will be displayed
|
||||
if ($item['network'] === NETWORK_MAIL && local_user() != $item['uid']) {
|
||||
|
|
|
@ -1197,6 +1197,7 @@ class DFRN
|
|||
$ret = Network::curl($url);
|
||||
|
||||
if ($ret['errno'] == CURLE_OPERATION_TIMEDOUT) {
|
||||
Contact::markForArchival($contact);
|
||||
return -2; // timed out
|
||||
}
|
||||
|
||||
|
@ -1204,24 +1205,28 @@ class DFRN
|
|||
|
||||
$curl_stat = $a->get_curl_code();
|
||||
if (empty($curl_stat)) {
|
||||
Contact::markForArchival($contact);
|
||||
return -3; // timed out
|
||||
}
|
||||
|
||||
logger('dfrn_deliver: ' . $xml, LOGGER_DATA);
|
||||
|
||||
if (empty($xml)) {
|
||||
Contact::markForArchival($contact);
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (strpos($xml, '<?xml') === false) {
|
||||
logger('dfrn_deliver: no valid XML returned');
|
||||
logger('dfrn_deliver: returned XML: ' . $xml, LOGGER_DATA);
|
||||
Contact::markForArchival($contact);
|
||||
return 3;
|
||||
}
|
||||
|
||||
$res = XML::parseString($xml);
|
||||
|
||||
if ((intval($res->status) != 0) || (! strlen($res->challenge)) || (! strlen($res->dfrn_id))) {
|
||||
if ((intval($res->status) != 0) || !strlen($res->challenge) || !strlen($res->dfrn_id)) {
|
||||
Contact::markForArchival($contact);
|
||||
return ($res->status ? $res->status : 3);
|
||||
}
|
||||
|
||||
|
@ -1274,6 +1279,7 @@ class DFRN
|
|||
if ($final_dfrn_id != $orig_id) {
|
||||
logger('dfrn_deliver: wrong dfrn_id.');
|
||||
// did not decode properly - cannot trust this site
|
||||
Contact::markForArchival($contact);
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
@ -1309,6 +1315,7 @@ class DFRN
|
|||
break;
|
||||
default:
|
||||
logger("rino: invalid requested version '$rino_remote_version'");
|
||||
Contact::markForArchival($contact);
|
||||
return -8;
|
||||
}
|
||||
|
||||
|
@ -1346,22 +1353,26 @@ class DFRN
|
|||
|
||||
$curl_stat = $a->get_curl_code();
|
||||
if (empty($curl_stat) || empty($xml)) {
|
||||
Contact::markForArchival($contact);
|
||||
return -9; // timed out
|
||||
}
|
||||
|
||||
if (($curl_stat == 503) && stristr($a->get_curl_headers(), 'retry-after')) {
|
||||
Contact::markForArchival($contact);
|
||||
return -10;
|
||||
}
|
||||
|
||||
if (strpos($xml, '<?xml') === false) {
|
||||
logger('dfrn_deliver: phase 2: no valid XML returned');
|
||||
logger('dfrn_deliver: phase 2: returned XML: ' . $xml, LOGGER_DATA);
|
||||
Contact::markForArchival($contact);
|
||||
return 3;
|
||||
}
|
||||
|
||||
$res = XML::parseString($xml);
|
||||
|
||||
if (!isset($res->status)) {
|
||||
Contact::markForArchival($contact);
|
||||
return -11;
|
||||
}
|
||||
|
||||
|
@ -1374,7 +1385,7 @@ class DFRN
|
|||
logger('Delivery returned status '.$res->status.' - '.$res->message, LOGGER_DEBUG);
|
||||
}
|
||||
|
||||
if ($res->status == 200) {
|
||||
if (($res->status >= 200) && ($res->status <= 299)) {
|
||||
Contact::unmarkForArchival($contact);
|
||||
}
|
||||
|
||||
|
@ -1394,28 +1405,41 @@ class DFRN
|
|||
{
|
||||
$a = get_app();
|
||||
|
||||
if (empty($contact['addr'])) {
|
||||
logger('Empty contact handle for ' . $contact['id'] . ' - ' . $contact['url'] . ' - trying to update it.');
|
||||
if (Contact::updateFromProbe($contact['id'])) {
|
||||
$new_contact = dba::selectFirst('contact', ['addr'], ['id' => $contact['id']]);
|
||||
$contact['addr'] = $new_contact['addr'];
|
||||
}
|
||||
|
||||
if (!$public_batch) {
|
||||
if (empty($contact['addr'])) {
|
||||
logger('Unable to find contact handle for ' . $contact['id'] . ' - ' . $contact['url']);
|
||||
return -21;
|
||||
}
|
||||
}
|
||||
logger('Empty contact handle for ' . $contact['id'] . ' - ' . $contact['url'] . ' - trying to update it.');
|
||||
if (Contact::updateFromProbe($contact['id'])) {
|
||||
$new_contact = dba::selectFirst('contact', ['addr'], ['id' => $contact['id']]);
|
||||
$contact['addr'] = $new_contact['addr'];
|
||||
}
|
||||
|
||||
$fcontact = Diaspora::personByHandle($contact['addr']);
|
||||
if (empty($fcontact)) {
|
||||
logger('Unable to find contact details for ' . $contact['id'] . ' - ' . $contact['addr']);
|
||||
return -22;
|
||||
if (empty($contact['addr'])) {
|
||||
logger('Unable to find contact handle for ' . $contact['id'] . ' - ' . $contact['url']);
|
||||
Contact::markForArchival($contact);
|
||||
return -21;
|
||||
}
|
||||
}
|
||||
|
||||
$fcontact = Diaspora::personByHandle($contact['addr']);
|
||||
if (empty($fcontact)) {
|
||||
logger('Unable to find contact details for ' . $contact['id'] . ' - ' . $contact['addr']);
|
||||
Contact::markForArchival($contact);
|
||||
return -22;
|
||||
}
|
||||
}
|
||||
|
||||
$envelope = Diaspora::buildMessage($atom, $owner, $contact, $owner['uprvkey'], $fcontact['pubkey'], $public_batch);
|
||||
|
||||
$dest_url = ($public_batch ? $fcontact["batch"] : $contact["notify"]);
|
||||
// Create the endpoint for public posts. This is some WIP and should later be added to the probing
|
||||
if ($public_batch && empty($contact["batch"])) {
|
||||
$parts = parse_url($contact["notify"]);
|
||||
$path_parts = explode('/', $parts['path']);
|
||||
array_pop($path_parts);
|
||||
$parts['path'] = implode('/', $path_parts);
|
||||
$contact["batch"] = Network::unparseURL($parts);
|
||||
}
|
||||
|
||||
$dest_url = ($public_batch ? $contact["batch"] : $contact["notify"]);
|
||||
|
||||
$content_type = ($public_batch ? "application/magic-envelope+xml" : "application/json");
|
||||
|
||||
|
@ -1424,22 +1448,26 @@ class DFRN
|
|||
$curl_stat = $a->get_curl_code();
|
||||
if (empty($curl_stat) || empty($xml)) {
|
||||
logger('Empty answer from ' . $contact['id'] . ' - ' . $dest_url);
|
||||
Contact::markForArchival($contact);
|
||||
return -9; // timed out
|
||||
}
|
||||
|
||||
if (($curl_stat == 503) && (stristr($a->get_curl_headers(), 'retry-after'))) {
|
||||
Contact::markForArchival($contact);
|
||||
return -10;
|
||||
}
|
||||
|
||||
if (strpos($xml, '<?xml') === false) {
|
||||
logger('No valid XML returned from ' . $contact['id'] . ' - ' . $dest_url);
|
||||
logger('Returned XML: ' . $xml, LOGGER_DATA);
|
||||
Contact::markForArchival($contact);
|
||||
return 3;
|
||||
}
|
||||
|
||||
$res = XML::parseString($xml);
|
||||
|
||||
if (empty($res->status)) {
|
||||
Contact::markForArchival($contact);
|
||||
return -23;
|
||||
}
|
||||
|
||||
|
@ -1447,7 +1475,7 @@ class DFRN
|
|||
logger('Transmit to ' . $dest_url . ' returned status '.$res->status.' - '.$res->message, LOGGER_DEBUG);
|
||||
}
|
||||
|
||||
if ($res->status == 200) {
|
||||
if (($res->status >= 200) && ($res->status <= 299)) {
|
||||
Contact::unmarkForArchival($contact);
|
||||
}
|
||||
|
||||
|
@ -1467,33 +1495,33 @@ class DFRN
|
|||
// Check for duplicates
|
||||
$r = q(
|
||||
"SELECT `id` FROM `event` WHERE `uid` = %d AND `cid` = %d AND `start` = '%s' AND `type` = '%s' LIMIT 1",
|
||||
intval($contact["uid"]),
|
||||
intval($contact["id"]),
|
||||
intval($contact['uid']),
|
||||
intval($contact['id']),
|
||||
dbesc(DateTimeFormat::utc($birthday)),
|
||||
dbesc("birthday")
|
||||
dbesc('birthday')
|
||||
);
|
||||
|
||||
if (DBM::is_result($r)) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger("updating birthday: ".$birthday." for contact ".$contact["id"]);
|
||||
logger('updating birthday: ' . $birthday . ' for contact ' . $contact['id']);
|
||||
|
||||
$bdtext = L10n::t("%s\'s birthday", $contact["name"]);
|
||||
$bdtext2 = L10n::t("Happy Birthday %s", " [url=".$contact["url"]."]".$contact["name"]."[/url]");
|
||||
$bdtext = L10n::t('%s\'s birthday', $contact['name']);
|
||||
$bdtext2 = L10n::t('Happy Birthday %s', ' [url=' . $contact['url'] . ']' . $contact['name'] . '[/url]');
|
||||
|
||||
$r = q(
|
||||
"INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`summary`,`desc`,`type`)
|
||||
VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s') ",
|
||||
intval($contact["uid"]),
|
||||
intval($contact["id"]),
|
||||
intval($contact['uid']),
|
||||
intval($contact['id']),
|
||||
dbesc(DateTimeFormat::utcNow()),
|
||||
dbesc(DateTimeFormat::utcNow()),
|
||||
dbesc(DateTimeFormat::utc($birthday)),
|
||||
dbesc(DateTimeFormat::utc($birthday . " + 1 day ")),
|
||||
dbesc(DateTimeFormat::utc($birthday . ' + 1 day ')),
|
||||
dbesc($bdtext),
|
||||
dbesc($bdtext2),
|
||||
dbesc("birthday")
|
||||
dbesc('birthday')
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -2747,6 +2775,10 @@ class DFRN
|
|||
if ($posted_id) {
|
||||
logger("Reply from contact ".$item["contact-id"]." was stored with id ".$posted_id, LOGGER_DEBUG);
|
||||
|
||||
if ($item['uid'] == 0) {
|
||||
Item::distribute($posted_id);
|
||||
}
|
||||
|
||||
$item["id"] = $posted_id;
|
||||
|
||||
$r = q(
|
||||
|
@ -2771,7 +2803,7 @@ class DFRN
|
|||
logger('ignoring read-only contact '.$importer["id"]);
|
||||
return;
|
||||
}
|
||||
if ($importer["uid"] == 0) {
|
||||
if (($importer["uid"] == 0) && ($importer["importer_uid"] != 0)) {
|
||||
logger("Contact ".$importer["id"]." isn't known to user ".$importer["importer_uid"].". The post will be ignored.", LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
@ -2801,6 +2833,10 @@ class DFRN
|
|||
|
||||
logger("Item was stored with id ".$posted_id, LOGGER_DEBUG);
|
||||
|
||||
if ($item['uid'] == 0) {
|
||||
Item::distribute($posted_id);
|
||||
}
|
||||
|
||||
if (stristr($item["verb"], ACTIVITY_POKE)) {
|
||||
self::doPoke($item, $importer, $posted_id);
|
||||
}
|
||||
|
@ -2923,6 +2959,9 @@ class DFRN
|
|||
|
||||
logger("Import DFRN message for user " . $importer["importer_uid"] . " from contact " . $importer["id"], LOGGER_DEBUG);
|
||||
|
||||
// is it a public forum? Private forums aren't exposed with this method
|
||||
$forum = intval($xpath->evaluate("/atom:feed/dfrn:community/text()")->item(0)->nodeValue);
|
||||
|
||||
// The account type is new since 3.5.1
|
||||
if ($xpath->query("/atom:feed/dfrn:account_type")->length > 0) {
|
||||
$accounttype = intval($xpath->evaluate("/atom:feed/dfrn:account_type/text()")->item(0)->nodeValue);
|
||||
|
@ -2930,17 +2969,17 @@ class DFRN
|
|||
if ($accounttype != $importer["contact-type"]) {
|
||||
dba::update('contact', ['contact-type' => $accounttype], ['id' => $importer["id"]]);
|
||||
}
|
||||
}
|
||||
|
||||
// is it a public forum? Private forums aren't supported with this method
|
||||
// This is deprecated since 3.5.1
|
||||
$forum = intval($xpath->evaluate("/atom:feed/dfrn:community/text()")->item(0)->nodeValue);
|
||||
|
||||
if ($forum != $importer["forum"]) {
|
||||
// A forum contact can either have set "forum" or "prv" - but not both
|
||||
if (($accounttype == ACCOUNT_TYPE_COMMUNITY) && (($forum != $importer["forum"]) || ($forum == $importer["prv"]))) {
|
||||
$condition = ['(`forum` != ? OR `prv` != ?) AND `id` = ?', $forum, !$forum, $importer["id"]];
|
||||
dba::update('contact', ['forum' => $forum, 'prv' => !$forum], $condition);
|
||||
}
|
||||
} elseif ($forum != $importer["forum"]) { // Deprecated since 3.5.1
|
||||
$condition = ['`forum` != ? AND `id` = ?', $forum, $importer["id"]];
|
||||
dba::update('contact', ['forum' => $forum], $condition);
|
||||
}
|
||||
|
||||
|
||||
// We are processing relocations even if we are ignoring a contact
|
||||
$relocations = $xpath->query("/atom:feed/dfrn:relocate");
|
||||
foreach ($relocations as $relocation) {
|
||||
|
|
|
@ -590,59 +590,15 @@ class Diaspora
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!($postdata = self::validPosting($msg))) {
|
||||
if (!($fields = self::validPosting($msg))) {
|
||||
logger("Invalid posting");
|
||||
return false;
|
||||
}
|
||||
|
||||
$fields = $postdata['fields'];
|
||||
$importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE];
|
||||
$success = self::dispatch($importer, $msg, $fields);
|
||||
|
||||
// Is it a an action (comment, like, ...) for our own post?
|
||||
if (isset($fields->parent_guid) && !$postdata["relayed"]) {
|
||||
$guid = notags(unxmlify($fields->parent_guid));
|
||||
$importer = self::importerForGuid($guid);
|
||||
if (is_array($importer)) {
|
||||
logger("delivering to origin: ".$importer["name"]);
|
||||
$message_id = self::dispatch($importer, $msg, $fields);
|
||||
return $message_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Process item retractions. This has to be done separated from the other stuff,
|
||||
// since retractions for comments could come even from non followers.
|
||||
if (!empty($fields) && in_array($fields->getName(), ['retraction'])) {
|
||||
$target = notags(unxmlify($fields->target_type));
|
||||
if (in_array($target, ["Comment", "Like", "Post", "Reshare", "StatusMessage"])) {
|
||||
logger('processing retraction for '.$target, LOGGER_DEBUG);
|
||||
$importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE];
|
||||
$message_id = self::dispatch($importer, $msg, $fields);
|
||||
return $message_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Now distribute it to the followers
|
||||
$r = q(
|
||||
"SELECT `user`.* FROM `user` WHERE `user`.`uid` IN
|
||||
(SELECT `contact`.`uid` FROM `contact` WHERE `contact`.`network` = '%s' AND `contact`.`addr` = '%s')
|
||||
AND NOT `account_expired` AND NOT `account_removed`",
|
||||
dbesc(NETWORK_DIASPORA),
|
||||
dbesc($msg["author"])
|
||||
);
|
||||
|
||||
if (DBM::is_result($r)) {
|
||||
foreach ($r as $rr) {
|
||||
logger("delivering to: ".$rr["username"]);
|
||||
self::dispatch($rr, $msg, $fields);
|
||||
}
|
||||
} elseif (!Config::get('system', 'relay_subscribe', false)) {
|
||||
logger("Unwanted message from ".$msg["author"]." send by ".$_SERVER["REMOTE_ADDR"]." with ".$_SERVER["HTTP_USER_AGENT"].": ".print_r($msg, true), LOGGER_DEBUG);
|
||||
} else {
|
||||
// Use a dummy importer to import the data for the public copy
|
||||
$importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE];
|
||||
$message_id = self::dispatch($importer, $msg, $fields);
|
||||
}
|
||||
|
||||
return $message_id;
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -662,11 +618,13 @@ class Diaspora
|
|||
|
||||
// This is only needed for private postings since this is already done for public ones before
|
||||
if (is_null($fields)) {
|
||||
if (!($postdata = self::validPosting($msg))) {
|
||||
$private = true;
|
||||
if (!($fields = self::validPosting($msg))) {
|
||||
logger("Invalid posting");
|
||||
return false;
|
||||
}
|
||||
$fields = $postdata['fields'];
|
||||
} else {
|
||||
$private = false;
|
||||
}
|
||||
|
||||
$type = $fields->getName();
|
||||
|
@ -675,27 +633,47 @@ class Diaspora
|
|||
|
||||
switch ($type) {
|
||||
case "account_migration":
|
||||
if (!$private) {
|
||||
logger('Message with type ' . $type . ' is not private, quitting.');
|
||||
return false;
|
||||
}
|
||||
return self::receiveAccountMigration($importer, $fields);
|
||||
|
||||
case "account_deletion":
|
||||
return self::receiveAccountDeletion($importer, $fields);
|
||||
return self::receiveAccountDeletion($fields);
|
||||
|
||||
case "comment":
|
||||
return self::receiveComment($importer, $sender, $fields, $msg["message"]);
|
||||
|
||||
case "contact":
|
||||
if (!$private) {
|
||||
logger('Message with type ' . $type . ' is not private, quitting.');
|
||||
return false;
|
||||
}
|
||||
return self::receiveContactRequest($importer, $fields);
|
||||
|
||||
case "conversation":
|
||||
if (!$private) {
|
||||
logger('Message with type ' . $type . ' is not private, quitting.');
|
||||
return false;
|
||||
}
|
||||
return self::receiveConversation($importer, $msg, $fields);
|
||||
|
||||
case "like":
|
||||
return self::receiveLike($importer, $sender, $fields);
|
||||
|
||||
case "message":
|
||||
if (!$private) {
|
||||
logger('Message with type ' . $type . ' is not private, quitting.');
|
||||
return false;
|
||||
}
|
||||
return self::receiveMessage($importer, $fields);
|
||||
|
||||
case "participation":
|
||||
if (!$private) {
|
||||
logger('Message with type ' . $type . ' is not private, quitting.');
|
||||
return false;
|
||||
}
|
||||
return self::receiveParticipation($importer, $fields);
|
||||
|
||||
case "photo": // Not implemented
|
||||
|
@ -705,6 +683,10 @@ class Diaspora
|
|||
return self::receivePollParticipation($importer, $fields);
|
||||
|
||||
case "profile":
|
||||
if (!$private) {
|
||||
logger('Message with type ' . $type . ' is not private, quitting.');
|
||||
return false;
|
||||
}
|
||||
return self::receiveProfile($importer, $fields);
|
||||
|
||||
case "reshare":
|
||||
|
@ -840,7 +822,7 @@ class Diaspora
|
|||
|
||||
// Only some message types have signatures. So we quit here for the other types.
|
||||
if (!in_array($type, ["comment", "like"])) {
|
||||
return ["fields" => $fields, "relayed" => false];
|
||||
return $fields;
|
||||
}
|
||||
// No author_signature? This is a must, so we quit.
|
||||
if (!isset($author_signature)) {
|
||||
|
@ -849,25 +831,29 @@ class Diaspora
|
|||
}
|
||||
|
||||
if (isset($parent_author_signature)) {
|
||||
$relayed = true;
|
||||
|
||||
$key = self::key($msg["author"]);
|
||||
if (empty($key)) {
|
||||
logger("No key found for parent author ".$msg["author"], LOGGER_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Crypto::rsaVerify($signed_data, $parent_author_signature, $key, "sha256")) {
|
||||
logger("No valid parent author signature for parent author ".$msg["author"]. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$parent_author_signature, LOGGER_DEBUG);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$relayed = false;
|
||||
}
|
||||
|
||||
$key = self::key($fields->author);
|
||||
if (empty($key)) {
|
||||
logger("No key found for author ".$fields->author, LOGGER_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Crypto::rsaVerify($signed_data, $author_signature, $key, "sha256")) {
|
||||
logger("No valid author signature for author ".$fields->author. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$author_signature, LOGGER_DEBUG);
|
||||
return false;
|
||||
} else {
|
||||
return ["fields" => $fields, "relayed" => $relayed];
|
||||
return $fields;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1650,25 +1636,23 @@ class Diaspora
|
|||
/**
|
||||
* @brief Processes an account deletion
|
||||
*
|
||||
* @param array $importer Array of the importer user
|
||||
* @param object $data The message object
|
||||
*
|
||||
* @return bool Success
|
||||
*/
|
||||
private static function receiveAccountDeletion($importer, $data)
|
||||
private static function receiveAccountDeletion($data)
|
||||
{
|
||||
/// @todo Account deletion should remove the contact from the global contacts as well
|
||||
|
||||
$author = notags(unxmlify($data->author));
|
||||
|
||||
$contact = self::contactByHandle($importer["uid"], $author);
|
||||
if (!$contact) {
|
||||
logger("cannot find contact for author: ".$author);
|
||||
return false;
|
||||
$contacts = dba::select('contact', ['id'], ['addr' => $author]);
|
||||
while ($contact = dba::fetch($contacts)) {
|
||||
Contact::remove($contact["id"]);
|
||||
}
|
||||
|
||||
// We now remove the contact
|
||||
Contact::remove($contact["id"]);
|
||||
dba::delete('gcontact', ['addr' => $author]);
|
||||
|
||||
logger('Removed contacts for ' . $author);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1836,6 +1820,9 @@ class Diaspora
|
|||
|
||||
if ($message_id) {
|
||||
logger("Stored comment ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
|
||||
if ($datarray['uid'] == 0) {
|
||||
Item::distribute($message_id);
|
||||
}
|
||||
}
|
||||
|
||||
// If we are the origin of the parent we store the original data and notify our followers
|
||||
|
@ -2157,6 +2144,9 @@ class Diaspora
|
|||
|
||||
if ($message_id) {
|
||||
logger("Stored like ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
|
||||
if ($datarray['uid'] == 0) {
|
||||
Item::distribute($message_id);
|
||||
}
|
||||
}
|
||||
|
||||
// like on comments have the comment as parent. So we need to fetch the toplevel parent
|
||||
|
@ -2739,10 +2729,15 @@ class Diaspora
|
|||
*/
|
||||
public static function originalItem($guid, $orig_author)
|
||||
{
|
||||
if (empty($guid)) {
|
||||
logger('Empty guid. Quitting.');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do we already have this item?
|
||||
$fields = ['body', 'tag', 'app', 'created', 'object-type', 'uri', 'guid',
|
||||
'author-name', 'author-link', 'author-avatar'];
|
||||
$condition = ['guid' => $guid, 'visible' => true, 'deleted' => false];
|
||||
$condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => false];
|
||||
$item = dba::selectfirst('item', $fields, $condition);
|
||||
|
||||
if (DBM::is_result($item)) {
|
||||
|
@ -2752,7 +2747,7 @@ class Diaspora
|
|||
// Then refetch the content, if it is a reshare from a reshare.
|
||||
// If it is a reshared post from another network then reformat to avoid display problems with two share elements
|
||||
if (self::isReshare($item["body"], true)) {
|
||||
$r = [];
|
||||
$item = [];
|
||||
} elseif (self::isReshare($item["body"], false) || strstr($item["body"], "[share")) {
|
||||
$item["body"] = Markdown::toBBCode(BBCode::toMarkdown($item["body"]));
|
||||
|
||||
|
@ -2767,21 +2762,26 @@ class Diaspora
|
|||
}
|
||||
}
|
||||
|
||||
if (!DBM::is_result($r)) {
|
||||
$server = "https://".substr($orig_author, strpos($orig_author, "@") + 1);
|
||||
logger("1st try: reshared message ".$guid." will be fetched via SSL from the server ".$server);
|
||||
$item_id = self::storeByGuid($guid, $server);
|
||||
|
||||
if (!$item_id) {
|
||||
$server = "http://".substr($orig_author, strpos($orig_author, "@") + 1);
|
||||
logger("2nd try: reshared message ".$guid." will be fetched without SLL from the server ".$server);
|
||||
$item_id = self::storeByGuid($guid, $server);
|
||||
if (!DBM::is_result($item)) {
|
||||
if (empty($orig_author)) {
|
||||
logger('Empty author for guid ' . $guid . '. Quitting.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($item_id) {
|
||||
$server = "https://".substr($orig_author, strpos($orig_author, "@") + 1);
|
||||
logger("1st try: reshared message ".$guid." will be fetched via SSL from the server ".$server);
|
||||
$stored = self::storeByGuid($guid, $server);
|
||||
|
||||
if (!$stored) {
|
||||
$server = "http://".substr($orig_author, strpos($orig_author, "@") + 1);
|
||||
logger("2nd try: reshared message ".$guid." will be fetched without SSL from the server ".$server);
|
||||
$stored = self::storeByGuid($guid, $server);
|
||||
}
|
||||
|
||||
if ($stored) {
|
||||
$fields = ['body', 'tag', 'app', 'created', 'object-type', 'uri', 'guid',
|
||||
'author-name', 'author-link', 'author-avatar'];
|
||||
$condition = ['id' => $item_id, 'visible' => true, 'deleted' => false];
|
||||
$condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => false];
|
||||
$item = dba::selectfirst('item', $fields, $condition);
|
||||
|
||||
if (DBM::is_result($item)) {
|
||||
|
@ -2883,6 +2883,9 @@ class Diaspora
|
|||
|
||||
if ($message_id) {
|
||||
logger("Stored reshare ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
|
||||
if ($datarray['uid'] == 0) {
|
||||
Item::distribute($message_id);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -3107,6 +3110,9 @@ class Diaspora
|
|||
|
||||
if ($message_id) {
|
||||
logger("Stored item ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
|
||||
if ($datarray['uid'] == 0) {
|
||||
Item::distribute($message_id);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
|
|
@ -36,7 +36,30 @@ class Network
|
|||
*/
|
||||
public static function fetchUrl($url, $binary = false, &$redirects = 0, $timeout = 0, $accept_content = null, $cookiejar = 0)
|
||||
{
|
||||
$ret = self::curl(
|
||||
$ret = self::fetchUrlFull($url, $binary, $redirects, $timeout, $accept_content, $cookiejar);
|
||||
|
||||
return $ret['body'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Curl wrapper with array of return values.
|
||||
*
|
||||
* Inner workings and parameters are the same as @ref fetchUrl but returns an array with
|
||||
* all the information collected during the fetch.
|
||||
*
|
||||
* @param string $url URL to fetch
|
||||
* @param boolean $binary default false
|
||||
* TRUE if asked to return binary results (file download)
|
||||
* @param integer $redirects The recursion counter for internal use - default 0
|
||||
* @param integer $timeout Timeout in seconds, default system config value or 60 seconds
|
||||
* @param string $accept_content supply Accept: header with 'accept_content' as the value
|
||||
* @param string $cookiejar Path to cookie jar file
|
||||
*
|
||||
* @return array With all relevant information, 'body' contains the actual fetched content.
|
||||
*/
|
||||
public static function fetchUrlFull($url, $binary = false, &$redirects = 0, $timeout = 0, $accept_content = null, $cookiejar = 0)
|
||||
{
|
||||
return self::curl(
|
||||
$url,
|
||||
$binary,
|
||||
$redirects,
|
||||
|
@ -45,8 +68,6 @@ class Network
|
|||
'cookiejar'=>$cookiejar
|
||||
]
|
||||
);
|
||||
|
||||
return($ret['body']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -59,7 +59,7 @@ class Temporal
|
|||
|
||||
$o = '<select id="timezone_select" name="timezone">';
|
||||
|
||||
usort($timezone_identifiers, [self, 'timezoneCompareCallback']);
|
||||
usort($timezone_identifiers, [__CLASS__, 'timezoneCompareCallback']);
|
||||
$continent = '';
|
||||
foreach ($timezone_identifiers as $value) {
|
||||
$ex = explode("/", $value);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
namespace Friendica\Worker;
|
||||
|
||||
use Friendica\BaseObject;
|
||||
use Friendica\Core\Config;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\System;
|
||||
|
@ -19,98 +20,67 @@ use dba;
|
|||
|
||||
require_once 'include/items.php';
|
||||
|
||||
/// @todo This is some ugly code that needs to be split into several methods
|
||||
class Delivery extends BaseObject
|
||||
{
|
||||
const MAIL = 'mail';
|
||||
const SUGGESTION = 'suggest';
|
||||
const RELOCATION = 'relocate';
|
||||
const DELETION = 'drop';
|
||||
const POST = 'wall-new';
|
||||
const COMMENT = 'comment-new';
|
||||
|
||||
class Delivery {
|
||||
public static function execute($cmd, $item_id, $contact_id) {
|
||||
global $a;
|
||||
public static function execute($cmd, $item_id, $contact_id)
|
||||
{
|
||||
logger('Invoked: ' . $cmd . ': ' . $item_id . ' to ' . $contact_id, LOGGER_DEBUG);
|
||||
|
||||
logger('delivery: invoked: '.$cmd.': '.$item_id.' to '.$contact_id, LOGGER_DEBUG);
|
||||
|
||||
$mail = false;
|
||||
$fsuggest = false;
|
||||
$relocate = false;
|
||||
$top_level = false;
|
||||
$recipients = [];
|
||||
$followup = false;
|
||||
$public_message = false;
|
||||
|
||||
$normal_mode = true;
|
||||
|
||||
$item = null;
|
||||
|
||||
$recipients[] = $contact_id;
|
||||
|
||||
if ($cmd === 'mail') {
|
||||
$normal_mode = false;
|
||||
$mail = true;
|
||||
$message = q("SELECT * FROM `mail` WHERE `id` = %d LIMIT 1",
|
||||
intval($item_id)
|
||||
);
|
||||
if (!count($message)) {
|
||||
if ($cmd == self::MAIL) {
|
||||
$target_item = dba::selectFirst('mail', [], ['id' => $item_id]);
|
||||
if (!DBM::is_result($message)) {
|
||||
return;
|
||||
}
|
||||
$uid = $message[0]['uid'];
|
||||
$recipients[] = $message[0]['contact-id'];
|
||||
$item = $message[0];
|
||||
} elseif ($cmd === 'suggest') {
|
||||
$normal_mode = false;
|
||||
$fsuggest = true;
|
||||
|
||||
$suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1",
|
||||
intval($item_id)
|
||||
);
|
||||
if (!count($suggest)) {
|
||||
$uid = $target_item['uid'];
|
||||
} elseif ($cmd == self::SUGGESTION) {
|
||||
$target_item = dba::selectFirst('fsuggest', [], ['id' => $item_id]);
|
||||
if (!DBM::is_result($message)) {
|
||||
return;
|
||||
}
|
||||
$uid = $suggest[0]['uid'];
|
||||
$recipients[] = $suggest[0]['cid'];
|
||||
$item = $suggest[0];
|
||||
} elseif ($cmd === 'relocate') {
|
||||
$normal_mode = false;
|
||||
$relocate = true;
|
||||
$uid = $target_item['uid'];
|
||||
} elseif ($cmd == self::RELOCATION) {
|
||||
$uid = $item_id;
|
||||
} else {
|
||||
// find ancestors
|
||||
$target_item = dba::fetch_first("SELECT `item`.*, `contact`.`uid` AS `cuid` FROM `item`
|
||||
INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
|
||||
WHERE `item`.`id` = ? AND `visible` AND NOT `moderated`", $item_id);
|
||||
|
||||
if (!DBM::is_result($target_item) || !intval($target_item['parent'])) {
|
||||
$item = dba::selectFirst('item', ['parent'], ['id' => $item_id]);
|
||||
if (!DBM::is_result($item) || empty($item['parent'])) {
|
||||
return;
|
||||
}
|
||||
$parent_id = intval($item['parent']);
|
||||
|
||||
$parent_id = intval($target_item['parent']);
|
||||
$uid = $target_item['cuid'];
|
||||
$updated = $target_item['edited'];
|
||||
|
||||
$items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer`
|
||||
FROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d AND visible = 1 AND moderated = 0 ORDER BY `id` ASC",
|
||||
intval($parent_id)
|
||||
);
|
||||
|
||||
if (!count($items)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$icontacts = null;
|
||||
$contacts_arr = [];
|
||||
foreach ($items as $item) {
|
||||
if (!in_array($item['contact-id'],$contacts_arr)) {
|
||||
$contacts_arr[] = intval($item['contact-id']);
|
||||
$itemdata = dba::p("SELECT `item`.*, `contact`.`uid` AS `cuid`,
|
||||
`sign`.`signed_text`,`sign`.`signature`,`sign`.`signer`
|
||||
FROM `item`
|
||||
INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
|
||||
LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id`
|
||||
WHERE `item`.`id` IN (?, ?) AND `visible` AND NOT `moderated`
|
||||
ORDER BY `item`.`id`",
|
||||
$item_id, $parent_id);
|
||||
$items = [];
|
||||
while ($item = dba::fetch($itemdata)) {
|
||||
if ($item['id'] == $parent_id) {
|
||||
$parent = $item;
|
||||
}
|
||||
if ($item['id'] == $item_id) {
|
||||
$target_item = $item;
|
||||
}
|
||||
$items[] = $item;
|
||||
}
|
||||
if (count($contacts_arr)) {
|
||||
$str_contacts = implode(',',$contacts_arr);
|
||||
$icontacts = q("SELECT * FROM `contact`
|
||||
WHERE `id` IN ( $str_contacts ) "
|
||||
);
|
||||
}
|
||||
if ( !($icontacts && count($icontacts))) {
|
||||
return;
|
||||
}
|
||||
dba::close($itemdata);
|
||||
|
||||
$uid = $target_item['cuid'];
|
||||
|
||||
// avoid race condition with deleting entries
|
||||
|
||||
if ($items[0]['deleted']) {
|
||||
foreach ($items as $item) {
|
||||
$item['deleted'] = 1;
|
||||
|
@ -120,24 +90,10 @@ class Delivery {
|
|||
// When commenting too fast after delivery, a post wasn't recognized as top level post.
|
||||
// The count then showed more than one entry. The additional check should help.
|
||||
// The check for the "count" should be superfluous, but I'm not totally sure by now, so we keep it.
|
||||
if ((($items[0]['id'] == $item_id) || (count($items) == 1)) && ($items[0]['uri'] === $items[0]['parent-uri'])) {
|
||||
logger('delivery: top level post');
|
||||
if ((($parent['id'] == $item_id) || (count($items) == 1)) && ($parent['uri'] === $parent['parent-uri'])) {
|
||||
logger('Top level post');
|
||||
$top_level = true;
|
||||
}
|
||||
}
|
||||
|
||||
$owner = User::getOwnerDataById($uid);
|
||||
if (!$owner) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't treat Forum posts as "wall-to-wall" to be able to post them via Diaspora
|
||||
$walltowall = $top_level && ($owner['id'] != $items[0]['contact-id']) & ($owner['account-type'] != ACCOUNT_TYPE_COMMUNITY);
|
||||
|
||||
$public_message = true;
|
||||
|
||||
if (!$mail && !$fsuggest && !$relocate) {
|
||||
$parent = $items[0];
|
||||
|
||||
// This is IMPORTANT!!!!
|
||||
|
||||
|
@ -147,9 +103,9 @@ class Delivery {
|
|||
// if $parent['wall'] == 1 we will already have the parent message in our array
|
||||
// and we will relay the whole lot.
|
||||
|
||||
$localhost = $a->get_hostname();
|
||||
if (strpos($localhost,':')) {
|
||||
$localhost = substr($localhost,0,strpos($localhost,':'));
|
||||
$localhost = self::getApp()->get_hostname();
|
||||
if (strpos($localhost, ':')) {
|
||||
$localhost = substr($localhost, 0, strpos($localhost, ':'));
|
||||
}
|
||||
/**
|
||||
*
|
||||
|
@ -159,26 +115,24 @@ class Delivery {
|
|||
*
|
||||
*/
|
||||
|
||||
$relay_to_owner = false;
|
||||
|
||||
if (!$top_level && ($parent['wall'] == 0) && stristr($target_item['uri'], $localhost)) {
|
||||
$relay_to_owner = true;
|
||||
}
|
||||
|
||||
if ($relay_to_owner) {
|
||||
logger('followup '.$target_item["guid"], LOGGER_DEBUG);
|
||||
logger('Followup ' . $target_item["guid"], LOGGER_DEBUG);
|
||||
// local followup to remote post
|
||||
$followup = true;
|
||||
}
|
||||
|
||||
if (strlen($parent['allow_cid'])
|
||||
|| strlen($parent['allow_gid'])
|
||||
|| strlen($parent['deny_cid'])
|
||||
|| strlen($parent['deny_gid'])
|
||||
|| $parent["private"]) {
|
||||
$public_message = false; // private recipients, not public
|
||||
if (empty($parent['allow_cid'])
|
||||
&& empty($parent['allow_gid'])
|
||||
&& empty($parent['deny_cid'])
|
||||
&& empty($parent['deny_gid'])
|
||||
&& !$parent["private"]) {
|
||||
$public_message = true;
|
||||
}
|
||||
}
|
||||
|
||||
$owner = User::getOwnerDataById($uid);
|
||||
if (!DBM::is_result($owner)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't deliver our items to blocked or pending contacts, and not to ourselves either
|
||||
|
@ -189,146 +143,22 @@ class Delivery {
|
|||
return;
|
||||
}
|
||||
|
||||
$deliver_status = 0;
|
||||
|
||||
// Transmit via Diaspora if not possible via Friendica
|
||||
if (($item['uid'] == 0) && ($contact['network'] == NETWORK_DFRN)) {
|
||||
// Transmit via Diaspora if the thread had started as Diaspora post
|
||||
// This is done since the uri wouldn't match (Diaspora doesn't transmit it)
|
||||
if (isset($parent) && ($parent['network'] == NETWORK_DIASPORA) && ($contact['network'] == NETWORK_DFRN)) {
|
||||
$contact['network'] = NETWORK_DIASPORA;
|
||||
}
|
||||
|
||||
logger("main delivery by delivery: followup=$followup mail=$mail fsuggest=$fsuggest relocate=$relocate - network ".$contact['network']);
|
||||
logger("Delivering " . $cmd . " followup=$followup - via network " . $contact['network']);
|
||||
|
||||
switch ($contact['network']) {
|
||||
|
||||
case NETWORK_DFRN:
|
||||
logger('notifier: '.$target_item["guid"].' dfrndelivery: '.$contact['name']);
|
||||
|
||||
if ($mail) {
|
||||
$item['body'] = Item::fixPrivatePhotos($item['body'], $owner['uid'], null, $item['contact-id']);
|
||||
$atom = DFRN::mail($item, $owner);
|
||||
} elseif ($fsuggest) {
|
||||
$atom = DFRN::fsuggest($item, $owner);
|
||||
dba::delete('fsuggest', ['id' => $item['id']]);
|
||||
} elseif ($relocate) {
|
||||
$atom = DFRN::relocate($owner, $uid);
|
||||
} elseif ($followup) {
|
||||
$msgitems = [];
|
||||
foreach ($items as $item) { // there is only one item
|
||||
if (!$item['parent']) {
|
||||
return;
|
||||
}
|
||||
if ($item['id'] == $item_id) {
|
||||
logger('followup: item: '. print_r($item,true), LOGGER_DATA);
|
||||
$msgitems[] = $item;
|
||||
}
|
||||
}
|
||||
$atom = DFRN::entries($msgitems,$owner);
|
||||
} else {
|
||||
$msgitems = [];
|
||||
foreach ($items as $item) {
|
||||
if (!$item['parent']) {
|
||||
return;
|
||||
}
|
||||
|
||||
// private emails may be in included in public conversations. Filter them.
|
||||
if ($public_message && $item['private']) {
|
||||
return;
|
||||
}
|
||||
|
||||
$item_contact = self::getItemContact($item,$icontacts);
|
||||
if (!$item_contact) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($normal_mode) {
|
||||
// Only add the parent when we don't delete other items.
|
||||
if ($item_id == $item['id'] || (($item['id'] == $item['parent']) && ($cmd != 'drop'))) {
|
||||
$item["entry:comment-allow"] = true;
|
||||
$item["entry:cid"] = (($top_level) ? $contact['id'] : 0);
|
||||
$msgitems[] = $item;
|
||||
}
|
||||
} else {
|
||||
$item["entry:comment-allow"] = true;
|
||||
$msgitems[] = $item;
|
||||
}
|
||||
}
|
||||
$atom = DFRN::entries($msgitems,$owner);
|
||||
}
|
||||
|
||||
logger('notifier entry: '.$contact["url"].' '.$target_item["guid"].' entry: '.$atom, LOGGER_DEBUG);
|
||||
|
||||
logger('notifier: '.$atom, LOGGER_DATA);
|
||||
$basepath = implode('/', array_slice(explode('/',$contact['url']),0,3));
|
||||
|
||||
// perform local delivery if we are on the same site
|
||||
|
||||
if (link_compare($basepath,System::baseUrl())) {
|
||||
$nickname = basename($contact['url']);
|
||||
if ($contact['issued-id']) {
|
||||
$sql_extra = sprintf(" AND `dfrn-id` = '%s' ", dbesc($contact['issued-id']));
|
||||
} else {
|
||||
$sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($contact['dfrn-id']));
|
||||
}
|
||||
|
||||
$x = q("SELECT `contact`.*, `contact`.`uid` AS `importer_uid`,
|
||||
`contact`.`pubkey` AS `cpubkey`,
|
||||
`contact`.`prvkey` AS `cprvkey`,
|
||||
`contact`.`thumb` AS `thumb`,
|
||||
`contact`.`url` as `url`,
|
||||
`contact`.`name` as `senderName`,
|
||||
`user`.*
|
||||
FROM `contact`
|
||||
INNER JOIN `user` ON `contact`.`uid` = `user`.`uid`
|
||||
WHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0
|
||||
AND `contact`.`network` = '%s' AND `user`.`nickname` = '%s'
|
||||
$sql_extra
|
||||
AND `user`.`account_expired` = 0 AND `user`.`account_removed` = 0 LIMIT 1",
|
||||
dbesc(NETWORK_DFRN),
|
||||
dbesc($nickname)
|
||||
);
|
||||
|
||||
if ($x && count($x)) {
|
||||
$write_flag = ((($x[0]['rel']) && ($x[0]['rel'] != CONTACT_IS_SHARING)) ? true : false);
|
||||
if ((($owner['page-flags'] == PAGE_COMMUNITY) || $write_flag) && !$x[0]['writable']) {
|
||||
dba::update('contact', ['writable' => true], ['id' => $x[0]['id']]);
|
||||
$x[0]['writable'] = 1;
|
||||
}
|
||||
|
||||
$ssl_policy = Config::get('system','ssl_policy');
|
||||
$x[0] = Contact::updateSslPolicy($x[0], $ssl_policy);
|
||||
|
||||
// If we are setup as a soapbox we aren't accepting top level posts from this person
|
||||
|
||||
if (($x[0]['page-flags'] == PAGE_SOAPBOX) && $top_level) {
|
||||
break;
|
||||
}
|
||||
logger('mod-delivery: local delivery');
|
||||
DFRN::import($atom, $x[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Queue::wasDelayed($contact['id'])) {
|
||||
$deliver_status = DFRN::deliver($owner, $contact, $atom);
|
||||
} else {
|
||||
$deliver_status = -1;
|
||||
}
|
||||
|
||||
logger('notifier: dfrn_delivery to '.$contact["url"].' with guid '.$target_item["guid"].' returns '.$deliver_status);
|
||||
|
||||
if ($deliver_status < 0) {
|
||||
logger('notifier: delivery failed: queuing message');
|
||||
Queue::add($contact['id'], NETWORK_DFRN, $atom, false, $target_item['guid']);
|
||||
}
|
||||
|
||||
if (($deliver_status >= 200) && ($deliver_status <= 299)) {
|
||||
// We successfully delivered a message, the contact is alive
|
||||
Contact::unmarkForArchival($contact);
|
||||
} else {
|
||||
// The message could not be delivered. We mark the contact as "dead"
|
||||
Contact::markForArchival($contact);
|
||||
}
|
||||
self::deliverDFRN($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup);
|
||||
break;
|
||||
|
||||
case NETWORK_DIASPORA:
|
||||
self::deliverDiaspora($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup);
|
||||
break;
|
||||
|
||||
case NETWORK_OSTATUS:
|
||||
|
@ -345,156 +175,7 @@ class Delivery {
|
|||
break;
|
||||
|
||||
case NETWORK_MAIL:
|
||||
|
||||
if (Config::get('system','dfrn_only')) {
|
||||
break;
|
||||
}
|
||||
// WARNING: does not currently convert to RFC2047 header encodings, etc.
|
||||
|
||||
$addr = $contact['addr'];
|
||||
if (!strlen($addr)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ($cmd === 'wall-new' || $cmd === 'comment-new') {
|
||||
$it = null;
|
||||
if ($cmd === 'wall-new') {
|
||||
$it = $items[0];
|
||||
} else {
|
||||
$r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1",
|
||||
intval($item_id)
|
||||
);
|
||||
if (DBM::is_result($r)) {
|
||||
$it = $r[0];
|
||||
}
|
||||
}
|
||||
if (!$it) {
|
||||
break;
|
||||
}
|
||||
|
||||
$local_user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
|
||||
intval($uid)
|
||||
);
|
||||
if (!count($local_user)) {
|
||||
break;
|
||||
}
|
||||
|
||||
$reply_to = '';
|
||||
$r1 = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1",
|
||||
intval($uid)
|
||||
);
|
||||
if ($r1 && $r1[0]['reply_to']) {
|
||||
$reply_to = $r1[0]['reply_to'];
|
||||
}
|
||||
|
||||
$subject = (($it['title']) ? Email::encodeHeader($it['title'],'UTF-8') : L10n::t("\x28no subject\x29")) ;
|
||||
|
||||
// only expose our real email address to true friends
|
||||
|
||||
if (($contact['rel'] == CONTACT_IS_FRIEND) && !$contact['blocked']) {
|
||||
if ($reply_to) {
|
||||
$headers = 'From: '.Email::encodeHeader($local_user[0]['username'],'UTF-8').' <'.$reply_to.'>'."\n";
|
||||
$headers .= 'Sender: '.$local_user[0]['email']."\n";
|
||||
} else {
|
||||
$headers = 'From: '.Email::encodeHeader($local_user[0]['username'],'UTF-8').' <'.$local_user[0]['email'].'>'."\n";
|
||||
}
|
||||
} else {
|
||||
$headers = 'From: '. Email::encodeHeader($local_user[0]['username'], 'UTF-8') . ' <noreply@' . $a->get_hostname() . '>' . "\n";
|
||||
}
|
||||
|
||||
//if ($reply_to)
|
||||
// $headers .= 'Reply-to: '.$reply_to . "\n";
|
||||
|
||||
$headers .= 'Message-Id: <'. Email::iri2msgid($it['uri']).'>'. "\n";
|
||||
|
||||
//logger("Mail: uri: ".$it['uri']." parent-uri ".$it['parent-uri'], LOGGER_DEBUG);
|
||||
//logger("Mail: Data: ".print_r($it, true), LOGGER_DEBUG);
|
||||
//logger("Mail: Data: ".print_r($it, true), LOGGER_DATA);
|
||||
|
||||
if ($it['uri'] !== $it['parent-uri']) {
|
||||
$headers .= "References: <".Email::iri2msgid($it["parent-uri"]).">";
|
||||
|
||||
// If Threading is enabled, write down the correct parent
|
||||
if (($it["thr-parent"] != "") && ($it["thr-parent"] != $it["parent-uri"])) {
|
||||
$headers .= " <".Email::iri2msgid($it["thr-parent"]).">";
|
||||
}
|
||||
$headers .= "\n";
|
||||
|
||||
if (!$it['title']) {
|
||||
$r = q("SELECT `title` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
|
||||
dbesc($it['parent-uri']),
|
||||
intval($uid));
|
||||
|
||||
if (DBM::is_result($r) && ($r[0]['title'] != '')) {
|
||||
$subject = $r[0]['title'];
|
||||
} else {
|
||||
$r = q("SELECT `title` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d LIMIT 1",
|
||||
dbesc($it['parent-uri']),
|
||||
intval($uid));
|
||||
|
||||
if (DBM::is_result($r) && ($r[0]['title'] != '')) {
|
||||
$subject = $r[0]['title'];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (strncasecmp($subject,'RE:',3)) {
|
||||
$subject = 'Re: '.$subject;
|
||||
}
|
||||
}
|
||||
Email::send($addr, $subject, $headers, $it);
|
||||
}
|
||||
break;
|
||||
|
||||
case NETWORK_DIASPORA:
|
||||
if ($public_message) {
|
||||
$loc = 'public batch '.$contact['batch'];
|
||||
} else {
|
||||
$loc = $contact['name'];
|
||||
}
|
||||
|
||||
logger('delivery: diaspora batch deliver: '.$loc);
|
||||
|
||||
if (Config::get('system','dfrn_only') || !Config::get('system','diaspora_enabled')) {
|
||||
break;
|
||||
}
|
||||
if ($mail) {
|
||||
Diaspora::sendMail($item,$owner,$contact);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$normal_mode) {
|
||||
break;
|
||||
}
|
||||
if (!$contact['pubkey'] && !$public_message) {
|
||||
break;
|
||||
}
|
||||
if (($target_item['deleted']) && (($target_item['uri'] === $target_item['parent-uri']) || $followup)) {
|
||||
// top-level retraction
|
||||
logger('diaspora retract: '.$loc);
|
||||
Diaspora::sendRetraction($target_item,$owner,$contact,$public_message);
|
||||
break;
|
||||
} elseif ($relocate) {
|
||||
Diaspora::sendAccountMigration($owner, $contact, $uid);
|
||||
break;
|
||||
} elseif ($followup) {
|
||||
// send comments and likes to owner to relay
|
||||
logger('diaspora followup: '.$loc);
|
||||
Diaspora::sendFollowup($target_item,$owner,$contact,$public_message);
|
||||
break;
|
||||
} elseif ($target_item['uri'] !== $target_item['parent-uri']) {
|
||||
// we are the relay - send comments, likes and relayable_retractions to our conversants
|
||||
logger('diaspora relay: '.$loc);
|
||||
Diaspora::sendRelay($target_item,$owner,$contact,$public_message);
|
||||
break;
|
||||
} elseif ($top_level && !$walltowall) {
|
||||
// currently no workable solution for sending walltowall
|
||||
logger('diaspora status: '.$loc);
|
||||
Diaspora::sendStatus($target_item,$owner,$contact,$public_message);
|
||||
break;
|
||||
}
|
||||
|
||||
logger('delivery: diaspora unknown mode: '.$contact['name']);
|
||||
|
||||
self::deliverMail($cmd, $contact, $owner, $target_item);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -504,16 +185,268 @@ class Delivery {
|
|||
return;
|
||||
}
|
||||
|
||||
private static function getItemContact($item, $contacts)
|
||||
/**
|
||||
* @brief Deliver content via DFRN
|
||||
*
|
||||
* @param string $cmd Command
|
||||
* @param array $contact Contact record of the receiver
|
||||
* @param array $owner Owner record of the sender
|
||||
* @param array $items Item record of the content and the parent
|
||||
* @param array $target_item Item record of the content
|
||||
* @param boolean $public_message Is the content public?
|
||||
* @param boolean $top_level Is it a thread starter?
|
||||
* @param boolean $followup Is it an answer to a remote post?
|
||||
*/
|
||||
private static function deliverDFRN($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup)
|
||||
{
|
||||
if (!count($contacts) || !is_array($item)) {
|
||||
return false;
|
||||
logger('Deliver ' . $target_item["guid"] . ' via DFRN to ' . $contact['addr']);
|
||||
|
||||
if ($cmd == self::MAIL) {
|
||||
$item = $target_item;
|
||||
$item['body'] = Item::fixPrivatePhotos($item['body'], $owner['uid'], null, $item['contact-id']);
|
||||
$atom = DFRN::mail($item, $owner);
|
||||
} elseif ($cmd == self::SUGGESTION) {
|
||||
$item = $target_item;
|
||||
$atom = DFRN::fsuggest($item, $owner);
|
||||
dba::delete('fsuggest', ['id' => $item['id']]);
|
||||
} elseif ($cmd == self::RELOCATION) {
|
||||
$atom = DFRN::relocate($owner, $owner['uid']);
|
||||
} elseif ($followup) {
|
||||
$msgitems = [$target_item];
|
||||
$atom = DFRN::entries($msgitems, $owner);
|
||||
} else {
|
||||
$msgitems = [];
|
||||
foreach ($items as $item) {
|
||||
// Only add the parent when we don't delete other items.
|
||||
if (($target_item['id'] == $item['id']) || ($cmd != self::DELETION)) {
|
||||
$item["entry:comment-allow"] = true;
|
||||
$item["entry:cid"] = ($top_level ? $contact['id'] : 0);
|
||||
$msgitems[] = $item;
|
||||
}
|
||||
}
|
||||
$atom = DFRN::entries($msgitems, $owner);
|
||||
}
|
||||
foreach ($contacts as $contact) {
|
||||
if ($contact['id'] == $item['contact-id']) {
|
||||
return $contact;
|
||||
|
||||
logger('Notifier entry: ' . $contact["url"] . ' ' . $target_item["guid"] . ' entry: ' . $atom, LOGGER_DATA);
|
||||
|
||||
$basepath = implode('/', array_slice(explode('/', $contact['url']), 0, 3));
|
||||
|
||||
// perform local delivery if we are on the same site
|
||||
|
||||
if (link_compare($basepath, System::baseUrl())) {
|
||||
$condition = ['nurl' => normalise_link($contact['url']), 'self' => true];
|
||||
$target_self = dba::selectFirst('contact', ['uid'], $condition);
|
||||
if (!DBM::is_result($target_self)) {
|
||||
return;
|
||||
}
|
||||
$target_uid = $target_self['uid'];
|
||||
|
||||
// Check if the user has got this contact
|
||||
$cid = Contact::getIdForURL($owner['url'], $target_uid);
|
||||
if (!$cid) {
|
||||
// Otherwise there should be a public contact
|
||||
$cid = Contact::getIdForURL($owner['url']);
|
||||
if (!$cid) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We now have some contact, so we fetch it
|
||||
$target_importer = dba::fetch_first("SELECT *, `name` as `senderName`
|
||||
FROM `contact`
|
||||
WHERE NOT `blocked` AND `id` = ? LIMIT 1",
|
||||
$cid);
|
||||
|
||||
// This should never fail
|
||||
if (!DBM::is_result($target_importer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the user id. This is important if this is a public contact
|
||||
$target_importer['importer_uid'] = $target_uid;
|
||||
DFRN::import($atom, $target_importer);
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't have a relationship with contacts on a public post.
|
||||
// Se we transmit with the new method and via Diaspora as a fallback
|
||||
if ($items[0]['uid'] == 0) {
|
||||
// Transmit in public if it's a relay post
|
||||
$public_dfrn = ($contact['contact-type'] == ACCOUNT_TYPE_RELAY);
|
||||
|
||||
$deliver_status = DFRN::transmit($owner, $contact, $atom, $public_dfrn);
|
||||
if (($deliver_status < 200) || ($deliver_status > 299)) {
|
||||
// Transmit via Diaspora if not possible via Friendica
|
||||
self::deliverDiaspora($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$deliver_status = DFRN::deliver($owner, $contact, $atom);
|
||||
}
|
||||
|
||||
logger('Delivery to ' . $contact["url"] . ' with guid ' . $target_item["guid"] . ' returns ' . $deliver_status);
|
||||
|
||||
if ($deliver_status < 0) {
|
||||
logger('Delivery failed: queuing message ' . $target_item["guid"] );
|
||||
Queue::add($contact['id'], NETWORK_DFRN, $atom, false, $target_item['guid']);
|
||||
}
|
||||
|
||||
if (($deliver_status >= 200) && ($deliver_status <= 299)) {
|
||||
// We successfully delivered a message, the contact is alive
|
||||
Contact::unmarkForArchival($contact);
|
||||
} else {
|
||||
// The message could not be delivered. We mark the contact as "dead"
|
||||
Contact::markForArchival($contact);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deliver content via Diaspora
|
||||
*
|
||||
* @param string $cmd Command
|
||||
* @param array $contact Contact record of the receiver
|
||||
* @param array $owner Owner record of the sender
|
||||
* @param array $items Item record of the content and the parent
|
||||
* @param array $target_item Item record of the content
|
||||
* @param boolean $public_message Is the content public?
|
||||
* @param boolean $top_level Is it a thread starter?
|
||||
* @param boolean $followup Is it an answer to a remote post?
|
||||
*/
|
||||
private static function deliverDiaspora($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup)
|
||||
{
|
||||
// We don't treat Forum posts as "wall-to-wall" to be able to post them via Diaspora
|
||||
$walltowall = $top_level && ($owner['id'] != $items[0]['contact-id']) & ($owner['account-type'] != ACCOUNT_TYPE_COMMUNITY);
|
||||
|
||||
if ($public_message) {
|
||||
$loc = 'public batch ' . $contact['batch'];
|
||||
} else {
|
||||
$loc = $contact['addr'];
|
||||
}
|
||||
|
||||
logger('Deliver ' . $target_item["guid"] . ' via Diaspora to ' . $loc);
|
||||
|
||||
if (Config::get('system', 'dfrn_only') || !Config::get('system', 'diaspora_enabled')) {
|
||||
return;
|
||||
}
|
||||
if ($cmd == self::MAIL) {
|
||||
Diaspora::sendMail($target_item, $owner, $contact);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($cmd == self::SUGGESTION) {
|
||||
return;
|
||||
}
|
||||
if (!$contact['pubkey'] && !$public_message) {
|
||||
return;
|
||||
}
|
||||
if (($target_item['deleted']) && (($target_item['uri'] === $target_item['parent-uri']) || $followup)) {
|
||||
// top-level retraction
|
||||
logger('diaspora retract: ' . $loc);
|
||||
Diaspora::sendRetraction($target_item, $owner, $contact, $public_message);
|
||||
return;
|
||||
} elseif ($cmd == self::RELOCATION) {
|
||||
Diaspora::sendAccountMigration($owner, $contact, $owner['uid']);
|
||||
return;
|
||||
} elseif ($followup) {
|
||||
// send comments and likes to owner to relay
|
||||
logger('diaspora followup: ' . $loc);
|
||||
Diaspora::sendFollowup($target_item, $owner, $contact, $public_message);
|
||||
return;
|
||||
} elseif ($target_item['uri'] !== $target_item['parent-uri']) {
|
||||
// we are the relay - send comments, likes and relayable_retractions to our conversants
|
||||
logger('diaspora relay: ' . $loc);
|
||||
Diaspora::sendRelay($target_item, $owner, $contact, $public_message);
|
||||
return;
|
||||
} elseif ($top_level && !$walltowall) {
|
||||
// currently no workable solution for sending walltowall
|
||||
logger('diaspora status: ' . $loc);
|
||||
Diaspora::sendStatus($target_item, $owner, $contact, $public_message);
|
||||
return;
|
||||
}
|
||||
|
||||
logger('Unknown mode ' . $cmd . ' for ' . $loc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deliver content via mail
|
||||
*
|
||||
* @param string $cmd Command
|
||||
* @param array $contact Contact record of the receiver
|
||||
* @param array $owner Owner record of the sender
|
||||
* @param array $target_item Item record of the content
|
||||
*/
|
||||
private static function deliverMail($cmd, $contact, $owner, $target_item)
|
||||
{
|
||||
if (Config::get('system','dfrn_only')) {
|
||||
return;
|
||||
}
|
||||
// WARNING: does not currently convert to RFC2047 header encodings, etc.
|
||||
|
||||
$addr = $contact['addr'];
|
||||
if (!strlen($addr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!in_array($cmd, [self::POST, self::COMMENT])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$local_user = dba::selectFirst('user', [], ['uid' => $owner['uid']]);
|
||||
if (!DBM::is_result($local_user)) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger('Deliver ' . $target_item["guid"] . ' via mail to ' . $contact['addr']);
|
||||
|
||||
$reply_to = '';
|
||||
$mailacct = dba::selectFirst('mailacct', ['reply_to'], ['uid' => $owner['uid']]);
|
||||
if (DBM::is_result($mailacct) && !empty($mailacct['reply_to'])) {
|
||||
$reply_to = $mailacct['reply_to'];
|
||||
}
|
||||
|
||||
$subject = ($target_item['title'] ? Email::encodeHeader($target_item['title'], 'UTF-8') : L10n::t("\x28no subject\x29"));
|
||||
|
||||
// only expose our real email address to true friends
|
||||
|
||||
if (($contact['rel'] == CONTACT_IS_FRIEND) && !$contact['blocked']) {
|
||||
if ($reply_to) {
|
||||
$headers = 'From: ' . Email::encodeHeader($local_user['username'],'UTF-8') . ' <' . $reply_to.'>' . "\n";
|
||||
$headers .= 'Sender: ' . $local_user['email'] . "\n";
|
||||
} else {
|
||||
$headers = 'From: ' . Email::encodeHeader($local_user['username'],'UTF-8').' <' . $local_user['email'] . '>' . "\n";
|
||||
}
|
||||
} else {
|
||||
$headers = 'From: '. Email::encodeHeader($local_user['username'], 'UTF-8') . ' <noreply@' . self::getApp()->get_hostname() . '>' . "\n";
|
||||
}
|
||||
|
||||
$headers .= 'Message-Id: <' . Email::iri2msgid($target_item['uri']) . '>' . "\n";
|
||||
|
||||
if ($target_item['uri'] !== $target_item['parent-uri']) {
|
||||
$headers .= "References: <" . Email::iri2msgid($target_item["parent-uri"]) . ">";
|
||||
|
||||
// If Threading is enabled, write down the correct parent
|
||||
if (($target_item["thr-parent"] != "") && ($target_item["thr-parent"] != $target_item["parent-uri"])) {
|
||||
$headers .= " <".Email::iri2msgid($target_item["thr-parent"]).">";
|
||||
}
|
||||
$headers .= "\n";
|
||||
|
||||
if (empty($target_item['title'])) {
|
||||
$condition = ['uri' => $target_item['parent-uri'], 'uid' => $owner['uid']];
|
||||
$title = dba::selectFirst('item', ['title'], $condition);
|
||||
if (DBM::is_result($title) && ($title['title'] != '')) {
|
||||
$subject = $title['title'];
|
||||
} else {
|
||||
$condition = ['parent-uri' => $target_item['parent-uri'], 'uid' => $owner['uid']];
|
||||
$title = dba::selectFirst('item', ['title'], $condition);
|
||||
if (DBM::is_result($title) && ($title['title'] != '')) {
|
||||
$subject = $title['title'];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (strncasecmp($subject, 'RE:', 3)) {
|
||||
$subject = 'Re: ' . $subject;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
Email::send($addr, $subject, $headers, $target_item);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ class PubSubPublish {
|
|||
$rr['topic']),
|
||||
"X-Hub-Signature: sha1=".$hmac_sig];
|
||||
|
||||
logger('POST '.print_r($headers, true)."\n".$params, LOGGER_DEBUG);
|
||||
logger('POST '.print_r($headers, true)."\n".$params, LOGGER_DATA);
|
||||
|
||||
Network::post($rr['callback_url'], $params, $headers);
|
||||
$ret = $a->get_curl_code();
|
||||
|
|
|
@ -63,7 +63,7 @@ class Queue
|
|||
return;
|
||||
}
|
||||
|
||||
if (empty($contact['notify'])) {
|
||||
if (empty($contact['notify']) || $contact['archive']) {
|
||||
QueueModel::removeItem($q_item['id']);
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue