From d867d73a2358050adceb0dab60612d5f56cbd211 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Sun, 20 Oct 2024 07:50:08 +0000
Subject: [PATCH] Improved block behaviour

---
 database.sql                                 |  10 +-
 src/Content/Widget/VCard.php                 |   5 +
 src/Core/Protocol.php                        |  40 +++-
 src/Model/Contact.php                        |  12 +-
 src/Model/Contact/User.php                   |  14 +-
 src/Model/Post.php                           |   2 +-
 src/Module/Api/Mastodon/Accounts/Block.php   |  11 --
 src/Module/Api/Mastodon/Statuses/Context.php |   2 +-
 src/Module/Api/Mastodon/Timelines/Direct.php |   2 +-
 src/Module/Api/Mastodon/Timelines/Home.php   |   2 +-
 src/Module/Api/Mastodon/Timelines/Tag.php    |   2 +-
 src/Module/Contact/Profile.php               |   5 +
 src/Protocol/ActivityPub/Transmitter.php     |  52 ++++-
 src/Worker/Contact/Block.php                 |  38 ++++
 src/Worker/Contact/Unblock.php               |  38 ++++
 static/dbstructure.config.php                |   2 +-
 static/dbview.config.php                     |   8 +-
 view/lang/C/messages.po                      | 192 ++++++++++---------
 18 files changed, 309 insertions(+), 128 deletions(-)
 create mode 100644 src/Worker/Contact/Block.php
 create mode 100644 src/Worker/Contact/Unblock.php

diff --git a/database.sql b/database.sql
index 16e3b7af98..6d19766960 100644
--- a/database.sql
+++ b/database.sql
@@ -1,6 +1,6 @@
 -- ------------------------------------------
 -- Friendica 2024.09-rc (Yellow Archangel)
--- DB_UPDATE_VERSION 1574
+-- DB_UPDATE_VERSION 1575
 -- ------------------------------------------
 
 
@@ -2123,7 +2123,7 @@ CREATE VIEW `post-engagement-user-view` AS SELECT
 			AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`)
 			AND (`post-thread-user`.`hidden` IS NULL OR NOT `post-thread-user`.`hidden`)
 			AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked`
-			AND NOT EXISTS(SELECT `cid`  FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored`))
+			AND NOT EXISTS(SELECT `cid`  FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored` OR `is-blocked`))
 			AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`);
 
 --
@@ -2249,7 +2249,7 @@ CREATE VIEW `post-searchindex-user-view` AS SELECT
 			AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`)
 			AND (`post-thread-user`.`hidden` IS NULL OR NOT `post-thread-user`.`hidden`)
 			AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked`
-			AND NOT EXISTS(SELECT `cid`  FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored`))
+			AND NOT EXISTS(SELECT `cid`  FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored` OR `is-blocked`))
 			AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`);
 
 --
@@ -3429,7 +3429,7 @@ CREATE VIEW `network-thread-view` AS SELECT
 			AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`)
 			AND (`post-thread-user`.`hidden` IS NULL OR NOT `post-thread-user`.`hidden`)
 			AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked`
-			AND NOT EXISTS(SELECT `cid`  FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`post-thread-user`.`author-id`, `post-thread-user`.`owner-id`, `post-thread-user`.`causer-id`) AND (`blocked` OR `ignored` OR `channel-only`))
+			AND NOT EXISTS(SELECT `cid`  FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`post-thread-user`.`author-id`, `post-thread-user`.`owner-id`, `post-thread-user`.`causer-id`) AND (`blocked` OR `ignored` OR `is-blocked` OR `channel-only`))
 			AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`);
 
 --
@@ -3457,7 +3457,7 @@ CREATE VIEW `network-thread-circle-view` AS SELECT
 			AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`)
 			AND (`post-thread-user`.`hidden` IS NULL OR NOT `post-thread-user`.`hidden`)
 			AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked`
-			AND NOT EXISTS(SELECT `cid`  FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`post-thread-user`.`author-id`, `post-thread-user`.`owner-id`, `post-thread-user`.`causer-id`) AND (`blocked` OR `ignored`))
+			AND NOT EXISTS(SELECT `cid`  FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`post-thread-user`.`author-id`, `post-thread-user`.`owner-id`, `post-thread-user`.`causer-id`) AND (`blocked` OR `ignored` OR `is-blocked`))
 			AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`);
 
 --
diff --git a/src/Content/Widget/VCard.php b/src/Content/Widget/VCard.php
index 8a33ba09e9..3ccdaeb421 100644
--- a/src/Content/Widget/VCard.php
+++ b/src/Content/Widget/VCard.php
@@ -58,6 +58,11 @@ class VCard
 		$photo   = Contact::getPhoto($contact);
 
 		if (DI::userSession()->getLocalUserId()) {
+			if (Contact\User::isIsBlocked($contact['id'], DI::userSession()->getLocalUserId())) {
+				$hide_follow  = true;
+				$hide_mention = true;
+			}
+		
 			if ($contact['uid']) {
 				$id      = $contact['id'];
 				$rel     = $contact['rel'];
diff --git a/src/Core/Protocol.php b/src/Core/Protocol.php
index e8ffe57123..8270400025 100644
--- a/src/Core/Protocol.php
+++ b/src/Core/Protocol.php
@@ -11,6 +11,7 @@ use Friendica\Database\DBA;
 use Friendica\Model\User;
 use Friendica\Network\HTTPException;
 use Friendica\Protocol\ActivityPub;
+use Friendica\Protocol\ActivityPub\Transmitter;
 use Friendica\Protocol\Diaspora;
 
 /**
@@ -211,7 +212,7 @@ class Protocol
 	}
 
 	/**
-	 * Send a block message to a remote server. Only useful for connector addons.
+	 * Send a block message to a remote server.
 	 *
 	 * @param array $contact Public contact record to block
 	 * @param int   $uid     User issuing the block
@@ -220,6 +221,23 @@ class Protocol
 	 */
 	public static function block(array $contact, int $uid): ?bool
 	{
+		if (empty($contact['network'])) {
+			throw new \InvalidArgumentException('Missing network key in contact array');
+		}
+
+		$protocol = $contact['network'];
+		if ($protocol == self::DFRN && !empty($contact['protocol'])) {
+			$protocol = $contact['protocol'];
+		}
+
+		if ($protocol == self::ACTIVITYPUB) {
+			$activity_id = Transmitter::activityIDFromContact($contact['id'], $uid);
+			if (empty($activity_id)) {
+				return false;
+			}
+			return ActivityPub\Transmitter::sendActivity('Block', $contact['url'], $uid, $activity_id);
+		}
+
 		// Catch-all hook for connector addons
 		$hook_data = [
 			'contact' => $contact,
@@ -232,7 +250,7 @@ class Protocol
 	}
 
 	/**
-	 * Send an unblock message to a remote server. Only useful for connector addons.
+	 * Send an unblock message to a remote server.
 	 *
 	 * @param array $contact Public contact record to unblock
 	 * @param int   $uid     User revoking the block
@@ -241,6 +259,24 @@ class Protocol
 	 */
 	public static function unblock(array $contact, int $uid): ?bool
 	{
+		$owner = User::getOwnerDataById($uid);
+		if (!DBA::isResult($owner)) {
+			return false;
+		}
+
+		if (empty($contact['network'])) {
+			throw new \InvalidArgumentException('Missing network key in contact array');
+		}
+
+		$protocol = $contact['network'];
+		if ($protocol == self::DFRN && !empty($contact['protocol'])) {
+			$protocol = $contact['protocol'];
+		}
+
+		if ($protocol == self::ACTIVITYPUB) {
+			return ActivityPub\Transmitter::sendContactUnblock($contact['url'], $contact['id'], $owner);
+		}
+
 		// Catch-all hook for connector addons
 		$hook_data = [
 			'contact' => $contact,
diff --git a/src/Model/Contact.php b/src/Model/Contact.php
index cd0d1feca2..e88f8dc6aa 100644
--- a/src/Model/Contact.php
+++ b/src/Model/Contact.php
@@ -1590,11 +1590,15 @@ class Contact
 	 */
 	public static function getPostsFromId(int $cid, int $uid, bool $only_media = false, string $last_created = null): string
 	{
-		$contact = DBA::selectFirst('contact', ['contact-type', 'network'], ['id' => $cid]);
+		$contact = DBA::selectFirst('contact', ['contact-type', 'network', 'name', 'nick'], ['id' => $cid]);
 		if (!DBA::isResult($contact)) {
 			return '';
 		}
 
+		if (Contact\User::isIsBlocked($cid, $uid)) {
+			return DI::l10n()->t('%s has blocked you', $contact['name'] ?: $contact['nick']);
+		}
+
 		if (empty($contact["network"]) || in_array($contact["network"], Protocol::FEDERATED)) {
 			$condition = ["(`uid` = 0 OR (`uid` = ? AND NOT `global`))", $uid];
 		} else {
@@ -1658,11 +1662,15 @@ class Contact
 	 */
 	public static function getThreadsFromId(int $cid, int $uid, int $update = 0, int $parent = 0, string $last_created = ''): string
 	{
-		$contact = DBA::selectFirst('contact', ['contact-type', 'network'], ['id' => $cid]);
+		$contact = DBA::selectFirst('contact', ['contact-type', 'network', 'name', 'nick'], ['id' => $cid]);
 		if (!DBA::isResult($contact)) {
 			return '';
 		}
 
+		if (Contact\User::isIsBlocked($cid, $uid)) {
+			return DI::l10n()->t('%s has blocked you', $contact['name'] ?: $contact['nick']);
+		}
+
 		if (empty($contact["network"]) || in_array($contact["network"], Protocol::FEDERATED)) {
 			$condition = ["(`uid` = 0 OR (`uid` = ? AND NOT `global`))", $uid];
 		} else {
diff --git a/src/Model/Contact/User.php b/src/Model/Contact/User.php
index 084b438038..ad121fd86a 100644
--- a/src/Model/Contact/User.php
+++ b/src/Model/Contact/User.php
@@ -9,7 +9,7 @@ namespace Friendica\Model\Contact;
 
 use Exception;
 use Friendica\Core\Logger;
-use Friendica\Core\Protocol;
+use Friendica\Core\Worker;
 use Friendica\Database\Database;
 use Friendica\Database\DBA;
 use Friendica\DI;
@@ -140,13 +140,21 @@ class User
 
 		$contact = Contact::getById($cdata['public']);
 		if ($blocked) {
-			Protocol::block($contact, $uid);
+			Worker::add(Worker::PRIORITY_HIGH, 'Contact\Block', $cid, $uid);
 		} else {
-			Protocol::unblock($contact, $uid);
+			Worker::add(Worker::PRIORITY_HIGH, 'Contact\Unblock', $cid, $uid);
 		}
 
 		if ($cdata['user'] != 0) {
 			DBA::update('contact', ['blocked' => $blocked], ['id' => $cdata['user'], 'pending' => false]);
+
+			if ($blocked) {
+				$contact = Contact::getById($cdata['user']);
+				if (!empty($contact)) {
+					// Mastodon-expected behavior: relationship is severed on block
+					Contact::terminateFriendship($contact);
+				}
+			}
 		}
 
 		DBA::update('user-contact', ['blocked' => $blocked], ['cid' => $cdata['public'], 'uid' => $uid], true);
diff --git a/src/Model/Post.php b/src/Model/Post.php
index 2f96b714a7..3439ce4846 100644
--- a/src/Model/Post.php
+++ b/src/Model/Post.php
@@ -465,7 +465,7 @@ class Post
 			AND ((NOT `contact-readonly` AND NOT `contact-pending` AND (`contact-rel` IN (?, ?)))
 				OR `self` OR `contact-uid` = ?)
 			AND NOT EXISTS(SELECT `uri-id` FROM `post-user`    WHERE `uid` = ? AND `uri-id` = " . DBA::quoteIdentifier($view) . ".`uri-id` AND `hidden`)
-			AND NOT EXISTS(SELECT `cid`    FROM `user-contact` WHERE `uid` = ? AND `cid` IN (`author-id`, `owner-id`) AND (`blocked` OR `ignored`))
+			AND NOT EXISTS(SELECT `cid`    FROM `user-contact` WHERE `uid` = ? AND `cid` IN (`author-id`, `owner-id`) AND (`blocked` OR `ignored` OR `is-blocked`))
 			AND NOT EXISTS(SELECT `gsid`   FROM `user-gserver` WHERE `uid` = ? AND `gsid` IN (`author-gsid`, `owner-gsid`, `causer-gsid`) AND `ignored`)",
 				0, Contact::SHARING, Contact::FRIEND, 0, $uid, $uid, $uid]);
 
diff --git a/src/Module/Api/Mastodon/Accounts/Block.php b/src/Module/Api/Mastodon/Accounts/Block.php
index 95735c8f1e..941f6542bd 100644
--- a/src/Module/Api/Mastodon/Accounts/Block.php
+++ b/src/Module/Api/Mastodon/Accounts/Block.php
@@ -7,10 +7,8 @@
 
 namespace Friendica\Module\Api\Mastodon\Accounts;
 
-use Friendica\Core\System;
 use Friendica\DI;
 use Friendica\Model\Contact;
-use Friendica\Model\User;
 use Friendica\Module\BaseApi;
 
 /**
@@ -29,15 +27,6 @@ class Block extends BaseApi
 
 		Contact\User::setBlocked($this->parameters['id'], $uid, true);
 
-		$ucid = Contact::getUserContactId($this->parameters['id'], $uid);
-		if ($ucid) {
-			$contact = Contact::getById($ucid);
-			if (!empty($contact)) {
-				// Mastodon-expected behavior: relationship is severed on block
-				Contact::terminateFriendship($contact);
-			}
-		}
-
 		$this->jsonExit(DI::mstdnRelationship()->createFromContactId($this->parameters['id'], $uid)->toArray());
 	}
 }
diff --git a/src/Module/Api/Mastodon/Statuses/Context.php b/src/Module/Api/Mastodon/Statuses/Context.php
index ad1539bd1a..2d17eed232 100644
--- a/src/Module/Api/Mastodon/Statuses/Context.php
+++ b/src/Module/Api/Mastodon/Statuses/Context.php
@@ -66,7 +66,7 @@ class Context extends BaseApi
 			if (!empty($uid) && !$request['show_all']) {
 				$condition = DBA::mergeConditions(
 					$condition,
-					["NOT `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND (`blocked` OR `ignored`))", $uid]
+					["NOT `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND (`blocked` OR `ignored` OR `is-blocked`))", $uid]
 				);
 			}
 
diff --git a/src/Module/Api/Mastodon/Timelines/Direct.php b/src/Module/Api/Mastodon/Timelines/Direct.php
index ee5e6b4406..f91aaa0c1c 100644
--- a/src/Module/Api/Mastodon/Timelines/Direct.php
+++ b/src/Module/Api/Mastodon/Timelines/Direct.php
@@ -55,7 +55,7 @@ class Direct extends BaseApi
 		if (!empty($uid)) {
 			$condition = DBA::mergeConditions(
 				$condition,
-				["NOT `parent-author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND (`blocked` OR `ignored`) AND `cid` = `parent-author-id`)", $uid]
+				["NOT `parent-author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND (`blocked` OR `ignored` OR `is-blocked`) AND `cid` = `parent-author-id`)", $uid]
 			);
 		}
 
diff --git a/src/Module/Api/Mastodon/Timelines/Home.php b/src/Module/Api/Mastodon/Timelines/Home.php
index 5d72b38ca9..5272ce0b9a 100644
--- a/src/Module/Api/Mastodon/Timelines/Home.php
+++ b/src/Module/Api/Mastodon/Timelines/Home.php
@@ -66,7 +66,7 @@ class Home extends BaseApi
 			$condition = DBA::mergeConditions($condition, ['gravity' => Item::GRAVITY_PARENT]);
 		}
 
-		$condition = DBA::mergeConditions($condition, ["NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `cid` IN (`parent-owner-id`, `parent-author-id`) AND (`blocked` OR `ignored` OR `channel-only`))", $uid]);
+		$condition = DBA::mergeConditions($condition, ["NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `cid` IN (`parent-owner-id`, `parent-author-id`) AND (`blocked` OR `ignored` OR `is-blocked` OR `channel-only`))", $uid]);
 
 		$items = Post::selectTimelineForUser($uid, ['uri-id'], $condition, $params);
 
diff --git a/src/Module/Api/Mastodon/Timelines/Tag.php b/src/Module/Api/Mastodon/Timelines/Tag.php
index 3cd3fc2dcd..bfe54db0df 100644
--- a/src/Module/Api/Mastodon/Timelines/Tag.php
+++ b/src/Module/Api/Mastodon/Timelines/Tag.php
@@ -93,7 +93,7 @@ class Tag extends BaseApi
 		if (!empty($uid)) {
 			$condition = DBA::mergeConditions(
 				$condition,
-				["NOT `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND (`blocked` OR `ignored`) AND `cid` = `author-id`)", $uid]
+				["NOT `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND (`blocked` OR `ignored` OR `is-blocked`) AND `cid` = `author-id`)", $uid]
 			);
 		}
 
diff --git a/src/Module/Contact/Profile.php b/src/Module/Contact/Profile.php
index 71369c6de6..986f19bcb1 100644
--- a/src/Module/Contact/Profile.php
+++ b/src/Module/Contact/Profile.php
@@ -356,6 +356,11 @@ class Profile extends BaseModule
 
 		$contact_actions = $this->getContactActions($contact, $localRelationship);
 
+		if (Contact\User::isIsBlocked($contact['id'], $this->session->getLocalUserId())) {
+			$relation_text = $this->t('%s has blocked you', $contact['name'] ?: $contact['nick']);
+			unset($contact_actions['follow']);
+		}
+
 		if ($localRelationship->rel !== Contact::NOTHING) {
 			$lbl_info1              = $this->t('Contact Information / Notes');
 			$contact_settings_label = $this->t('Contact Settings');
diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php
index 0359738379..c0f2a2c383 100644
--- a/src/Protocol/ActivityPub/Transmitter.php
+++ b/src/Protocol/ActivityPub/Transmitter.php
@@ -2103,17 +2103,18 @@ class Transmitter
 	 * Creates an activity id for a given contact id
 	 *
 	 * @param integer $cid Contact ID of target
+	 * @param integer $uid Optional user id. if empty, the contact uid is used.
 	 *
 	 * @return bool|string activity id
 	 */
-	public static function activityIDFromContact(int $cid)
+	public static function activityIDFromContact(int $cid, int $uid = 0)
 	{
 		$contact = DBA::selectFirst('contact', ['uid', 'id', 'created'], ['id' => $cid]);
 		if (!DBA::isResult($contact)) {
 			return false;
 		}
 
-		$hash = hash('ripemd128', $contact['uid'] . '-' . $contact['id'] . '-' . $contact['created']);
+		$hash = hash('ripemd128', $uid ?: $contact['uid'] . '-' . $contact['id'] . '-' . $contact['created']);
 		$uuid = substr($hash, 0, 8) . '-' . substr($hash, 8, 4) . '-' . substr($hash, 12, 4) . '-' . substr($hash, 16, 4) . '-' . substr($hash, 20, 12);
 		return DI::baseUrl() . '/activity/' . $uuid;
 	}
@@ -2477,6 +2478,53 @@ class Transmitter
 		return HTTPSignature::transmit($signed, $profile['inbox'], $owner);
 	}
 
+	/**
+	 * Transmits a message that we don't want to block this contact anymore
+	 *
+	 * @param string  $target Target profile
+	 * @param integer $cid    Contact id
+	 * @param array   $owner  Sender owner-view record
+	 * @return bool success
+	 * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+	 * @throws \ImagickException
+	 * @throws \Exception
+	 */
+	public static function sendContactUnblock(string $target, int $cid, array $owner): bool
+	{
+		$profile = APContact::getByURL($target);
+		if (empty($profile['inbox'])) {
+			Logger::warning('No inbox found for target', ['target' => $target, 'profile' => $profile]);
+			return false;
+		}
+
+		$object_id = self::activityIDFromContact($cid, $owner['uid']);
+		if (empty($object_id)) {
+			return false;
+		}
+
+		$objectId = DI::baseUrl() . '/activity/' . System::createGUID();
+
+		$data = [
+			'@context' => ActivityPub::CONTEXT,
+			'id' => $objectId,
+			'type' => 'Undo',
+			'actor' => $owner['url'],
+			'object' => [
+				'id' => $object_id,
+				'type' => 'Block',
+				'actor' => $owner['url'],
+				'object' => $profile['url']
+			],
+			'instrument' => self::getService(),
+			'to' => [$profile['url']],
+		];
+
+		Logger::info('Sending undo to ' . $target . ' for user ' . $owner['uid'] . ' with id ' . $objectId);
+
+		$signed = LDSignature::sign($data, $owner);
+		return HTTPSignature::transmit($signed, $profile['inbox'], $owner);
+	}
+
 	/**
 	 * Prepends mentions (@) to $body variable
 	 *
diff --git a/src/Worker/Contact/Block.php b/src/Worker/Contact/Block.php
new file mode 100644
index 0000000000..9c1c2cb43c
--- /dev/null
+++ b/src/Worker/Contact/Block.php
@@ -0,0 +1,38 @@
+<?php
+
+// Copyright (C) 2010-2024, the Friendica project
+// SPDX-FileCopyrightText: 2010-2024 the Friendica project
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+namespace Friendica\Worker\Contact;
+
+use Friendica\Core\Protocol;
+use Friendica\Core\Worker;
+use Friendica\Model\Contact;
+
+class Block
+{
+	const WORKER_DEFER_LIMIT = 5;
+
+	/**
+	 * Issue asynchronous block message to remote servers.
+	 *
+	 * @param int $cid Target public contact (uid = 0) id
+	 * @param int $uid Source local user id
+	 * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+	 * @throws \ImagickException
+	 */
+	public static function execute(int $cid, int $uid)
+	{
+		$contact = Contact::getById($cid);
+		if (empty($contact)) {
+			return;
+		}
+
+		$result = Protocol::block($contact, $uid);
+		if ($result === false) {
+			Worker::defer(self::WORKER_DEFER_LIMIT);
+		}
+	}
+}
diff --git a/src/Worker/Contact/Unblock.php b/src/Worker/Contact/Unblock.php
new file mode 100644
index 0000000000..a79b6ad7aa
--- /dev/null
+++ b/src/Worker/Contact/Unblock.php
@@ -0,0 +1,38 @@
+<?php
+
+// Copyright (C) 2010-2024, the Friendica project
+// SPDX-FileCopyrightText: 2010-2024 the Friendica project
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+namespace Friendica\Worker\Contact;
+
+use Friendica\Core\Protocol;
+use Friendica\Core\Worker;
+use Friendica\Model\Contact;
+
+class Unblock
+{
+	const WORKER_DEFER_LIMIT = 5;
+
+	/**
+	 * Issue asynchronous unblock message to remote servers.
+	 *
+	 * @param int $cid Target public contact (uid = 0) id
+	 * @param int $uid Source local user id
+	 * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+	 * @throws \ImagickException
+	 */
+	public static function execute(int $cid, int $uid)
+	{
+		$contact = Contact::getById($cid);
+		if (empty($contact)) {
+			return;
+		}
+
+		$result = Protocol::unblock($contact, $uid);
+		if ($result === false) {
+			Worker::defer(self::WORKER_DEFER_LIMIT);
+		}
+	}
+}
diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php
index 5956b5458c..27d7f030c2 100644
--- a/static/dbstructure.config.php
+++ b/static/dbstructure.config.php
@@ -44,7 +44,7 @@ use Friendica\Database\DBA;
 
 // This file is required several times during the test in DbaDefinition which justifies this condition
 if (!defined('DB_UPDATE_VERSION')) {
-	define('DB_UPDATE_VERSION', 1574);
+	define('DB_UPDATE_VERSION', 1575);
 }
 
 return [
diff --git a/static/dbview.config.php b/static/dbview.config.php
index 6a944d7188..2208f1c565 100644
--- a/static/dbview.config.php
+++ b/static/dbview.config.php
@@ -115,7 +115,7 @@ return [
 			AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`)
 			AND (`post-thread-user`.`hidden` IS NULL OR NOT `post-thread-user`.`hidden`)
 			AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked`
-			AND NOT EXISTS(SELECT `cid`  FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored`))
+			AND NOT EXISTS(SELECT `cid`  FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored` OR `is-blocked`))
 			AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`)"
 	],
 	"post-timeline-view" => [
@@ -235,7 +235,7 @@ return [
 			AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`)
 			AND (`post-thread-user`.`hidden` IS NULL OR NOT `post-thread-user`.`hidden`)
 			AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked`
-			AND NOT EXISTS(SELECT `cid`  FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored`))
+			AND NOT EXISTS(SELECT `cid`  FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored` OR `is-blocked`))
 			AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`)"
 	],
 	"post-origin-view" => [
@@ -1393,7 +1393,7 @@ return [
 			AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`)
 			AND (`post-thread-user`.`hidden` IS NULL OR NOT `post-thread-user`.`hidden`)
 			AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked`
-			AND NOT EXISTS(SELECT `cid`  FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`post-thread-user`.`author-id`, `post-thread-user`.`owner-id`, `post-thread-user`.`causer-id`) AND (`blocked` OR `ignored` OR `channel-only`))
+			AND NOT EXISTS(SELECT `cid`  FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`post-thread-user`.`author-id`, `post-thread-user`.`owner-id`, `post-thread-user`.`causer-id`) AND (`blocked` OR `ignored` OR `is-blocked` OR `channel-only`))
 			AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`)"
 	],
 	"network-thread-circle-view" => [
@@ -1419,7 +1419,7 @@ return [
 			AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`)
 			AND (`post-thread-user`.`hidden` IS NULL OR NOT `post-thread-user`.`hidden`)
 			AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked`
-			AND NOT EXISTS(SELECT `cid`  FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`post-thread-user`.`author-id`, `post-thread-user`.`owner-id`, `post-thread-user`.`causer-id`) AND (`blocked` OR `ignored`))
+			AND NOT EXISTS(SELECT `cid`  FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`post-thread-user`.`author-id`, `post-thread-user`.`owner-id`, `post-thread-user`.`causer-id`) AND (`blocked` OR `ignored` OR `is-blocked`))
 			AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`)"
 	],
 	"owner-view" => [
diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po
index 8ecb08c432..fd086af7ba 100644
--- a/view/lang/C/messages.po
+++ b/view/lang/C/messages.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: 2024.09-rc\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-10-18 19:06+0000\n"
+"POT-Creation-Date: 2024-10-20 08:32+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -291,7 +291,7 @@ msgstr ""
 #: mod/photos.php:778 mod/photos.php:1055 mod/photos.php:1096
 #: mod/photos.php:1152 mod/photos.php:1232
 #: src/Module/Calendar/Event/Form.php:236 src/Module/Contact/Advanced.php:118
-#: src/Module/Contact/Profile.php:371
+#: src/Module/Contact/Profile.php:376
 #: src/Module/Debug/ActivityPubConversion.php:132
 #: src/Module/Debug/Babel.php:307 src/Module/Debug/Localtime.php:50
 #: src/Module/Debug/Probe.php:40 src/Module/Debug/WebFinger.php:37
@@ -1365,7 +1365,7 @@ msgstr ""
 msgid "Public post"
 msgstr ""
 
-#: src/Content/Conversation.php:410 src/Content/Widget/VCard.php:117
+#: src/Content/Conversation.php:410 src/Content/Widget/VCard.php:122
 #: src/Model/Profile.php:462 src/Module/Admin/Logs/View.php:80
 #: src/Module/Post/Edit.php:167
 msgid "Message"
@@ -1881,7 +1881,7 @@ msgid "Send PM"
 msgstr ""
 
 #: src/Content/Item.php:421 src/Module/Contact.php:449
-#: src/Module/Contact/Profile.php:519
+#: src/Module/Contact/Profile.php:524
 #: src/Module/Moderation/Blocklist/Contact.php:102
 #: src/Module/Moderation/Users/Active.php:123
 #: src/Module/Moderation/Users/Index.php:138
@@ -1889,7 +1889,7 @@ msgid "Block"
 msgstr ""
 
 #: src/Content/Item.php:422 src/Module/Contact.php:450
-#: src/Module/Contact/Profile.php:527
+#: src/Module/Contact/Profile.php:532
 #: src/Module/Notifications/Introductions.php:126
 #: src/Module/Notifications/Introductions.php:198
 #: src/Module/Notifications/Notification.php:75
@@ -1897,7 +1897,7 @@ msgid "Ignore"
 msgstr ""
 
 #: src/Content/Item.php:423 src/Module/Contact.php:451
-#: src/Module/Contact/Profile.php:535
+#: src/Module/Contact/Profile.php:540
 msgid "Collapse"
 msgstr ""
 
@@ -1969,7 +1969,7 @@ msgstr ""
 
 #: src/Content/Nav.php:216 src/Module/BaseProfile.php:35
 #: src/Module/BaseSettings.php:84 src/Module/Contact.php:485
-#: src/Module/Contact/Profile.php:426 src/Module/Profile/Profile.php:256
+#: src/Module/Contact/Profile.php:431 src/Module/Profile/Profile.php:256
 #: src/Module/Welcome.php:43 view/theme/frio/theme.php:221
 msgid "Profile"
 msgstr ""
@@ -2278,8 +2278,8 @@ msgstr ""
 msgid "The end"
 msgstr ""
 
-#: src/Content/Text/HTML.php:847 src/Content/Widget/VCard.php:113
-#: src/Model/Profile.php:456 src/Module/Contact/Profile.php:479
+#: src/Content/Text/HTML.php:847 src/Content/Widget/VCard.php:118
+#: src/Model/Profile.php:456 src/Module/Contact/Profile.php:484
 msgid "Follow"
 msgstr ""
 
@@ -2397,7 +2397,7 @@ msgstr ""
 msgid "Organisations"
 msgstr ""
 
-#: src/Content/Widget.php:515 src/Model/Contact.php:1747
+#: src/Content/Widget.php:515 src/Model/Contact.php:1755
 msgid "News"
 msgstr ""
 
@@ -2451,46 +2451,46 @@ msgstr[1] ""
 msgid "More Trending Tags"
 msgstr ""
 
-#: src/Content/Widget/VCard.php:91 src/Model/Contact.php:1212
+#: src/Content/Widget/VCard.php:96 src/Model/Contact.php:1212
 #: src/Model/Profile.php:441
 msgid "Post to group"
 msgstr ""
 
-#: src/Content/Widget/VCard.php:96 src/Model/Contact.php:1216
+#: src/Content/Widget/VCard.php:101 src/Model/Contact.php:1216
 #: src/Model/Profile.php:445 src/Module/Moderation/Item/Source.php:77
 msgid "Mention"
 msgstr ""
 
-#: src/Content/Widget/VCard.php:106 src/Model/Profile.php:360
-#: src/Module/Contact/Profile.php:415 src/Module/Profile/Profile.php:187
+#: src/Content/Widget/VCard.php:111 src/Model/Profile.php:360
+#: src/Module/Contact/Profile.php:420 src/Module/Profile/Profile.php:187
 msgid "XMPP:"
 msgstr ""
 
-#: src/Content/Widget/VCard.php:107 src/Model/Profile.php:361
-#: src/Module/Contact/Profile.php:417 src/Module/Profile/Profile.php:191
+#: src/Content/Widget/VCard.php:112 src/Model/Profile.php:361
+#: src/Module/Contact/Profile.php:422 src/Module/Profile/Profile.php:191
 msgid "Matrix:"
 msgstr ""
 
-#: src/Content/Widget/VCard.php:108 src/Model/Event.php:68
+#: src/Content/Widget/VCard.php:113 src/Model/Event.php:68
 #: src/Model/Event.php:95 src/Model/Event.php:457 src/Model/Event.php:946
-#: src/Model/Profile.php:355 src/Module/Contact/Profile.php:413
+#: src/Model/Profile.php:355 src/Module/Contact/Profile.php:418
 #: src/Module/Directory.php:134 src/Module/Notifications/Introductions.php:179
 #: src/Module/Profile/Profile.php:209
 msgid "Location:"
 msgstr ""
 
-#: src/Content/Widget/VCard.php:111 src/Model/Profile.php:469
+#: src/Content/Widget/VCard.php:116 src/Model/Profile.php:469
 #: src/Module/Notifications/Introductions.php:193
 msgid "Network:"
 msgstr ""
 
-#: src/Content/Widget/VCard.php:115 src/Model/Contact.php:1244
+#: src/Content/Widget/VCard.php:120 src/Model/Contact.php:1244
 #: src/Model/Contact.php:1256 src/Model/Profile.php:458
-#: src/Module/Contact/Profile.php:471
+#: src/Module/Contact/Profile.php:476
 msgid "Unfollow"
 msgstr ""
 
-#: src/Content/Widget/VCard.php:121 src/Model/Contact.php:1214
+#: src/Content/Widget/VCard.php:126 src/Model/Contact.php:1214
 #: src/Model/Profile.php:443
 msgid "View group"
 msgstr ""
@@ -3200,72 +3200,78 @@ msgstr ""
 msgid "Approve"
 msgstr ""
 
-#: src/Model/Contact.php:1743
-msgid "Organisation"
+#: src/Model/Contact.php:1599 src/Model/Contact.php:1671
+#: src/Module/Contact/Profile.php:360
+#, php-format
+msgid "%s has blocked you"
 msgstr ""
 
 #: src/Model/Contact.php:1751
+msgid "Organisation"
+msgstr ""
+
+#: src/Model/Contact.php:1759
 msgid "Group"
 msgstr ""
 
-#: src/Model/Contact.php:1755 src/Module/Moderation/BaseUsers.php:120
+#: src/Model/Contact.php:1763 src/Module/Moderation/BaseUsers.php:120
 msgid "Relay"
 msgstr ""
 
-#: src/Model/Contact.php:3070
+#: src/Model/Contact.php:3078
 msgid "Disallowed profile URL."
 msgstr ""
 
-#: src/Model/Contact.php:3075 src/Module/Friendica.php:86
+#: src/Model/Contact.php:3083 src/Module/Friendica.php:86
 msgid "Blocked domain"
 msgstr ""
 
-#: src/Model/Contact.php:3080
+#: src/Model/Contact.php:3088
 msgid "Connect URL missing."
 msgstr ""
 
-#: src/Model/Contact.php:3089
+#: src/Model/Contact.php:3097
 msgid "The contact could not be added. Please check the relevant network credentials in your Settings -> Social Networks page."
 msgstr ""
 
-#: src/Model/Contact.php:3107
+#: src/Model/Contact.php:3115
 #, php-format
 msgid "Expected network %s does not match actual network %s"
 msgstr ""
 
-#: src/Model/Contact.php:3124
+#: src/Model/Contact.php:3132
 msgid "This seems to be a relay account. They can't be followed by users."
 msgstr ""
 
-#: src/Model/Contact.php:3131
+#: src/Model/Contact.php:3139
 msgid "The profile address specified does not provide adequate information."
 msgstr ""
 
-#: src/Model/Contact.php:3133
+#: src/Model/Contact.php:3141
 msgid "No compatible communication protocols or feeds were discovered."
 msgstr ""
 
-#: src/Model/Contact.php:3136
+#: src/Model/Contact.php:3144
 msgid "An author or name was not found."
 msgstr ""
 
-#: src/Model/Contact.php:3139
+#: src/Model/Contact.php:3147
 msgid "No browser URL could be matched to this address."
 msgstr ""
 
-#: src/Model/Contact.php:3142
+#: src/Model/Contact.php:3150
 msgid "Unable to match @-style Identity Address with a known protocol or email contact."
 msgstr ""
 
-#: src/Model/Contact.php:3143
+#: src/Model/Contact.php:3151
 msgid "Use mailto: in front of address to force email check."
 msgstr ""
 
-#: src/Model/Contact.php:3149
+#: src/Model/Contact.php:3157
 msgid "Limited profile. This person will be unable to receive direct/personal notifications from you."
 msgstr ""
 
-#: src/Model/Contact.php:3208
+#: src/Model/Contact.php:3216
 msgid "Unable to retrieve contact information."
 msgstr ""
 
@@ -3481,7 +3487,7 @@ msgstr ""
 msgid "Homepage:"
 msgstr ""
 
-#: src/Model/Profile.php:359 src/Module/Contact/Profile.php:419
+#: src/Model/Profile.php:359 src/Module/Contact/Profile.php:424
 #: src/Module/Notifications/Introductions.php:181
 msgid "About:"
 msgstr ""
@@ -6086,18 +6092,18 @@ msgstr ""
 msgid "Update"
 msgstr ""
 
-#: src/Module/Contact.php:449 src/Module/Contact/Profile.php:519
+#: src/Module/Contact.php:449 src/Module/Contact/Profile.php:524
 #: src/Module/Moderation/Blocklist/Contact.php:103
 #: src/Module/Moderation/Users/Blocked.php:124
 #: src/Module/Moderation/Users/Index.php:140
 msgid "Unblock"
 msgstr ""
 
-#: src/Module/Contact.php:450 src/Module/Contact/Profile.php:527
+#: src/Module/Contact.php:450 src/Module/Contact/Profile.php:532
 msgid "Unignore"
 msgstr ""
 
-#: src/Module/Contact.php:451 src/Module/Contact/Profile.php:535
+#: src/Module/Contact.php:451 src/Module/Contact/Profile.php:540
 msgid "Uncollapse"
 msgstr ""
 
@@ -6149,7 +6155,7 @@ msgstr ""
 msgid "Pending incoming contact request"
 msgstr ""
 
-#: src/Module/Contact.php:608 src/Module/Contact/Profile.php:378
+#: src/Module/Contact.php:608 src/Module/Contact/Profile.php:383
 #, php-format
 msgid "Visit %s's profile [%s]"
 msgstr ""
@@ -6280,7 +6286,7 @@ msgstr ""
 msgid "Your Identity Address:"
 msgstr ""
 
-#: src/Module/Contact/Follow.php:155 src/Module/Contact/Profile.php:409
+#: src/Module/Contact/Follow.php:155 src/Module/Contact/Profile.php:414
 #: src/Module/Contact/Unfollow.php:115
 #: src/Module/Moderation/Blocklist/Contact.php:117
 #: src/Module/Moderation/Reports.php:109
@@ -6289,7 +6295,7 @@ msgstr ""
 msgid "Profile URL"
 msgstr ""
 
-#: src/Module/Contact/Follow.php:156 src/Module/Contact/Profile.php:421
+#: src/Module/Contact/Follow.php:156 src/Module/Contact/Profile.php:426
 #: src/Module/Notifications/Introductions.php:183
 #: src/Module/Profile/Profile.php:222
 msgid "Tags:"
@@ -6391,7 +6397,7 @@ msgstr ""
 msgid "(Update was successful)"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:296 src/Module/Contact/Profile.php:490
+#: src/Module/Contact/Profile.php:296 src/Module/Contact/Profile.php:495
 msgid "Suggest friends"
 msgstr ""
 
@@ -6438,191 +6444,191 @@ msgstr ""
 msgid "Native reshare"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:360
+#: src/Module/Contact/Profile.php:365
 msgid "Contact Information / Notes"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:361
+#: src/Module/Contact/Profile.php:366
 msgid "Contact Settings"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:369
+#: src/Module/Contact/Profile.php:374
 msgid "Contact"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:373
+#: src/Module/Contact/Profile.php:378
 msgid "Their personal note"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:375
+#: src/Module/Contact/Profile.php:380
 msgid "Edit contact notes"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:379
+#: src/Module/Contact/Profile.php:384
 msgid "Block/Unblock contact"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:380
+#: src/Module/Contact/Profile.php:385
 #: src/Module/Moderation/Report/Create.php:279
 msgid "Ignore contact"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:381
+#: src/Module/Contact/Profile.php:386
 msgid "View conversations"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:386
+#: src/Module/Contact/Profile.php:391
 msgid "Last update:"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:388
+#: src/Module/Contact/Profile.php:393
 msgid "Update public posts"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:390 src/Module/Contact/Profile.php:500
+#: src/Module/Contact/Profile.php:395 src/Module/Contact/Profile.php:505
 msgid "Update now"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:392
+#: src/Module/Contact/Profile.php:397
 msgid "Awaiting connection acknowledge"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:393
+#: src/Module/Contact/Profile.php:398
 msgid "Currently blocked"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:394
+#: src/Module/Contact/Profile.php:399
 msgid "Currently ignored"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:395
+#: src/Module/Contact/Profile.php:400
 msgid "Currently collapsed"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:396
+#: src/Module/Contact/Profile.php:401
 msgid "Currently archived"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:399
+#: src/Module/Contact/Profile.php:404
 msgid "Manage remote servers"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:401
+#: src/Module/Contact/Profile.php:406
 #: src/Module/Notifications/Introductions.php:184
 msgid "Hide this contact from others"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:401
+#: src/Module/Contact/Profile.php:406
 msgid "Replies/likes to your public posts <strong>may</strong> still be visible"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:402
+#: src/Module/Contact/Profile.php:407
 msgid "Notification for new posts"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:402
+#: src/Module/Contact/Profile.php:407
 msgid "Send a notification of every new post of this contact"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:404
+#: src/Module/Contact/Profile.php:409
 msgid "Keyword Deny List"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:404
+#: src/Module/Contact/Profile.php:409
 msgid "Comma separated list of keywords that should not be converted to hashtags, when \"Fetch information and keywords\" is selected"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:422
+#: src/Module/Contact/Profile.php:427
 #: src/Module/Settings/TwoFactor/Index.php:146
 msgid "Actions"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:424
+#: src/Module/Contact/Profile.php:429
 #: src/Module/Settings/TwoFactor/Index.php:126 view/theme/frio/theme.php:220
 msgid "Status"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:430
+#: src/Module/Contact/Profile.php:435
 msgid "Mirror postings from this contact"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:432
+#: src/Module/Contact/Profile.php:437
 msgid "Mark this contact as remote_self, this will cause friendica to repost new entries from this contact."
 msgstr ""
 
-#: src/Module/Contact/Profile.php:435
+#: src/Module/Contact/Profile.php:440
 msgid "Channel Settings"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:436
+#: src/Module/Contact/Profile.php:441
 msgid "Frequency of this contact in relevant channels"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:437
+#: src/Module/Contact/Profile.php:442
 msgid "Depending on the type of the channel not all posts from this contact are displayed. By default, posts need to have a minimum amount of interactions (comments, likes) to show in your channels. On the other hand there can be contacts who flood the channel, so you might want to see only some of their posts. Or you don't want to see their content at all, but you don't want to block or hide the contact completely."
 msgstr ""
 
-#: src/Module/Contact/Profile.php:438
+#: src/Module/Contact/Profile.php:443
 msgid "Default frequency"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:438
+#: src/Module/Contact/Profile.php:443
 msgid "Posts by this contact are displayed in the \"for you\" channel if you interact often with this contact or if a post reached some level of interaction."
 msgstr ""
 
-#: src/Module/Contact/Profile.php:439
+#: src/Module/Contact/Profile.php:444
 msgid "Display all posts of this contact"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:439
+#: src/Module/Contact/Profile.php:444
 msgid "All posts from this contact will appear on the \"for you\" channel"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:440
+#: src/Module/Contact/Profile.php:445
 msgid "Display only few posts"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:440
+#: src/Module/Contact/Profile.php:445
 msgid "When a contact creates a lot of posts in a short period, this setting reduces the number of displayed posts in every channel."
 msgstr ""
 
-#: src/Module/Contact/Profile.php:441
+#: src/Module/Contact/Profile.php:446
 msgid "Never display posts"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:441
+#: src/Module/Contact/Profile.php:446
 msgid "Posts from this contact will never be displayed in any channel"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:442
+#: src/Module/Contact/Profile.php:447
 msgid "Channel Only"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:442
+#: src/Module/Contact/Profile.php:447
 msgid "If enabled, posts from this contact will only appear in channels and network streams in circles, but not in the general network stream."
 msgstr ""
 
-#: src/Module/Contact/Profile.php:510
+#: src/Module/Contact/Profile.php:515
 msgid "Refetch contact data"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:521
+#: src/Module/Contact/Profile.php:526
 msgid "Toggle Blocked status"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:529
+#: src/Module/Contact/Profile.php:534
 msgid "Toggle Ignored status"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:537
+#: src/Module/Contact/Profile.php:542
 msgid "Toggle Collapsed status"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:544 src/Module/Contact/Revoke.php:89
+#: src/Module/Contact/Profile.php:549 src/Module/Contact/Revoke.php:89
 msgid "Revoke Follow"
 msgstr ""
 
-#: src/Module/Contact/Profile.php:546
+#: src/Module/Contact/Profile.php:551
 msgid "Revoke the follow from this contact"
 msgstr ""