mirror of
https://github.com/LongSoft/UEFITool.git
synced 2024-11-25 01:18:22 +08:00
NE Alpha 36
This commit is contained in:
parent
4160a6a580
commit
0e60013311
@ -37,7 +37,7 @@ void HexViewDialog::setFont(const QFont &font)
|
|||||||
hexView->setFont(font);
|
hexView->setFont(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HexViewDialog::setItem(const UModelIndex & index)
|
void HexViewDialog::setItem(const UModelIndex & index, bool bodyOnly)
|
||||||
{
|
{
|
||||||
const TreeModel * model = (const TreeModel*)index.model();
|
const TreeModel * model = (const TreeModel*)index.model();
|
||||||
|
|
||||||
@ -47,6 +47,8 @@ void HexViewDialog::setItem(const UModelIndex & index)
|
|||||||
setWindowTitle(UString("Hex view: ") + (itemText.isEmpty() ? itemName : itemName + " | " + itemText));
|
setWindowTitle(UString("Hex view: ") + (itemText.isEmpty() ? itemName : itemName + " | " + itemText));
|
||||||
|
|
||||||
// Set hex data
|
// Set hex data
|
||||||
QByteArray data = model->header(index) + model->body(index) + model->tail(index);
|
QByteArray data;
|
||||||
|
if (bodyOnly) data = model->body(index);
|
||||||
|
else data = model->header(index) + model->body(index) + model->tail(index);
|
||||||
hexView->setData(data);
|
hexView->setData(data);
|
||||||
}
|
}
|
@ -28,7 +28,7 @@ public:
|
|||||||
~HexViewDialog();
|
~HexViewDialog();
|
||||||
Ui::HexViewDialog* ui;
|
Ui::HexViewDialog* ui;
|
||||||
|
|
||||||
void setItem(const UModelIndex & index);
|
void setItem(const UModelIndex & index, bool bodyOnly);
|
||||||
void setFont(const QFont &font);
|
void setFont(const QFont &font);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
UEFITool::UEFITool(QWidget *parent) :
|
UEFITool::UEFITool(QWidget *parent) :
|
||||||
QMainWindow(parent),
|
QMainWindow(parent),
|
||||||
ui(new Ui::UEFITool),
|
ui(new Ui::UEFITool),
|
||||||
version(tr("NE Alpha35"))
|
version(tr("NE Alpha36"))
|
||||||
{
|
{
|
||||||
clipboard = QApplication::clipboard();
|
clipboard = QApplication::clipboard();
|
||||||
|
|
||||||
@ -39,6 +39,7 @@ version(tr("NE Alpha35"))
|
|||||||
connect(ui->actionSaveImageFile, SIGNAL(triggered()), this, SLOT(saveImageFile()));
|
connect(ui->actionSaveImageFile, SIGNAL(triggered()), this, SLOT(saveImageFile()));
|
||||||
connect(ui->actionSearch, SIGNAL(triggered()), this, SLOT(search()));
|
connect(ui->actionSearch, SIGNAL(triggered()), this, SLOT(search()));
|
||||||
connect(ui->actionHexView, SIGNAL(triggered()), this, SLOT(hexView()));
|
connect(ui->actionHexView, SIGNAL(triggered()), this, SLOT(hexView()));
|
||||||
|
connect(ui->actionBodyHexView, SIGNAL(triggered()), this, SLOT(bodyHexView()));
|
||||||
connect(ui->actionExtract, SIGNAL(triggered()), this, SLOT(extractAsIs()));
|
connect(ui->actionExtract, SIGNAL(triggered()), this, SLOT(extractAsIs()));
|
||||||
connect(ui->actionExtractBody, SIGNAL(triggered()), this, SLOT(extractBody()));
|
connect(ui->actionExtractBody, SIGNAL(triggered()), this, SLOT(extractBody()));
|
||||||
connect(ui->actionExtractBodyUncompressed, SIGNAL(triggered()), this, SLOT(extractBodyUncompressed()));
|
connect(ui->actionExtractBodyUncompressed, SIGNAL(triggered()), this, SLOT(extractBodyUncompressed()));
|
||||||
@ -198,6 +199,7 @@ void UEFITool::populateUi(const QModelIndex ¤t)
|
|||||||
|
|
||||||
// Enable actions
|
// Enable actions
|
||||||
ui->actionHexView->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current) && model->hasEmptyTail(current));
|
ui->actionHexView->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current) && model->hasEmptyTail(current));
|
||||||
|
ui->actionBodyHexView->setDisabled(model->hasEmptyBody(current));
|
||||||
ui->actionExtract->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current) && model->hasEmptyTail(current));
|
ui->actionExtract->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current) && model->hasEmptyTail(current));
|
||||||
ui->actionGoToData->setEnabled(type == Types::NvarEntry && subtype == Subtypes::LinkNvarEntry);
|
ui->actionGoToData->setEnabled(type == Types::NvarEntry && subtype == Subtypes::LinkNvarEntry);
|
||||||
|
|
||||||
@ -309,7 +311,17 @@ void UEFITool::hexView()
|
|||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hexViewDialog->setItem(index);
|
hexViewDialog->setItem(index, false);
|
||||||
|
hexViewDialog->exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEFITool::bodyHexView()
|
||||||
|
{
|
||||||
|
QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex();
|
||||||
|
if (!index.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
hexViewDialog->setItem(index, true);
|
||||||
hexViewDialog->exec();
|
hexViewDialog->exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,7 +376,7 @@ void UEFITool::goToData()
|
|||||||
void UEFITool::insert(const UINT8 mode)
|
void UEFITool::insert(const UINT8 mode)
|
||||||
{
|
{
|
||||||
U_UNUSED_PARAMETER(mode);
|
U_UNUSED_PARAMETER(mode);
|
||||||
|
|
||||||
/*QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex();
|
/*QModelIndex index = ui->structureTreeView->selectionModel()->currentIndex();
|
||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return;
|
return;
|
||||||
|
@ -78,6 +78,7 @@ private slots:
|
|||||||
void goToOffset();
|
void goToOffset();
|
||||||
|
|
||||||
void hexView();
|
void hexView();
|
||||||
|
void bodyHexView();
|
||||||
void goToData();
|
void goToData();
|
||||||
|
|
||||||
void extract(const UINT8 mode);
|
void extract(const UINT8 mode);
|
||||||
|
@ -305,6 +305,7 @@
|
|||||||
<string>&Capsule</string>
|
<string>&Capsule</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionHexView"/>
|
<addaction name="actionHexView"/>
|
||||||
|
<addaction name="actionBodyHexView"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionExtract"/>
|
<addaction name="actionExtract"/>
|
||||||
<addaction name="actionExtractBody"/>
|
<addaction name="actionExtractBody"/>
|
||||||
@ -354,6 +355,7 @@
|
|||||||
<string>&Volume</string>
|
<string>&Volume</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionHexView"/>
|
<addaction name="actionHexView"/>
|
||||||
|
<addaction name="actionBodyHexView"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionExtract"/>
|
<addaction name="actionExtract"/>
|
||||||
<addaction name="actionExtractBody"/>
|
<addaction name="actionExtractBody"/>
|
||||||
@ -373,6 +375,7 @@
|
|||||||
<string>&File</string>
|
<string>&File</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionHexView"/>
|
<addaction name="actionHexView"/>
|
||||||
|
<addaction name="actionBodyHexView"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionExtract"/>
|
<addaction name="actionExtract"/>
|
||||||
<addaction name="actionExtractBody"/>
|
<addaction name="actionExtractBody"/>
|
||||||
@ -396,6 +399,7 @@
|
|||||||
<string>&Section</string>
|
<string>&Section</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionHexView"/>
|
<addaction name="actionHexView"/>
|
||||||
|
<addaction name="actionBodyHexView"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionExtract"/>
|
<addaction name="actionExtract"/>
|
||||||
<addaction name="actionExtractBody"/>
|
<addaction name="actionExtractBody"/>
|
||||||
@ -432,6 +436,7 @@
|
|||||||
<string>Variable</string>
|
<string>Variable</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionHexView"/>
|
<addaction name="actionHexView"/>
|
||||||
|
<addaction name="actionBodyHexView"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionGoToData"/>
|
<addaction name="actionGoToData"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
@ -456,6 +461,7 @@
|
|||||||
<string>S&tore</string>
|
<string>S&tore</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionHexView"/>
|
<addaction name="actionHexView"/>
|
||||||
|
<addaction name="actionBodyHexView"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionExtract"/>
|
<addaction name="actionExtract"/>
|
||||||
<addaction name="actionExtractBody"/>
|
<addaction name="actionExtractBody"/>
|
||||||
@ -771,6 +777,17 @@
|
|||||||
<string>Ctrl+G</string>
|
<string>Ctrl+G</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionBodyHexView">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Body hex vie&w...</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Shift+D</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
@ -1063,7 +1063,7 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc
|
|||||||
}
|
}
|
||||||
index = model->addItem(model->offset(parent) + localOffset, Types::Volume, subtype, name, text, info, header, body, UByteArray(), Fixed, parent);
|
index = model->addItem(model->offset(parent) + localOffset, Types::Volume, subtype, name, text, info, header, body, UByteArray(), Fixed, parent);
|
||||||
|
|
||||||
// Set parsing data for created item
|
// Set parsing data for created volume
|
||||||
VOLUME_PARSING_DATA pdata;
|
VOLUME_PARSING_DATA pdata;
|
||||||
pdata.emptyByte = emptyByte;
|
pdata.emptyByte = emptyByte;
|
||||||
pdata.ffsVersion = ffsVersion;
|
pdata.ffsVersion = ffsVersion;
|
||||||
@ -1488,6 +1488,8 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
|
|||||||
FILE_PARSING_DATA pdata;
|
FILE_PARSING_DATA pdata;
|
||||||
pdata.emptyByte = (fileHeader->State & EFI_FILE_ERASE_POLARITY) ? 0xFF : 0x00;
|
pdata.emptyByte = (fileHeader->State & EFI_FILE_ERASE_POLARITY) ? 0xFF : 0x00;
|
||||||
pdata.guid = fileHeader->Name;
|
pdata.guid = fileHeader->Name;
|
||||||
|
model->setParsingData(index, UByteArray((const char*)&pdata, sizeof(pdata)));
|
||||||
|
|
||||||
|
|
||||||
// Override lastVtf index, if needed
|
// Override lastVtf index, if needed
|
||||||
if (isVtf) {
|
if (isVtf) {
|
||||||
@ -2904,6 +2906,7 @@ USTATUS FfsParser::parseFit(const UModelIndex & index, const UINT32 diff)
|
|||||||
UString info;
|
UString info;
|
||||||
for (UINT32 i = 1; i < fitHeader->Size; i++) {
|
for (UINT32 i = 1; i < fitHeader->Size; i++) {
|
||||||
currentStrings.clear();
|
currentStrings.clear();
|
||||||
|
info.clear();
|
||||||
const FIT_ENTRY* currentEntry = fitHeader + i;
|
const FIT_ENTRY* currentEntry = fitHeader + i;
|
||||||
UINT32 currentEntrySize = currentEntry->Size;
|
UINT32 currentEntrySize = currentEntry->Size;
|
||||||
|
|
||||||
@ -2916,13 +2919,13 @@ USTATUS FfsParser::parseFit(const UModelIndex & index, const UINT32 diff)
|
|||||||
case FIT_TYPE_EMPTY:
|
case FIT_TYPE_EMPTY:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FIT_TYPE_MICROCODE:
|
case FIT_TYPE_MICROCODE: {
|
||||||
//TODO: refactor into function with error reporting
|
//TODO: refactor into function with error reporting
|
||||||
if (currentEntry->Address > diff && currentEntry->Address < 0xFFFFFFFFUL) {
|
if (currentEntry->Address > diff && currentEntry->Address < 0xFFFFFFFFUL) {
|
||||||
UINT32 offset = currentEntry->Address - diff;
|
UINT32 offset = currentEntry->Address - diff;
|
||||||
UModelIndex mcIndex = model->findByOffset(offset);
|
UModelIndex mcIndex = model->findByOffset(offset);
|
||||||
UByteArray mcFile = model->header(mcIndex) + model->body(mcIndex) + model->tail(mcIndex);
|
UByteArray mcFile = model->header(mcIndex) + model->body(mcIndex) + model->tail(mcIndex);
|
||||||
|
|
||||||
UINT32 mcOffset = offset - model->offset(mcIndex);
|
UINT32 mcOffset = offset - model->offset(mcIndex);
|
||||||
if (mcOffset + sizeof(INTEL_MICROCODE_HEADER) <= (UINT32)mcFile.size()) {
|
if (mcOffset + sizeof(INTEL_MICROCODE_HEADER) <= (UINT32)mcFile.size()) {
|
||||||
const INTEL_MICROCODE_HEADER* header = (const INTEL_MICROCODE_HEADER*)(mcFile.constData() + mcOffset);
|
const INTEL_MICROCODE_HEADER* header = (const INTEL_MICROCODE_HEADER*)(mcFile.constData() + mcOffset);
|
||||||
@ -2936,7 +2939,7 @@ USTATUS FfsParser::parseFit(const UModelIndex & index, const UINT32 diff)
|
|||||||
if (reservedBytesValid) {
|
if (reservedBytesValid) {
|
||||||
UINT32 mcSize = header->TotalSize;
|
UINT32 mcSize = header->TotalSize;
|
||||||
if (mcOffset + mcSize <= (UINT32)mcFile.size()) {
|
if (mcOffset + mcSize <= (UINT32)mcFile.size()) {
|
||||||
info = usprintf("LocalOffset %08Xh, CPUID %Xh, Revision %Xh, Date %08Xh",
|
info = usprintf("LocalOffset %08Xh, CPUID %08Xh, Revision %08Xh, Date %08Xh",
|
||||||
mcOffset,
|
mcOffset,
|
||||||
header->CpuSignature,
|
header->CpuSignature,
|
||||||
header->Revision,
|
header->Revision,
|
||||||
@ -2948,7 +2951,7 @@ USTATUS FfsParser::parseFit(const UModelIndex & index, const UINT32 diff)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
} break;
|
||||||
|
|
||||||
case FIT_TYPE_BIOS_AC_MODULE:
|
case FIT_TYPE_BIOS_AC_MODULE:
|
||||||
case FIT_TYPE_BIOS_INIT_MODULE:
|
case FIT_TYPE_BIOS_INIT_MODULE:
|
||||||
|
@ -57,7 +57,6 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index)
|
|||||||
|
|
||||||
bool isInvalid = false;
|
bool isInvalid = false;
|
||||||
bool isInvalidLink = false;
|
bool isInvalidLink = false;
|
||||||
//bool isDataOnly = false;
|
|
||||||
bool hasExtendedHeader = false;
|
bool hasExtendedHeader = false;
|
||||||
bool hasChecksum = false;
|
bool hasChecksum = false;
|
||||||
bool hasTimestamp = false;
|
bool hasTimestamp = false;
|
||||||
@ -113,7 +112,7 @@ USTATUS NvramParser::parseNvarStore(const UModelIndex & index)
|
|||||||
// Add GUID store area
|
// Add GUID store area
|
||||||
UByteArray guidArea = data.right(guidAreaSize);
|
UByteArray guidArea = data.right(guidAreaSize);
|
||||||
// Get info
|
// Get info
|
||||||
name = UString("GUID store area");
|
name = UString("GUID store");
|
||||||
info = usprintf("Full size: %Xh (%u)\nGUIDs in store: %u",
|
info = usprintf("Full size: %Xh (%u)\nGUIDs in store: %u",
|
||||||
guidArea.size(), guidArea.size(),
|
guidArea.size(), guidArea.size(),
|
||||||
guidsInStore);
|
guidsInStore);
|
||||||
@ -412,8 +411,7 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index)
|
|||||||
UINT32 storeOffset = prevStoreOffset;
|
UINT32 storeOffset = prevStoreOffset;
|
||||||
UINT32 prevStoreSize = 0;
|
UINT32 prevStoreSize = 0;
|
||||||
|
|
||||||
while (!result)
|
while (!result) {
|
||||||
{
|
|
||||||
// Padding between stores
|
// Padding between stores
|
||||||
if (storeOffset > prevStoreOffset + prevStoreSize) {
|
if (storeOffset > prevStoreOffset + prevStoreSize) {
|
||||||
UINT32 paddingOffset = prevStoreOffset + prevStoreSize;
|
UINT32 paddingOffset = prevStoreOffset + prevStoreSize;
|
||||||
@ -476,7 +474,6 @@ USTATUS NvramParser::parseNvramVolumeBody(const UModelIndex & index)
|
|||||||
info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size());
|
info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size());
|
||||||
|
|
||||||
if (padding.count(emptyByte) == padding.size()) { // Free space
|
if (padding.count(emptyByte) == padding.size()) { // Free space
|
||||||
|
|
||||||
// Add tree item
|
// Add tree item
|
||||||
model->addItem(localOffset + storeOffset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), padding, UByteArray(), Movable, index);
|
model->addItem(localOffset + storeOffset, Types::FreeSpace, 0, UString("Free space"), UString(), info, UByteArray(), padding, UByteArray(), Movable, index);
|
||||||
}
|
}
|
||||||
@ -781,7 +778,7 @@ USTATUS NvramParser::parseFtwStoreHeader(const UByteArray & store, const UINT32
|
|||||||
if (parentVolumeIndex.isValid() && model->hasEmptyParsingData(parentVolumeIndex) == false) {
|
if (parentVolumeIndex.isValid() && model->hasEmptyParsingData(parentVolumeIndex) == false) {
|
||||||
UByteArray data = model->parsingData(parentVolumeIndex);
|
UByteArray data = model->parsingData(parentVolumeIndex);
|
||||||
const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData();
|
const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData();
|
||||||
emptyByte = pdata->ffsVersion;
|
emptyByte = pdata->emptyByte;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get FTW block headers
|
// Get FTW block headers
|
||||||
@ -1185,7 +1182,7 @@ USTATUS NvramParser::parseIntelMicrocodeHeader(const UByteArray & store, const U
|
|||||||
|
|
||||||
// Add info
|
// Add info
|
||||||
UString name("Intel microcode");
|
UString name("Intel microcode");
|
||||||
UString info = usprintf("\nFull size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\n"
|
UString info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\n"
|
||||||
"Date: %08Xh\nCPU signature: %08Xh\nRevision: %08Xh\nChecksum: %08Xh\nLoader revision: %08Xh\nCPU flags: %08Xh",
|
"Date: %08Xh\nCPU signature: %08Xh\nRevision: %08Xh\nChecksum: %08Xh\nLoader revision: %08Xh\nCPU flags: %08Xh",
|
||||||
ucodeHeader->TotalSize, ucodeHeader->TotalSize,
|
ucodeHeader->TotalSize, ucodeHeader->TotalSize,
|
||||||
header.size(), header.size(),
|
header.size(), header.size(),
|
||||||
@ -1262,7 +1259,7 @@ USTATUS NvramParser::parseVssStoreBody(const UModelIndex & index)
|
|||||||
if (parentVolumeIndex.isValid() && model->hasEmptyParsingData(parentVolumeIndex) == false) {
|
if (parentVolumeIndex.isValid() && model->hasEmptyParsingData(parentVolumeIndex) == false) {
|
||||||
UByteArray data = model->parsingData(parentVolumeIndex);
|
UByteArray data = model->parsingData(parentVolumeIndex);
|
||||||
const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData();
|
const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData();
|
||||||
emptyByte = pdata->ffsVersion;
|
emptyByte = pdata->emptyByte;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get local offset
|
// Get local offset
|
||||||
@ -1553,7 +1550,7 @@ USTATUS NvramParser::parseEvsaStoreBody(const UModelIndex & index)
|
|||||||
if (parentVolumeIndex.isValid() && model->hasEmptyParsingData(parentVolumeIndex) == false) {
|
if (parentVolumeIndex.isValid() && model->hasEmptyParsingData(parentVolumeIndex) == false) {
|
||||||
UByteArray data = model->parsingData(parentVolumeIndex);
|
UByteArray data = model->parsingData(parentVolumeIndex);
|
||||||
const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData();
|
const VOLUME_PARSING_DATA* pdata = (const VOLUME_PARSING_DATA*)data.constData();
|
||||||
emptyByte = pdata->ffsVersion;
|
emptyByte = pdata->emptyByte;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get local offset
|
// Get local offset
|
||||||
|
Loading…
Reference in New Issue
Block a user