fixed: BBCODEParser incorrectly worked with the latest changes in HTMLFilter
git-svn-id: svn://ttmath.org/publicrep/winix/trunk@729 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
@@ -10,6 +10,8 @@
|
|||||||
#include "bbcodeparser.h"
|
#include "bbcodeparser.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool BBCODEParser::Equal(const wchar_t * str1, const wchar_t * str2)
|
bool BBCODEParser::Equal(const wchar_t * str1, const wchar_t * str2)
|
||||||
{
|
{
|
||||||
while( *str1 == *str2 && *str1 != 0 )
|
while( *str1 == *str2 && *str1 != 0 )
|
||||||
@@ -67,6 +69,10 @@ bool BBCODEParser::IsClosingXmlSimpleTagMark()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// one enter will generate one <br>
|
// one enter will generate one <br>
|
||||||
// two enters or more will generate only two br (<br><br>)
|
// two enters or more will generate only two br (<br><br>)
|
||||||
void BBCODEParser::PutNormalText(const wchar_t * str, const wchar_t * end)
|
void BBCODEParser::PutNormalText(const wchar_t * str, const wchar_t * end)
|
||||||
@@ -116,12 +122,6 @@ int br_len;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BBCODEParser::PutNormalTextTrim(const wchar_t * str, const wchar_t * end)
|
|
||||||
{
|
|
||||||
// we don't use trimming in bbcode parser
|
|
||||||
PutNormalText(str, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void BBCODEParser::ReadNormalTextSkipWhite(const wchar_t * & start, const wchar_t * & last_non_white)
|
void BBCODEParser::ReadNormalTextSkipWhite(const wchar_t * & start, const wchar_t * & last_non_white)
|
||||||
{
|
{
|
||||||
@@ -367,19 +367,21 @@ void BBCODEParser::PrintEncode(const wchar_t * start, const wchar_t * end)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void BBCODEParser::PutOpeningTagFromEzc(const wchar_t * start, const wchar_t * end)
|
void BBCODEParser::PutOpeningTagFromEzc()
|
||||||
{
|
{
|
||||||
// this can be a tag from Ezc templates system
|
// this can be a tag from Ezc templates system
|
||||||
(*out_string) += '[';
|
(*out_string) += '[';
|
||||||
(*out_string) += LastItem().name;
|
(*out_string) += LastItem().name;
|
||||||
|
|
||||||
if( start != end )
|
const wchar_t * start = pchar;
|
||||||
{
|
|
||||||
(*out_string) += ' ';
|
|
||||||
PrintEscape(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
(*out_string) += ']';
|
while( *pchar && *pchar!=']' )
|
||||||
|
++pchar;
|
||||||
|
|
||||||
|
if( *pchar == ']' )
|
||||||
|
++pchar;
|
||||||
|
|
||||||
|
Put(start, pchar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -495,33 +497,40 @@ bool has_u;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BBCODEParser::PutOpeningTagFromBBCode(const Tags * tag, const wchar_t * start, const wchar_t * end)
|
void BBCODEParser::PutOpeningTagFromBBCode(const Tags * tag)
|
||||||
{
|
{
|
||||||
CheckOpeningTag(tag);
|
CheckOpeningTag(tag);
|
||||||
PutOpeningTagMark();
|
PutOpeningTagMark();
|
||||||
(*out_string) += tag->html_tag;
|
Put(tag->html_tag);
|
||||||
PutHtmlArgument(tag, start, end);
|
|
||||||
|
const wchar_t * start = pchar;
|
||||||
|
|
||||||
|
while( *pchar && *pchar != ']' )
|
||||||
|
++pchar;
|
||||||
|
|
||||||
|
PutHtmlArgument(tag, start, pchar);
|
||||||
|
|
||||||
|
if( *pchar == ']' )
|
||||||
|
++pchar;
|
||||||
|
|
||||||
if( !tag->inline_tag )
|
if( !tag->inline_tag )
|
||||||
{
|
{
|
||||||
(*out_string) += L"\n";
|
Put(10);
|
||||||
SkipWhiteLines();
|
SkipWhiteLines();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BBCODEParser::PutOpeningTag(const wchar_t * start, const wchar_t * end)
|
bool BBCODEParser::PutOpeningTag()
|
||||||
{
|
{
|
||||||
const Tags * tag = FindTag(LastItem().name);
|
const Tags * tag = FindTag(LastItem().name);
|
||||||
|
|
||||||
if( !tag )
|
if( !tag )
|
||||||
{
|
PutOpeningTagFromEzc();
|
||||||
PutOpeningTagFromEzc(start, end);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
PutOpeningTagFromBBCode(tag);
|
||||||
PutOpeningTagFromBBCode(tag, start, end);
|
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -570,7 +579,7 @@ void BBCODEParser::Init()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BBCODEParser::Deinit()
|
void BBCODEParser::Uninit()
|
||||||
{
|
{
|
||||||
if( has_open_li_tag )
|
if( has_open_li_tag )
|
||||||
(*out_string) += L"</li>\n";
|
(*out_string) += L"</li>\n";
|
||||||
|
|||||||
@@ -13,55 +13,60 @@
|
|||||||
#include "htmlfilter.h"
|
#include "htmlfilter.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BBCODEParser : public HTMLFilter
|
class BBCODEParser : public HTMLFilter
|
||||||
{
|
{
|
||||||
|
|
||||||
//using HTMLFilter::pchar;
|
|
||||||
|
|
||||||
|
|
||||||
struct Tags
|
struct Tags
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
const wchar_t * bbcode;
|
|
||||||
const wchar_t * html_tag;
|
|
||||||
const wchar_t * html_arg_prefix;
|
|
||||||
const wchar_t * html_arg_postfix;
|
|
||||||
const wchar_t * additional_html_tag_prefix;
|
|
||||||
const wchar_t * additional_html_tag_postfix;
|
|
||||||
bool inline_tag;
|
|
||||||
*/
|
|
||||||
const wchar_t * bbcode;
|
const wchar_t * bbcode;
|
||||||
const wchar_t * html_tag;
|
const wchar_t * html_tag;
|
||||||
const wchar_t * html_argument; // with closing '>'
|
const wchar_t * html_argument; // with closing '>'
|
||||||
bool inline_tag;
|
bool inline_tag;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Equal(const wchar_t * str1, const wchar_t * str2);
|
|
||||||
|
|
||||||
virtual bool IsValidCharForName(int c);
|
/*
|
||||||
|
virtual methods
|
||||||
|
(from HTMLFilter class)
|
||||||
|
*/
|
||||||
|
virtual void Init();
|
||||||
|
virtual void Uninit();
|
||||||
|
|
||||||
virtual bool IsOpeningTagMark();
|
virtual bool IsOpeningTagMark();
|
||||||
virtual bool IsOpeningCommentaryTagMark();
|
virtual bool IsOpeningCommentaryTagMark();
|
||||||
virtual bool SkipCommentaryTagIfExists();
|
|
||||||
virtual bool IsClosingTagMark();
|
virtual bool IsClosingTagMark();
|
||||||
virtual bool IsClosingXmlSimpleTagMark();
|
virtual bool IsClosingXmlSimpleTagMark();
|
||||||
|
|
||||||
|
virtual bool IsValidCharForName(int c);
|
||||||
|
virtual void CheckExceptions();
|
||||||
|
virtual bool SkipCommentaryTagIfExists();
|
||||||
|
|
||||||
|
virtual bool PutOpeningTag();
|
||||||
|
virtual void PutClosingTag(const wchar_t * tag);
|
||||||
|
|
||||||
|
virtual void PutNormalText(const wchar_t * str, const wchar_t * end);
|
||||||
|
virtual void ReadNormalTextSkipWhite(const wchar_t * & start, const wchar_t * & last_non_white);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
others
|
||||||
|
*/
|
||||||
|
bool Equal(const wchar_t * str1, const wchar_t * str2);
|
||||||
|
|
||||||
void PutHtmlArgument1(const wchar_t * arg_start, const wchar_t * arg_end, bool has_u);
|
void PutHtmlArgument1(const wchar_t * arg_start, const wchar_t * arg_end, bool has_u);
|
||||||
void PutHtmlArgument2(const Tags * tag, bool has_u);
|
void PutHtmlArgument2(const Tags * tag, bool has_u);
|
||||||
void PutHtmlArgument(const Tags * tag, const wchar_t * arg_start, const wchar_t * arg_end);
|
void PutHtmlArgument(const Tags * tag, const wchar_t * arg_start, const wchar_t * arg_end);
|
||||||
|
|
||||||
void PutOpeningTagFromEzc(const wchar_t * start, const wchar_t * end);
|
void PutOpeningTagFromEzc();
|
||||||
void PutOpeningTagFromBBCode(const Tags * tag, const wchar_t * start, const wchar_t * end);
|
void PutOpeningTagFromBBCode(const Tags * tag);
|
||||||
|
|
||||||
virtual void PutOpeningTag(const wchar_t * start, const wchar_t * end);
|
|
||||||
virtual void PutClosingTag(const wchar_t * tag);
|
|
||||||
|
|
||||||
const Tags * FindTag(const wchar_t * tag);
|
const Tags * FindTag(const wchar_t * tag);
|
||||||
const Tags * FindTag(const std::wstring & tag);
|
const Tags * FindTag(const std::wstring & tag);
|
||||||
void PrintArgumentCheckQuotes(const wchar_t * & start, const wchar_t * & end);
|
void PrintArgumentCheckQuotes(const wchar_t * & start, const wchar_t * & end);
|
||||||
|
|
||||||
|
|
||||||
void PrintEscape(int c, bool change_quote = false);
|
void PrintEscape(int c, bool change_quote = false);
|
||||||
void PrintEncode(int c);
|
void PrintEncode(int c);
|
||||||
|
|
||||||
@@ -71,18 +76,8 @@ class BBCODEParser : public HTMLFilter
|
|||||||
void PrintArgumentEncode(const wchar_t * start, const wchar_t * end);
|
void PrintArgumentEncode(const wchar_t * start, const wchar_t * end);
|
||||||
void PrintArgumentEscape(const wchar_t * start, const wchar_t * end);
|
void PrintArgumentEscape(const wchar_t * start, const wchar_t * end);
|
||||||
|
|
||||||
virtual void ReadNormalTextSkipWhite(const wchar_t * & start, const wchar_t * & last_non_white);
|
|
||||||
virtual void PutNormalText(const wchar_t * str, const wchar_t * end);
|
|
||||||
virtual void PutNormalTextTrim(const wchar_t * str, const wchar_t * end);
|
|
||||||
|
|
||||||
virtual void CheckExceptions();
|
|
||||||
|
|
||||||
virtual void Init();
|
|
||||||
virtual void Deinit();
|
|
||||||
|
|
||||||
void PutClosingTag(const Tags * tag);
|
void PutClosingTag(const Tags * tag);
|
||||||
|
|
||||||
|
|
||||||
void CheckOpeningTag(const Tags * tag, const wchar_t * tag_name, bool & condition);
|
void CheckOpeningTag(const Tags * tag, const wchar_t * tag_name, bool & condition);
|
||||||
void CheckOpeningTag(const Tags * tag);
|
void CheckOpeningTag(const Tags * tag);
|
||||||
|
|
||||||
@@ -91,8 +86,6 @@ class BBCODEParser : public HTMLFilter
|
|||||||
bool has_open_ol_tag; // has open html <ol> tag
|
bool has_open_ol_tag; // has open html <ol> tag
|
||||||
bool has_open_ul_tag; // has open html <ul> tag
|
bool has_open_ul_tag; // has open html <ul> tag
|
||||||
bool has_open_li_tag; // has open html <li> tag
|
bool has_open_li_tag; // has open html <li> tag
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ void HTMLFilter::Filter(const wchar_t * in, std::wstring & out)
|
|||||||
|
|
||||||
Init();
|
Init();
|
||||||
Read();
|
Read();
|
||||||
Deinit();
|
Uninit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ void HTMLFilter::Init()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void HTMLFilter::Deinit()
|
void HTMLFilter::Uninit()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -714,19 +714,6 @@ void HTMLFilter::PutClosingTagMark()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// !! zamienic na poprostu Put (juz jest gotowa)
|
|
||||||
void HTMLFilter::PutTagName(const wchar_t * name)
|
|
||||||
{
|
|
||||||
Put(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HTMLFilter::PutTagName(const std::wstring & name)
|
|
||||||
{
|
|
||||||
PutTagName(name.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool HTMLFilter::IsTagSafe(const wchar_t * tag)
|
bool HTMLFilter::IsTagSafe(const wchar_t * tag)
|
||||||
{
|
{
|
||||||
@@ -760,17 +747,16 @@ bool HTMLFilter::IsTagSafe(const std::wstring & tag)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// start, end - arguments
|
bool HTMLFilter::PutOpeningTag()
|
||||||
void HTMLFilter::PutOpeningTag(bool close_tag)
|
|
||||||
{
|
{
|
||||||
if( !IsTagSafe(LastItem().name) )
|
if( !IsTagSafe(LastItem().name) )
|
||||||
return;
|
// dodac tutaj skipniecie calego tagu
|
||||||
|
return false;
|
||||||
|
|
||||||
PutOpeningTagMark();
|
PutOpeningTagMark();
|
||||||
PutTagName(LastItem().name);
|
Put(LastItem().name);
|
||||||
|
|
||||||
if( close_tag )
|
return true;
|
||||||
PutClosingTagMark();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -782,7 +768,7 @@ void HTMLFilter::PutClosingTag(const wchar_t * tag)
|
|||||||
|
|
||||||
PutOpeningTagMark();
|
PutOpeningTagMark();
|
||||||
Put('/');
|
Put('/');
|
||||||
PutTagName(tag);
|
Put(tag);
|
||||||
PutClosingTagMark();
|
PutClosingTagMark();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -952,7 +938,7 @@ const wchar_t * last_non_white = pchar;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void HTMLFilter::PrintOpeningItem()
|
bool HTMLFilter::PrintOpeningItem()
|
||||||
{
|
{
|
||||||
if( last_new_line )
|
if( last_new_line )
|
||||||
{
|
{
|
||||||
@@ -962,7 +948,7 @@ void HTMLFilter::PrintOpeningItem()
|
|||||||
PutTabs(stack_len-1);
|
PutTabs(stack_len-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
PutOpeningTag(false); // without closing mark
|
return PutOpeningTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1067,20 +1053,22 @@ void HTMLFilter::ReadItemOpening()
|
|||||||
{
|
{
|
||||||
LastItem().type = Item::opening;
|
LastItem().type = Item::opening;
|
||||||
ReadItemName();
|
ReadItemName();
|
||||||
PrintOpeningItem();
|
|
||||||
|
if( PrintOpeningItem() )
|
||||||
while( ReadItemAttr() )
|
|
||||||
{
|
{
|
||||||
if( CheckItemAttr() )
|
while( ReadItemAttr() )
|
||||||
PrinItemAttr();
|
{
|
||||||
|
if( CheckItemAttr() )
|
||||||
|
PrinItemAttr();
|
||||||
|
}
|
||||||
|
|
||||||
|
SkipAndCheckClosingTag(); // here LastItem().type can be changed to 'simple'
|
||||||
|
|
||||||
|
if( LastItem().type == Item::simple )
|
||||||
|
Put(L" /");
|
||||||
|
|
||||||
|
PutClosingTagMark();
|
||||||
}
|
}
|
||||||
|
|
||||||
SkipAndCheckClosingTag(); // here LastItem().type can be changed to 'simple'
|
|
||||||
|
|
||||||
if( LastItem().type == Item::simple )
|
|
||||||
Put(L" /");
|
|
||||||
|
|
||||||
PutClosingTagMark();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -169,8 +169,39 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
virtual methods
|
||||||
|
*/
|
||||||
|
virtual void Init();
|
||||||
|
virtual void Uninit();
|
||||||
|
|
||||||
|
virtual bool IsOpeningTagMark();
|
||||||
|
virtual bool IsOpeningCommentaryTagMark();
|
||||||
|
virtual bool IsClosingTagMark();
|
||||||
|
virtual bool IsClosingXmlSimpleTagMark();
|
||||||
|
|
||||||
|
virtual bool IsValidCharForName(int c);
|
||||||
|
virtual bool IsValidCharForAttrName(int c);
|
||||||
|
virtual void CheckExceptions();
|
||||||
|
virtual bool SkipCommentaryTagIfExists();
|
||||||
|
|
||||||
|
virtual void Put(wchar_t c);
|
||||||
|
virtual void Put(const wchar_t * str);
|
||||||
|
virtual void Put(const wchar_t * str, const wchar_t * end);
|
||||||
|
virtual void Put(const std::wstring & str);
|
||||||
|
|
||||||
|
virtual void PutOpeningTagMark();
|
||||||
|
virtual void PutClosingTagMark();
|
||||||
|
virtual bool PutOpeningTag();
|
||||||
|
virtual void PutClosingTag(const wchar_t * tag);
|
||||||
|
|
||||||
|
virtual void PutNormalText(const wchar_t * str, const wchar_t * end);
|
||||||
|
virtual void ReadNormalTextSkipWhite(const wchar_t * & start, const wchar_t * & last_non_white);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
others
|
||||||
|
*/
|
||||||
Item & GetItem(size_t i);
|
Item & GetItem(size_t i);
|
||||||
Item & LastItem();
|
Item & LastItem();
|
||||||
|
|
||||||
@@ -201,27 +232,18 @@ protected:
|
|||||||
void SkipWhiteWithFirstNewLine();
|
void SkipWhiteWithFirstNewLine();
|
||||||
void SkipWhiteLines(const wchar_t * & str, const wchar_t * end);
|
void SkipWhiteLines(const wchar_t * & str, const wchar_t * end);
|
||||||
bool IsClosingTagForLastItem();
|
bool IsClosingTagForLastItem();
|
||||||
virtual bool IsOpeningTagMark();
|
|
||||||
virtual bool IsOpeningCommentaryTagMark();
|
|
||||||
size_t OpeningCommentaryTagMarkSize();
|
size_t OpeningCommentaryTagMarkSize();
|
||||||
virtual bool IsClosingTagMark();
|
|
||||||
virtual bool IsClosingXmlSimpleTagMark();
|
|
||||||
bool SkipCommentaryTagIfExists();
|
|
||||||
void SkipAndCheckClosingTag();
|
void SkipAndCheckClosingTag();
|
||||||
|
|
||||||
void PopStack();
|
void PopStack();
|
||||||
bool PushStack();
|
bool PushStack();
|
||||||
virtual bool IsValidCharForName(int c);
|
|
||||||
virtual bool IsValidCharForAttrName(int c);
|
|
||||||
void CheckNewLine();
|
void CheckNewLine();
|
||||||
virtual void CheckExceptions();
|
|
||||||
void CheckStackPrintRest();
|
void CheckStackPrintRest();
|
||||||
void AddForgottenTags();
|
void AddForgottenTags();
|
||||||
void CheckClosingTags();
|
void CheckClosingTags();
|
||||||
virtual void ReadNormalTextSkipWhite(const wchar_t * & start, const wchar_t * & last_non_white);
|
|
||||||
void ReadNormalText();
|
void ReadNormalText();
|
||||||
bool PrintRest();
|
bool PrintRest();
|
||||||
void PrintOpeningItem();
|
bool PrintOpeningItem();
|
||||||
void ReadItemName();
|
void ReadItemName();
|
||||||
void ReadItemAttrName();
|
void ReadItemAttrName();
|
||||||
void ReadItemAttrValue(bool has_quote);
|
void ReadItemAttrValue(bool has_quote);
|
||||||
@@ -234,30 +256,16 @@ protected:
|
|||||||
void ReadItemSpecial();
|
void ReadItemSpecial();
|
||||||
void ReadItemOpening();
|
void ReadItemOpening();
|
||||||
bool ReadItem();
|
bool ReadItem();
|
||||||
virtual void Init();
|
|
||||||
virtual void Deinit();
|
|
||||||
void ReadLoop();
|
void ReadLoop();
|
||||||
void Read();
|
void Read();
|
||||||
|
|
||||||
void CheckChar(wchar_t c);
|
void CheckChar(wchar_t c);
|
||||||
|
|
||||||
virtual void Put(wchar_t c);
|
|
||||||
virtual void Put(const wchar_t * str);
|
|
||||||
virtual void Put(const wchar_t * str, const wchar_t * end);
|
|
||||||
virtual void Put(const std::wstring & str);
|
|
||||||
|
|
||||||
void CheckLineWrap();
|
void CheckLineWrap();
|
||||||
bool HasSemiloconAround(const wchar_t * str, const wchar_t * end);
|
bool HasSemiloconAround(const wchar_t * str, const wchar_t * end);
|
||||||
void PutNormalNonWhite(const wchar_t * & str, const wchar_t * end);
|
void PutNormalNonWhite(const wchar_t * & str, const wchar_t * end);
|
||||||
void PutNormalWhite(const wchar_t * & str, const wchar_t * end);
|
void PutNormalWhite(const wchar_t * & str, const wchar_t * end);
|
||||||
virtual void PutNormalText(const wchar_t * str, const wchar_t * end);
|
|
||||||
void PutLastTagWithClosingTag();
|
void PutLastTagWithClosingTag();
|
||||||
virtual void PutOpeningTagMark();
|
|
||||||
virtual void PutClosingTagMark();
|
|
||||||
virtual void PutTagName(const wchar_t * name);
|
|
||||||
void PutTagName(const std::wstring & name);
|
|
||||||
virtual void PutOpeningTag(bool close_tag = true);
|
|
||||||
virtual void PutClosingTag(const wchar_t * tag);
|
|
||||||
void PutTabs(size_t len);
|
void PutTabs(size_t len);
|
||||||
void PutNonBreakingSpace();
|
void PutNonBreakingSpace();
|
||||||
void PutNewLine();
|
void PutNewLine();
|
||||||
|
|||||||
Reference in New Issue
Block a user