Inherit wxURL from wxURI, providing assignment, copy construction, comparison, and less duplication of code. Change wxURI a bit to meet some of Vadim's reccommendations - move accessors into header, and finish some of his other reccom. Change assignment to use const wxString& instead of const wxChar*. Change wxURI docs to reflect that it inherits from wxObject. Made preliminary docs for the wxURL transition. Add some unit tests for the transition.
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@30136 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -207,6 +207,8 @@ All:
|
||||
- Norwegian (Bokm<6B>l) translation added (Hans F. Nordhaug)
|
||||
- wxDynamicLibrary::HasSymbol() added
|
||||
- added wxTextInputStream::operator>>(wchar_t) for compilers which support this
|
||||
- added wxURI
|
||||
- changed wxURL to inherit from wxURI and provide assignment and comparison
|
||||
|
||||
All (GUI):
|
||||
|
||||
|
@@ -28,7 +28,7 @@ furthur functionality.
|
||||
|
||||
\wxheading{Derived from}
|
||||
|
||||
No base class
|
||||
\helpref{wxObject}{wxobject}
|
||||
|
||||
\wxheading{Include files}
|
||||
|
||||
|
@@ -1,8 +1,13 @@
|
||||
\section{\class{wxURL}}\label{wxurl}
|
||||
|
||||
Parses URLs.
|
||||
|
||||
Supports standard assignment operators, copy constructors,
|
||||
and comparison operators.
|
||||
|
||||
\wxheading{Derived from}
|
||||
|
||||
\helpref{wxObject}{wxobject}
|
||||
\helpref{wxURI}{wxuri}
|
||||
|
||||
\wxheading{Include files}
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: uri.h
|
||||
// Purpose: wxURI - Class for parsing/validating URIs
|
||||
// Purpose: wxURI - Class for parsing URIs
|
||||
// Author: Ryan Norton
|
||||
// Modified By:
|
||||
// Created: 07/01/2004
|
||||
@@ -63,22 +63,22 @@ public:
|
||||
|
||||
void Create(const wxString& uri);
|
||||
|
||||
bool HasScheme() const;
|
||||
bool HasUser() const;
|
||||
bool HasServer() const;
|
||||
bool HasPort() const;
|
||||
bool HasPath() const;
|
||||
bool HasQuery() const;
|
||||
bool HasFragment() const;
|
||||
bool HasScheme() const { return (m_fields & wxURI_SCHEME) == wxURI_SCHEME; }
|
||||
bool HasUser() const { return (m_fields & wxURI_USER) == wxURI_USER; }
|
||||
bool HasServer() const { return (m_fields & wxURI_SERVER) == wxURI_SERVER; }
|
||||
bool HasPort() const { return (m_fields & wxURI_PORT) == wxURI_PORT; }
|
||||
bool HasPath() const { return (m_fields & wxURI_PATH) == wxURI_PATH; }
|
||||
bool HasQuery() const { return (m_fields & wxURI_QUERY) == wxURI_QUERY; }
|
||||
bool HasFragment() const { return (m_fields & wxURI_FRAGMENT) == wxURI_FRAGMENT; }
|
||||
|
||||
const wxString& GetScheme() const;
|
||||
const wxString& GetPath() const;
|
||||
const wxString& GetQuery() const;
|
||||
const wxString& GetFragment() const;
|
||||
const wxString& GetPort() const;
|
||||
const wxString& GetUser() const;
|
||||
const wxString& GetServer() const;
|
||||
const wxURIHostType& GetHostType() const;
|
||||
const wxString& GetScheme() const { return m_scheme; }
|
||||
const wxString& GetPath() const { return m_path; }
|
||||
const wxString& GetQuery() const { return m_query; }
|
||||
const wxString& GetFragment() const { return m_fragment; }
|
||||
const wxString& GetPort() const { return m_port; }
|
||||
const wxString& GetUser() const { return m_user; }
|
||||
const wxString& GetServer() const { return m_server; }
|
||||
const wxURIHostType& GetHostType() const { return m_hostType; }
|
||||
|
||||
wxString Get() const;
|
||||
|
||||
@@ -86,10 +86,11 @@ public:
|
||||
bool IsReference() const;
|
||||
|
||||
wxURI& operator = (const wxURI& uri);
|
||||
wxURI& operator = (const wxChar* string);
|
||||
wxURI& operator = (const wxString& string);
|
||||
bool operator == (const wxURI& uri) const;
|
||||
|
||||
protected:
|
||||
wxURI& Assign(const wxURI& uri);
|
||||
|
||||
void Clear();
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
// Name: url.h
|
||||
// Purpose: URL parser
|
||||
// Author: Guilhem Lavaux
|
||||
// Modified by:
|
||||
// Modified by: Ryan Norton
|
||||
// Created: 20/07/1997
|
||||
// RCS-ID: $Id$
|
||||
// Copyright: (c) 1997, 1998 Guilhem Lavaux
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#if wxUSE_URL
|
||||
|
||||
#include "wx/object.h"
|
||||
#include "wx/uri.h"
|
||||
#include "wx/protocol/protocol.h"
|
||||
|
||||
#if wxUSE_PROTOCOL_HTTP
|
||||
@@ -48,14 +48,18 @@ public:
|
||||
};
|
||||
#endif // wxUSE_URL_NATIVE
|
||||
|
||||
class WXDLLIMPEXP_NET wxURL : public wxObject
|
||||
class WXDLLIMPEXP_NET wxURL : public wxURI
|
||||
{
|
||||
public:
|
||||
wxURL(const wxString& url);
|
||||
wxURL(const wxString& sUrl);
|
||||
wxURL(const wxURI& url);
|
||||
virtual ~wxURL();
|
||||
|
||||
wxString GetProtocolName() const { return m_protoinfo->m_protoname; }
|
||||
wxString GetHostName() const { return m_hostname; }
|
||||
wxURL& operator = (const wxString& url);
|
||||
wxURL& operator = (const wxURI& url);
|
||||
|
||||
wxString GetProtocolName() const { return m_scheme; }
|
||||
wxString GetHostName() const { return m_server; }
|
||||
wxString GetURL() const { return m_url; }
|
||||
wxProtocol& GetProtocol() { return *m_protocol; }
|
||||
wxURLError GetError() const { return m_error; }
|
||||
@@ -95,13 +99,10 @@ protected:
|
||||
wxProtocol *m_protocol;
|
||||
|
||||
wxURLError m_error;
|
||||
wxString m_protoname, m_hostname, m_servname, m_path, m_url;
|
||||
wxString m_user, m_password;
|
||||
wxString m_url;
|
||||
bool m_useProxy;
|
||||
|
||||
bool PrepProto(wxString& url);
|
||||
bool PrepHost(wxString& url);
|
||||
bool PrepPath(wxString& url);
|
||||
void Init(const wxString&);
|
||||
bool ParseURL();
|
||||
void CleanData();
|
||||
bool FetchProtocol();
|
||||
@@ -110,10 +111,6 @@ protected:
|
||||
friend class wxURLModule;
|
||||
|
||||
private:
|
||||
// VZ: can't use default copy ctor for this class, should write a correct
|
||||
// one! (TODO)
|
||||
DECLARE_NO_COPY_CLASS(wxURL)
|
||||
|
||||
DECLARE_DYNAMIC_CLASS(wxURL)
|
||||
};
|
||||
|
||||
|
@@ -8,6 +8,11 @@
|
||||
// Licence: wxWindows
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
//TODO: RN: I had some massive doxygen docs, I need to move these
|
||||
//in a presentable form in these sources
|
||||
//
|
||||
|
||||
// ===========================================================================
|
||||
// declarations
|
||||
// ===========================================================================
|
||||
@@ -64,7 +69,7 @@ wxURI::wxURI(const wxString& uri) : m_hostType(wxURI_REGNAME), m_fields(0)
|
||||
|
||||
wxURI::wxURI(const wxURI& uri) : m_hostType(wxURI_REGNAME), m_fields(0)
|
||||
{
|
||||
*this = uri;
|
||||
Assign(uri);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -136,61 +141,12 @@ bool wxURI::IsEscape(const wxChar*& uri)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HasXXX
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
bool wxURI::HasScheme() const
|
||||
{ return (m_fields & wxURI_SCHEME) == wxURI_SCHEME; }
|
||||
|
||||
bool wxURI::HasUser() const
|
||||
{ return (m_fields & wxURI_USER) == wxURI_USER; }
|
||||
|
||||
bool wxURI::HasServer() const
|
||||
{ return (m_fields & wxURI_SERVER) == wxURI_SERVER; }
|
||||
|
||||
bool wxURI::HasPort() const
|
||||
{ return (m_fields & wxURI_PORT) == wxURI_PORT; }
|
||||
|
||||
bool wxURI::HasPath() const
|
||||
{ return (m_fields & wxURI_PATH) == wxURI_PATH; }
|
||||
|
||||
bool wxURI::HasQuery() const
|
||||
{ return (m_fields & wxURI_QUERY) == wxURI_QUERY; }
|
||||
|
||||
bool wxURI::HasFragment() const
|
||||
{ return (m_fields & wxURI_FRAGMENT) == wxURI_FRAGMENT; }
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// GetXXX
|
||||
// Get
|
||||
//
|
||||
// The normal Get() actually builds the entire URI into a useable
|
||||
// Get() actually builds the entire URI into a useable
|
||||
// representation, including proper identification characters such as slashes
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const wxString& wxURI::GetScheme() const
|
||||
{ return m_scheme; }
|
||||
|
||||
const wxString& wxURI::GetPath() const
|
||||
{ return m_path; }
|
||||
|
||||
const wxString& wxURI::GetQuery() const
|
||||
{ return m_query; }
|
||||
|
||||
const wxString& wxURI::GetFragment() const
|
||||
{ return m_fragment; }
|
||||
|
||||
const wxString& wxURI::GetPort() const
|
||||
{ return m_port; }
|
||||
|
||||
const wxString& wxURI::GetUser() const
|
||||
{ return m_user; }
|
||||
|
||||
const wxString& wxURI::GetServer() const
|
||||
{ return m_server; }
|
||||
|
||||
const wxURIHostType& wxURI::GetHostType() const
|
||||
{ return m_hostType; }
|
||||
|
||||
wxString wxURI::Get() const
|
||||
{
|
||||
wxString ret;
|
||||
@@ -228,36 +184,28 @@ wxString wxURI::Get() const
|
||||
|
||||
wxURI& wxURI::operator = (const wxURI& uri)
|
||||
{
|
||||
if (HasScheme())
|
||||
return Assign(uri);
|
||||
}
|
||||
|
||||
wxURI& wxURI::Assign(const wxURI& uri)
|
||||
{
|
||||
//assign fields
|
||||
m_fields = uri.m_fields;
|
||||
|
||||
//ref over components
|
||||
m_scheme = uri.m_scheme;
|
||||
|
||||
|
||||
if (HasServer())
|
||||
{
|
||||
if (HasUser())
|
||||
m_user = uri.m_user;
|
||||
|
||||
m_server = uri.m_server;
|
||||
m_hostType = uri.m_hostType;
|
||||
|
||||
if (HasPort())
|
||||
m_port = uri.m_port;
|
||||
}
|
||||
|
||||
|
||||
if (HasPath())
|
||||
m_path = uri.m_path;
|
||||
|
||||
if (HasQuery())
|
||||
m_query = uri.m_query;
|
||||
|
||||
if (HasFragment())
|
||||
m_fragment = uri.m_fragment;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
wxURI& wxURI::operator = (const wxChar* string)
|
||||
wxURI& wxURI::operator = (const wxString& string)
|
||||
{
|
||||
Create(string);
|
||||
return *this;
|
||||
|
@@ -32,7 +32,7 @@
|
||||
#include <ctype.h>
|
||||
|
||||
IMPLEMENT_CLASS(wxProtoInfo, wxObject)
|
||||
IMPLEMENT_CLASS(wxURL, wxObject)
|
||||
IMPLEMENT_CLASS(wxURL, wxURI)
|
||||
|
||||
// Protocols list
|
||||
wxProtoInfo *wxURL::ms_protocols = NULL;
|
||||
@@ -49,14 +49,39 @@ USE_PROTOCOL(wxFTP)
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------
|
||||
//
|
||||
// wxURL
|
||||
//
|
||||
// --------------------------------------------------------------
|
||||
|
||||
// --------------------------------------------------------------
|
||||
// --------- wxURL CONSTRUCTOR DESTRUCTOR -----------------------
|
||||
// --------------------------------------------------------------
|
||||
wxURL::wxURL(const wxString& url) : wxURI(url)
|
||||
{
|
||||
Init(url);
|
||||
ParseURL();
|
||||
}
|
||||
|
||||
wxURL::wxURL(const wxString& url)
|
||||
wxURL::wxURL(const wxURI& url) : wxURI(url)
|
||||
{
|
||||
Init(url.Get());
|
||||
ParseURL();
|
||||
}
|
||||
|
||||
wxURL& wxURL::operator = (const wxURI& url)
|
||||
{
|
||||
wxURI::operator = (url);
|
||||
Init(url.Get());
|
||||
ParseURL();
|
||||
return *this;
|
||||
}
|
||||
wxURL& wxURL::operator = (const wxString& url)
|
||||
{
|
||||
wxURI::operator = (url);
|
||||
Init(url);
|
||||
ParseURL();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void wxURL::Init(const wxString& url)
|
||||
{
|
||||
m_protocol = NULL;
|
||||
m_error = wxURL_NOERR;
|
||||
@@ -81,21 +106,23 @@ wxURL::wxURL(const wxString& url)
|
||||
m_proxy = ms_proxyDefault;
|
||||
#endif // wxUSE_SOCKETS
|
||||
|
||||
ParseURL();
|
||||
}
|
||||
// --------------------------------------------------------------
|
||||
// ParseURL
|
||||
//
|
||||
// Builds the URL and takes care of the old protocol stuff
|
||||
// --------------------------------------------------------------
|
||||
|
||||
bool wxURL::ParseURL()
|
||||
{
|
||||
wxString last_url = m_url;
|
||||
|
||||
// If the URL was already parsed (m_protocol != NULL), pass this section.
|
||||
if (!m_protocol)
|
||||
{
|
||||
// Clean up
|
||||
CleanData();
|
||||
|
||||
// Extract protocol name
|
||||
if (!PrepProto(last_url))
|
||||
// Make sure we have a protocol/scheme
|
||||
if (!HasScheme())
|
||||
{
|
||||
m_error = wxURL_SNTXERR;
|
||||
return false;
|
||||
@@ -111,22 +138,14 @@ bool wxURL::ParseURL()
|
||||
// Do we need a host name ?
|
||||
if (m_protoinfo->m_needhost)
|
||||
{
|
||||
// Extract it
|
||||
if (!PrepHost(last_url))
|
||||
// Make sure we have one, then
|
||||
if (!HasServer())
|
||||
{
|
||||
m_error = wxURL_SNTXERR;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Extract full path
|
||||
if (!PrepPath(last_url))
|
||||
{
|
||||
m_error = wxURL_NOPATH;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// URL parse finished.
|
||||
|
||||
#if wxUSE_SOCKETS
|
||||
if (m_useProxy)
|
||||
@@ -135,11 +154,9 @@ bool wxURL::ParseURL()
|
||||
delete m_protocol;
|
||||
|
||||
// Third, we rebuild the URL.
|
||||
m_url = m_protoname + wxT(":");
|
||||
m_url = m_scheme + wxT(":");
|
||||
if (m_protoinfo->m_needhost)
|
||||
m_url = m_url + wxT("//") + m_hostname;
|
||||
|
||||
m_url += m_path;
|
||||
m_url = m_url + wxT("//") + m_server;
|
||||
|
||||
// We initialize specific variables.
|
||||
m_protocol = m_proxy; // FIXME: we should clone the protocol
|
||||
@@ -170,87 +187,6 @@ wxURL::~wxURL()
|
||||
#endif
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------
|
||||
// --------- wxURL urls decoders --------------------------------
|
||||
// --------------------------------------------------------------
|
||||
|
||||
bool wxURL::PrepProto(wxString& url)
|
||||
{
|
||||
int pos;
|
||||
|
||||
// Find end
|
||||
pos = url.Find(wxT(':'));
|
||||
if (pos == wxNOT_FOUND)
|
||||
return false;
|
||||
|
||||
m_protoname = url(0, pos);
|
||||
|
||||
url = url(pos+1, url.Length());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxURL::PrepHost(wxString& url)
|
||||
{
|
||||
wxString temp_url;
|
||||
int pos, pos2;
|
||||
|
||||
if ((url.GetChar(0) != wxT('/')) || (url.GetChar(1) != wxT('/')))
|
||||
return false;
|
||||
|
||||
url = url(2, url.Length());
|
||||
|
||||
pos = url.Find(wxT('/'));
|
||||
if (pos == wxNOT_FOUND)
|
||||
pos = url.Length();
|
||||
|
||||
if (pos == 0)
|
||||
return false;
|
||||
|
||||
temp_url = url(0, pos);
|
||||
url = url(url.Find(wxT('/')), url.Length());
|
||||
|
||||
// Retrieve service number
|
||||
pos2 = temp_url.Find(wxT(':'), true);
|
||||
if (pos2 != wxNOT_FOUND && pos2 < pos)
|
||||
{
|
||||
m_servname = temp_url(pos2+1, pos);
|
||||
if (!m_servname.IsNumber())
|
||||
return false;
|
||||
temp_url = temp_url(0, pos2);
|
||||
}
|
||||
|
||||
// Retrieve user and password.
|
||||
pos2 = temp_url.Find(wxT('@'));
|
||||
// Even if pos2 equals wxNOT_FOUND, this code is right.
|
||||
m_hostname = temp_url(pos2+1, temp_url.Length());
|
||||
|
||||
m_user = wxT("");
|
||||
m_password = wxT("");
|
||||
|
||||
if (pos2 == wxNOT_FOUND)
|
||||
return true;
|
||||
|
||||
temp_url = temp_url(0, pos2);
|
||||
pos2 = temp_url.Find(wxT(':'));
|
||||
|
||||
if (pos2 == wxNOT_FOUND)
|
||||
return false;
|
||||
|
||||
m_user = temp_url(0, pos2);
|
||||
m_password = temp_url(pos2+1, url.Length());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxURL::PrepPath(wxString& url)
|
||||
{
|
||||
if (url.Length() != 0)
|
||||
m_path = ConvertToValidURI(url);
|
||||
else
|
||||
m_path = wxT("/");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxURL::FetchProtocol()
|
||||
{
|
||||
@@ -258,11 +194,10 @@ bool wxURL::FetchProtocol()
|
||||
|
||||
while (info)
|
||||
{
|
||||
if (m_protoname == info->m_protoname)
|
||||
if (m_scheme == info->m_protoname)
|
||||
{
|
||||
if (m_servname.IsNull())
|
||||
m_servname = info->m_servname;
|
||||
|
||||
if (m_port.IsNull())
|
||||
m_port = info->m_servname;
|
||||
m_protoinfo = info;
|
||||
m_protocol = (wxProtocol *)m_protoinfo->m_cinfo->CreateObject();
|
||||
return true;
|
||||
@@ -285,10 +220,17 @@ wxInputStream *wxURL::GetInputStream()
|
||||
}
|
||||
|
||||
m_error = wxURL_NOERR;
|
||||
if (m_user != wxT(""))
|
||||
if (HasUser())
|
||||
{
|
||||
size_t dwPasswordPos = m_user.find(':');
|
||||
|
||||
if (dwPasswordPos == wxString::npos)
|
||||
m_protocol->SetUser(m_user);
|
||||
m_protocol->SetPassword(m_password);
|
||||
else
|
||||
{
|
||||
m_protocol->SetUser(m_user(0, dwPasswordPos));
|
||||
m_protocol->SetPassword(m_user(dwPasswordPos+1, m_user.length() + 1));
|
||||
}
|
||||
}
|
||||
|
||||
#if wxUSE_URL_NATIVE
|
||||
@@ -310,13 +252,13 @@ wxInputStream *wxURL::GetInputStream()
|
||||
// m_protoinfo is NULL when we use a proxy
|
||||
if (!m_useProxy && m_protoinfo->m_needhost)
|
||||
{
|
||||
if (!addr.Hostname(m_hostname))
|
||||
if (!addr.Hostname(m_server))
|
||||
{
|
||||
m_error = wxURL_NOHOST;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
addr.Service(m_servname);
|
||||
addr.Service(m_port);
|
||||
|
||||
if (!m_protocol->Connect(addr, true)) // Watcom needs the 2nd arg for some reason
|
||||
{
|
||||
|
@@ -25,6 +25,9 @@
|
||||
|
||||
#include "wx/cppunit.h"
|
||||
|
||||
// Test wxURL & wxURI compat?
|
||||
#define TEST_URL 0
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// test class
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -46,6 +49,9 @@ private:
|
||||
CPPUNIT_TEST( BackwardsResolving );
|
||||
CPPUNIT_TEST( Assignment );
|
||||
CPPUNIT_TEST( Comparison );
|
||||
#if TEST_URL
|
||||
CPPUNIT_TEST( URLCompat );
|
||||
#endif
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
void IPv4();
|
||||
@@ -59,6 +65,10 @@ private:
|
||||
void Assignment();
|
||||
void Comparison();
|
||||
|
||||
#if 1
|
||||
void URLCompat();
|
||||
#endif
|
||||
|
||||
DECLARE_NO_COPY_CLASS(URITestCase)
|
||||
};
|
||||
|
||||
@@ -264,3 +274,37 @@ void URITestCase::Comparison()
|
||||
{
|
||||
CPPUNIT_ASSERT(wxURI(wxT("http://mysite.com")) == wxURI(wxT("http://mysite.com")));
|
||||
}
|
||||
|
||||
#if TEST_URL
|
||||
|
||||
#include "wx/url.h"
|
||||
|
||||
void URITestCase::URLCompat()
|
||||
{
|
||||
wxURL url(wxT("http://user:password@wxwidgets.org"));
|
||||
|
||||
CPPUNIT_ASSERT(url.GetError() == wxURL_NOERR);
|
||||
|
||||
wxInputStream* pInput = url.GetInputStream();
|
||||
|
||||
CPPUNIT_ASSERT( pInput != NULL );
|
||||
|
||||
CPPUNIT_ASSERT( url == wxURL(wxT("http://user:password@wxwidgets.org")) );
|
||||
|
||||
wxURI uri(wxT("http://user:password@wxwidgets.org"));
|
||||
|
||||
CPPUNIT_ASSERT( url == uri );
|
||||
|
||||
wxURL urlcopy(uri);
|
||||
|
||||
CPPUNIT_ASSERT( urlcopy == url );
|
||||
CPPUNIT_ASSERT( urlcopy == uri );
|
||||
|
||||
wxURI uricopy(url);
|
||||
|
||||
CPPUNIT_ASSERT( uricopy == url );
|
||||
CPPUNIT_ASSERT( uricopy == urlcopy );
|
||||
CPPUNIT_ASSERT( uricopy == uri );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user