mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 723217: Fix click-to-play support for plugins on Android. r=snorp
This commit is contained in:
parent
b351fc30f8
commit
7f8b14d760
@ -484,16 +484,18 @@ IsSupportedImage(const nsCString& aMimeType)
|
|||||||
return NS_SUCCEEDED(rv) && supported;
|
return NS_SUCCEEDED(rv) && supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
nsresult nsObjectLoadingContent::IsPluginEnabledForType(const nsCString& aMIMEType)
|
||||||
IsSupportedPlugin(const nsCString& aMIMEType, bool aShouldPlay)
|
|
||||||
{
|
{
|
||||||
|
if (!mShouldPlay) {
|
||||||
|
return NS_ERROR_PLUGIN_CLICKTOPLAY;
|
||||||
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
|
nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
|
||||||
nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
|
nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
|
||||||
if (!pluginHost) {
|
if (!pluginHost) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
nsresult rv = pluginHost->IsPluginEnabledForType(aMIMEType.get(), aShouldPlay);
|
return pluginHost->IsPluginEnabledForType(aMIMEType.get());
|
||||||
return NS_SUCCEEDED(rv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -517,9 +519,12 @@ GetExtensionFromURI(nsIURI* uri, nsCString& ext)
|
|||||||
* Checks whether a plugin exists and is enabled for the extension
|
* Checks whether a plugin exists and is enabled for the extension
|
||||||
* in the given URI. The MIME type is returned in the mimeType out parameter.
|
* in the given URI. The MIME type is returned in the mimeType out parameter.
|
||||||
*/
|
*/
|
||||||
static bool
|
bool nsObjectLoadingContent::IsPluginEnabledByExtension(nsIURI* uri, nsCString& mimeType)
|
||||||
IsPluginEnabledByExtension(nsIURI* uri, nsCString& mimeType, bool aShouldPlay)
|
|
||||||
{
|
{
|
||||||
|
if (!mShouldPlay) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
nsCAutoString ext;
|
nsCAutoString ext;
|
||||||
GetExtensionFromURI(uri, ext);
|
GetExtensionFromURI(uri, ext);
|
||||||
|
|
||||||
@ -534,8 +539,7 @@ IsPluginEnabledByExtension(nsIURI* uri, nsCString& mimeType, bool aShouldPlay)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char* typeFromExt;
|
const char* typeFromExt;
|
||||||
if (NS_SUCCEEDED(pluginHost->IsPluginEnabledForExtension(ext.get(), typeFromExt,
|
if (NS_SUCCEEDED(pluginHost->IsPluginEnabledForExtension(ext.get(), typeFromExt))) {
|
||||||
aShouldPlay))) {
|
|
||||||
mimeType = typeFromExt;
|
mimeType = typeFromExt;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -568,6 +572,10 @@ nsObjectLoadingContent::~nsObjectLoadingContent()
|
|||||||
nsresult
|
nsresult
|
||||||
nsObjectLoadingContent::InstantiatePluginInstance(const char* aMimeType, nsIURI* aURI)
|
nsObjectLoadingContent::InstantiatePluginInstance(const char* aMimeType, nsIURI* aURI)
|
||||||
{
|
{
|
||||||
|
if (!mShouldPlay) {
|
||||||
|
return NS_ERROR_PLUGIN_CLICKTOPLAY;
|
||||||
|
}
|
||||||
|
|
||||||
// Don't do anything if we already have an active instance.
|
// Don't do anything if we already have an active instance.
|
||||||
if (mInstanceOwner) {
|
if (mInstanceOwner) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -586,11 +594,6 @@ nsObjectLoadingContent::InstantiatePluginInstance(const char* aMimeType, nsIURI*
|
|||||||
nsCOMPtr<nsIObjectLoadingContent> kungFuDeathGrip = this;
|
nsCOMPtr<nsIObjectLoadingContent> kungFuDeathGrip = this;
|
||||||
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
||||||
|
|
||||||
nsCString typeToUse(aMimeType);
|
|
||||||
if (typeToUse.IsEmpty() && aURI) {
|
|
||||||
IsPluginEnabledByExtension(aURI, typeToUse, mShouldPlay);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> baseURI;
|
nsCOMPtr<nsIURI> baseURI;
|
||||||
if (!aURI) {
|
if (!aURI) {
|
||||||
// We need some URI. If we have nothing else, use the base URI.
|
// We need some URI. If we have nothing else, use the base URI.
|
||||||
@ -730,10 +733,10 @@ nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest,
|
|||||||
if ((channelType.EqualsASCII(APPLICATION_OCTET_STREAM) &&
|
if ((channelType.EqualsASCII(APPLICATION_OCTET_STREAM) &&
|
||||||
!mContentType.IsEmpty() &&
|
!mContentType.IsEmpty() &&
|
||||||
GetTypeOfContent(mContentType) != eType_Document) ||
|
GetTypeOfContent(mContentType) != eType_Document) ||
|
||||||
// Need to check IsSupportedPlugin() in addition to GetTypeOfContent()
|
// Need to check IsPluginEnabledForType() in addition to GetTypeOfContent()
|
||||||
// because otherwise the default plug-in's catch-all behavior would
|
// because otherwise the default plug-in's catch-all behavior would
|
||||||
// confuse things.
|
// confuse things.
|
||||||
(IsSupportedPlugin(mContentType, mShouldPlay) &&
|
(NS_SUCCEEDED(IsPluginEnabledForType(mContentType)) &&
|
||||||
GetTypeOfContent(mContentType) == eType_Plugin)) {
|
GetTypeOfContent(mContentType) == eType_Plugin)) {
|
||||||
// Set the type we'll use for dispatch on the channel. Otherwise we could
|
// Set the type we'll use for dispatch on the channel. Otherwise we could
|
||||||
// end up trying to dispatch to a nsFrameLoader, which will complain that
|
// end up trying to dispatch to a nsFrameLoader, which will complain that
|
||||||
@ -752,7 +755,7 @@ nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest,
|
|||||||
|
|
||||||
if (mContentType.EqualsASCII(APPLICATION_OCTET_STREAM)) {
|
if (mContentType.EqualsASCII(APPLICATION_OCTET_STREAM)) {
|
||||||
nsCAutoString extType;
|
nsCAutoString extType;
|
||||||
if (IsPluginEnabledByExtension(uri, extType, mShouldPlay)) {
|
if (IsPluginEnabledByExtension(uri, extType)) {
|
||||||
mContentType = extType;
|
mContentType = extType;
|
||||||
chan->SetContentType(extType);
|
chan->SetContentType(extType);
|
||||||
}
|
}
|
||||||
@ -1297,8 +1300,8 @@ nsObjectLoadingContent::LoadObject(nsIURI* aURI,
|
|||||||
|
|
||||||
nsCAutoString overrideType;
|
nsCAutoString overrideType;
|
||||||
if ((caps & eOverrideServerType) &&
|
if ((caps & eOverrideServerType) &&
|
||||||
((!aTypeHint.IsEmpty() && IsSupportedPlugin(aTypeHint, mShouldPlay)) ||
|
((!aTypeHint.IsEmpty() && NS_SUCCEEDED(IsPluginEnabledForType(aTypeHint))) ||
|
||||||
(aURI && IsPluginEnabledByExtension(aURI, overrideType, mShouldPlay)))) {
|
(aURI && IsPluginEnabledByExtension(aURI, overrideType)))) {
|
||||||
ObjectType newType;
|
ObjectType newType;
|
||||||
if (overrideType.IsEmpty()) {
|
if (overrideType.IsEmpty()) {
|
||||||
newType = GetTypeOfContent(aTypeHint);
|
newType = GetTypeOfContent(aTypeHint);
|
||||||
@ -1434,7 +1437,7 @@ nsObjectLoadingContent::LoadObject(nsIURI* aURI,
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsSupportedPlugin(aTypeHint, mShouldPlay)) {
|
if (NS_SUCCEEDED(IsPluginEnabledForType(aTypeHint))) {
|
||||||
mType = eType_Plugin;
|
mType = eType_Plugin;
|
||||||
} else {
|
} else {
|
||||||
rv = NS_ERROR_NOT_AVAILABLE;
|
rv = NS_ERROR_NOT_AVAILABLE;
|
||||||
@ -1744,7 +1747,7 @@ nsObjectLoadingContent::GetTypeOfContent(const nsCString& aMIMEType)
|
|||||||
return eType_Document;
|
return eType_Document;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((caps & eSupportPlugins) && IsSupportedPlugin(aMIMEType, mShouldPlay)) {
|
if ((caps & eSupportPlugins) && NS_SUCCEEDED(IsPluginEnabledForType(aMIMEType))) {
|
||||||
return eType_Plugin;
|
return eType_Plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1755,16 +1758,10 @@ nsresult
|
|||||||
nsObjectLoadingContent::TypeForClassID(const nsAString& aClassID,
|
nsObjectLoadingContent::TypeForClassID(const nsAString& aClassID,
|
||||||
nsACString& aType)
|
nsACString& aType)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
|
|
||||||
nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
|
|
||||||
if (!pluginHost) {
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringBeginsWith(aClassID, NS_LITERAL_STRING("java:"))) {
|
if (StringBeginsWith(aClassID, NS_LITERAL_STRING("java:"))) {
|
||||||
// Supported if we have a java plugin
|
// Supported if we have a java plugin
|
||||||
aType.AssignLiteral("application/x-java-vm");
|
aType.AssignLiteral("application/x-java-vm");
|
||||||
nsresult rv = pluginHost->IsPluginEnabledForType("application/x-java-vm");
|
nsresult rv = IsPluginEnabledForType(NS_LITERAL_CSTRING("application/x-java-vm"));
|
||||||
return NS_SUCCEEDED(rv) ? NS_OK : NS_ERROR_NOT_AVAILABLE;
|
return NS_SUCCEEDED(rv) ? NS_OK : NS_ERROR_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1772,11 +1769,11 @@ nsObjectLoadingContent::TypeForClassID(const nsAString& aClassID,
|
|||||||
if (StringBeginsWith(aClassID, NS_LITERAL_STRING("clsid:"), nsCaseInsensitiveStringComparator())) {
|
if (StringBeginsWith(aClassID, NS_LITERAL_STRING("clsid:"), nsCaseInsensitiveStringComparator())) {
|
||||||
// Check if we have a plugin for that
|
// Check if we have a plugin for that
|
||||||
|
|
||||||
if (NS_SUCCEEDED(pluginHost->IsPluginEnabledForType("application/x-oleobject"))) {
|
if (NS_SUCCEEDED(IsPluginEnabledForType(NS_LITERAL_CSTRING("application/x-oleobject")))) {
|
||||||
aType.AssignLiteral("application/x-oleobject");
|
aType.AssignLiteral("application/x-oleobject");
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
if (NS_SUCCEEDED(pluginHost->IsPluginEnabledForType("application/oleobject"))) {
|
if (NS_SUCCEEDED(IsPluginEnabledForType(NS_LITERAL_CSTRING("application/oleobject")))) {
|
||||||
aType.AssignLiteral("application/oleobject");
|
aType.AssignLiteral("application/oleobject");
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -1832,7 +1829,7 @@ nsObjectLoadingContent::HandleBeingBlockedByContentPolicy(nsresult aStatus,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ PluginSupportState
|
PluginSupportState
|
||||||
nsObjectLoadingContent::GetPluginSupportState(nsIContent* aContent,
|
nsObjectLoadingContent::GetPluginSupportState(nsIContent* aContent,
|
||||||
const nsCString& aContentType)
|
const nsCString& aContentType)
|
||||||
{
|
{
|
||||||
@ -1866,16 +1863,10 @@ nsObjectLoadingContent::GetPluginSupportState(nsIContent* aContent,
|
|||||||
GetPluginDisabledState(aContentType);
|
GetPluginDisabledState(aContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ PluginSupportState
|
PluginSupportState
|
||||||
nsObjectLoadingContent::GetPluginDisabledState(const nsCString& aContentType)
|
nsObjectLoadingContent::GetPluginDisabledState(const nsCString& aContentType)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
|
nsresult rv = IsPluginEnabledForType(aContentType);
|
||||||
nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
|
|
||||||
if (!pluginHost) {
|
|
||||||
return ePluginUnsupported;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult rv = pluginHost->IsPluginEnabledForType(aContentType.get());
|
|
||||||
if (rv == NS_ERROR_PLUGIN_DISABLED)
|
if (rv == NS_ERROR_PLUGIN_DISABLED)
|
||||||
return ePluginDisabled;
|
return ePluginDisabled;
|
||||||
if (rv == NS_ERROR_PLUGIN_CLICKTOPLAY)
|
if (rv == NS_ERROR_PLUGIN_CLICKTOPLAY)
|
||||||
@ -2117,6 +2108,7 @@ nsObjectLoadingContent::PlayPlugin()
|
|||||||
if (!nsContentUtils::IsCallerChrome())
|
if (!nsContentUtils::IsCallerChrome())
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
|
mSrcStreamLoadInitiated = false;
|
||||||
mShouldPlay = true;
|
mShouldPlay = true;
|
||||||
return LoadObject(mURI, true, mContentType, true);
|
return LoadObject(mURI, true, mContentType, true);
|
||||||
}
|
}
|
||||||
|
@ -328,9 +328,7 @@ class nsObjectLoadingContent : public nsImageLoadingContent
|
|||||||
*
|
*
|
||||||
* This should only be called if the type of this content is eType_Null.
|
* This should only be called if the type of this content is eType_Null.
|
||||||
*/
|
*/
|
||||||
static PluginSupportState
|
PluginSupportState GetPluginSupportState(nsIContent* aContent, const nsCString& aContentType);
|
||||||
GetPluginSupportState(nsIContent* aContent,
|
|
||||||
const nsCString& aContentType);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the plugin for aContentType is disabled, return ePluginDisabled.
|
* If the plugin for aContentType is disabled, return ePluginDisabled.
|
||||||
@ -339,17 +337,17 @@ class nsObjectLoadingContent : public nsImageLoadingContent
|
|||||||
*
|
*
|
||||||
* This should only be called if the type of this content is eType_Null.
|
* This should only be called if the type of this content is eType_Null.
|
||||||
*/
|
*/
|
||||||
static PluginSupportState
|
PluginSupportState GetPluginDisabledState(const nsCString& aContentType);
|
||||||
GetPluginDisabledState(const nsCString& aContentType);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When there is no usable plugin available this will send UI events and
|
* When there is no usable plugin available this will send UI events and
|
||||||
* update the AutoFallback object appropriate to the reason for there being
|
* update the AutoFallback object appropriate to the reason for there being
|
||||||
* no plugin available.
|
* no plugin available.
|
||||||
*/
|
*/
|
||||||
static void
|
void UpdateFallbackState(nsIContent* aContent, AutoFallback& fallback, const nsCString& aTypeHint);
|
||||||
UpdateFallbackState(nsIContent* aContent, AutoFallback& fallback,
|
|
||||||
const nsCString& aTypeHint);
|
nsresult IsPluginEnabledForType(const nsCString& aMIMEType);
|
||||||
|
bool IsPluginEnabledByExtension(nsIURI* uri, nsCString& mimeType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The final listener to ship the data to (imagelib, uriloader, etc)
|
* The final listener to ship the data to (imagelib, uriloader, etc)
|
||||||
|
@ -1367,18 +1367,10 @@ nsPluginHost::TrySetUpPluginInstance(const char *aMimeType,
|
|||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsPluginHost::IsPluginEnabledForType(const char* aMimeType)
|
nsPluginHost::IsPluginEnabledForType(const char* aMimeType)
|
||||||
{
|
|
||||||
// If plugins.click_to_play is false, plugins should always play
|
|
||||||
return IsPluginEnabledForType(aMimeType,
|
|
||||||
!Preferences::GetBool("plugins.click_to_play", false));
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
nsPluginHost::IsPluginEnabledForType(const char* aMimeType, bool aShouldPlay)
|
|
||||||
{
|
{
|
||||||
nsPluginTag *plugin = FindPluginForType(aMimeType, true);
|
nsPluginTag *plugin = FindPluginForType(aMimeType, true);
|
||||||
if (plugin)
|
if (plugin)
|
||||||
return aShouldPlay ? NS_OK : NS_ERROR_PLUGIN_CLICKTOPLAY;
|
return NS_OK;
|
||||||
|
|
||||||
// Pass false as the second arg so we can return NS_ERROR_PLUGIN_DISABLED
|
// Pass false as the second arg so we can return NS_ERROR_PLUGIN_DISABLED
|
||||||
// for disabled plug-ins.
|
// for disabled plug-ins.
|
||||||
@ -1393,7 +1385,7 @@ nsPluginHost::IsPluginEnabledForType(const char* aMimeType, bool aShouldPlay)
|
|||||||
return NS_ERROR_PLUGIN_DISABLED;
|
return NS_ERROR_PLUGIN_DISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return aShouldPlay ? NS_OK : NS_ERROR_PLUGIN_CLICKTOPLAY;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check comma delimitered extensions
|
// check comma delimitered extensions
|
||||||
@ -1421,22 +1413,13 @@ static int CompareExtensions(const char *aExtensionList, const char *aExtension)
|
|||||||
return PL_strcasecmp(pExt, aExtension);
|
return PL_strcasecmp(pExt, aExtension);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
|
||||||
nsPluginHost::IsPluginEnabledForExtension(const char* aExtension, const char* &aMimeType)
|
|
||||||
{
|
|
||||||
// If plugins.click_to_play is false, plugins should always play
|
|
||||||
return IsPluginEnabledForExtension(aExtension, aMimeType,
|
|
||||||
!Preferences::GetBool("plugins.click_to_play", false));
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsPluginHost::IsPluginEnabledForExtension(const char* aExtension,
|
nsPluginHost::IsPluginEnabledForExtension(const char* aExtension,
|
||||||
const char* &aMimeType,
|
const char* &aMimeType)
|
||||||
bool aShouldPlay)
|
|
||||||
{
|
{
|
||||||
nsPluginTag *plugin = FindPluginEnabledForExtension(aExtension, aMimeType);
|
nsPluginTag *plugin = FindPluginEnabledForExtension(aExtension, aMimeType);
|
||||||
if (plugin)
|
if (plugin)
|
||||||
return aShouldPlay ? NS_OK : NS_ERROR_PLUGIN_CLICKTOPLAY;
|
return NS_OK;
|
||||||
|
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -120,11 +120,8 @@ public:
|
|||||||
nsIURI *aURL,
|
nsIURI *aURL,
|
||||||
nsIPluginInstanceOwner *aOwner);
|
nsIPluginInstanceOwner *aOwner);
|
||||||
nsresult IsPluginEnabledForType(const char* aMimeType);
|
nsresult IsPluginEnabledForType(const char* aMimeType);
|
||||||
nsresult IsPluginEnabledForType(const char* aMimeType,
|
|
||||||
bool aShouldPlay);
|
|
||||||
nsresult IsPluginEnabledForExtension(const char* aExtension, const char* &aMimeType);
|
nsresult IsPluginEnabledForExtension(const char* aExtension, const char* &aMimeType);
|
||||||
nsresult IsPluginEnabledForExtension(const char* aExtension, const char* &aMimeType,
|
|
||||||
bool aShouldPlay);
|
|
||||||
nsresult GetPluginCount(PRUint32* aPluginCount);
|
nsresult GetPluginCount(PRUint32* aPluginCount);
|
||||||
nsresult GetPlugins(PRUint32 aPluginCount, nsIDOMPlugin** aPluginArray);
|
nsresult GetPlugins(PRUint32 aPluginCount, nsIDOMPlugin** aPluginArray);
|
||||||
|
|
||||||
|
@ -310,7 +310,7 @@ nsContentDLF::CreateInstance(const char* aCommand,
|
|||||||
nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
|
nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
|
||||||
nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
|
nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
|
||||||
if(pluginHost &&
|
if(pluginHost &&
|
||||||
NS_SUCCEEDED(pluginHost->IsPluginEnabledForType(aContentType, true))) {
|
NS_SUCCEEDED(pluginHost->IsPluginEnabledForType(aContentType))) {
|
||||||
return CreateDocument(aCommand,
|
return CreateDocument(aCommand,
|
||||||
aChannel, aLoadGroup,
|
aChannel, aLoadGroup,
|
||||||
aContainer, kPluginDocumentCID,
|
aContainer, kPluginDocumentCID,
|
||||||
|
Loading…
Reference in New Issue
Block a user