mirror of
https://projects.vdr-developer.org/git/vdr-plugin-skindesigner.git
synced 2023-10-19 17:58:31 +02:00
implemented dvbapi service interface, added viewelement ecminfo in displaychannel
This commit is contained in:
parent
4fb0b9de22
commit
e7d8a193a7
2
HISTORY
2
HISTORY
@ -300,4 +300,6 @@ Version 0.4.3
|
|||||||
to compare strings in conditions
|
to compare strings in conditions
|
||||||
- fixed sort order in lastrecordings viewelement
|
- fixed sort order in lastrecordings viewelement
|
||||||
- added tokens for progressbars in displamenudefault
|
- added tokens for progressbars in displamenudefault
|
||||||
|
- implemented dvbapi service interface, added viewelement ecminfo
|
||||||
|
in displaychannel
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@ cSDDisplayChannel::cSDDisplayChannel(cTemplate *channelTemplate, bool WithInfo)
|
|||||||
channelChange = false;
|
channelChange = false;
|
||||||
initial = true;
|
initial = true;
|
||||||
devicesLast = cTimeMs::Now();
|
devicesLast = cTimeMs::Now();
|
||||||
|
currentChannelSid = -1;
|
||||||
|
isEncrypted = false;
|
||||||
|
|
||||||
channelView = new cDisplayChannelView(channelTemplate->GetRootView());
|
channelView = new cDisplayChannelView(channelTemplate->GetRootView());
|
||||||
if (!channelView->createOsd()) {
|
if (!channelView->createOsd()) {
|
||||||
@ -33,17 +35,20 @@ cSDDisplayChannel::~cSDDisplayChannel() {
|
|||||||
void cSDDisplayChannel::SetChannel(const cChannel *Channel, int Number) {
|
void cSDDisplayChannel::SetChannel(const cChannel *Channel, int Number) {
|
||||||
if (!doOutput)
|
if (!doOutput)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
channelChange = true;
|
channelChange = true;
|
||||||
groupSep = false;
|
groupSep = false;
|
||||||
|
|
||||||
cString ChannelNumber("");
|
cString ChannelNumber("");
|
||||||
cString ChannelName("");
|
cString ChannelName("");
|
||||||
cString ChannelID("");
|
cString ChannelID("");
|
||||||
|
currentChannelSid = -1;
|
||||||
|
isEncrypted = false;
|
||||||
|
|
||||||
if (Channel) {
|
if (Channel) {
|
||||||
ChannelName = Channel->Name() ? Channel->Name() : "";
|
ChannelName = Channel->Name() ? Channel->Name() : "";
|
||||||
ChannelID = Channel->GetChannelID().ToString();
|
ChannelID = Channel->GetChannelID().ToString();
|
||||||
|
currentChannelSid = Channel->Sid();
|
||||||
|
isEncrypted = Channel->Ca();
|
||||||
if (!Channel->GroupSep()) {
|
if (!Channel->GroupSep()) {
|
||||||
ChannelNumber = cString::sprintf("%d%s", Channel->Number(), Number ? "-" : "");
|
ChannelNumber = cString::sprintf("%d%s", Channel->Number(), Number ? "-" : "");
|
||||||
} else {
|
} else {
|
||||||
@ -54,12 +59,14 @@ void cSDDisplayChannel::SetChannel(const cChannel *Channel, int Number) {
|
|||||||
} else {
|
} else {
|
||||||
ChannelName = ChannelString(NULL, 0);
|
ChannelName = ChannelString(NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
channelView->ClearChannel();
|
channelView->ClearChannel();
|
||||||
channelView->ClearEPGInfo();
|
channelView->ClearEPGInfo();
|
||||||
channelView->ClearStatusIcons();
|
channelView->ClearStatusIcons();
|
||||||
channelView->ClearChannelGroups();
|
channelView->ClearChannelGroups();
|
||||||
channelView->ClearScraperContent();
|
channelView->ClearScraperContent();
|
||||||
channelView->ClearAudioInfo();
|
channelView->ClearAudioInfo();
|
||||||
|
channelView->ClearEncryptionInfo();
|
||||||
if (!groupSep) {
|
if (!groupSep) {
|
||||||
channelView->DrawChannel(ChannelNumber, ChannelName, ChannelID, (Number > 0)?true:false);
|
channelView->DrawChannel(ChannelNumber, ChannelName, ChannelID, (Number > 0)?true:false);
|
||||||
channelView->DrawProgressBarBack();
|
channelView->DrawProgressBarBack();
|
||||||
@ -189,6 +196,9 @@ void cSDDisplayChannel::Flush(void) {
|
|||||||
channelView->DrawDevices(initial);
|
channelView->DrawDevices(initial);
|
||||||
devicesLast = cTimeMs::Now();
|
devicesLast = cTimeMs::Now();
|
||||||
}
|
}
|
||||||
|
if (isEncrypted) {
|
||||||
|
channelView->DrawEncryptionInfo(currentChannelSid);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
channelView->ClearStatusIcons();
|
channelView->ClearStatusIcons();
|
||||||
channelView->ClearScreenResolution();
|
channelView->ClearScreenResolution();
|
||||||
|
@ -20,6 +20,8 @@ private:
|
|||||||
int currentLast;
|
int currentLast;
|
||||||
uint64_t devicesLast;
|
uint64_t devicesLast;
|
||||||
const cEvent *present;
|
const cEvent *present;
|
||||||
|
int currentChannelSid;
|
||||||
|
int isEncrypted;
|
||||||
void SetProgressBar(const cEvent *present);
|
void SetProgressBar(const cEvent *present);
|
||||||
public:
|
public:
|
||||||
cSDDisplayChannel(cTemplate *channelTemplate, bool WithInfo);
|
cSDDisplayChannel(cTemplate *channelTemplate, bool WithInfo);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<!ENTITY % functions SYSTEM "functions.dtd">
|
<!ENTITY % functions SYSTEM "functions.dtd">
|
||||||
|
|
||||||
<!ELEMENT displaychannel (background | channelinfo | epginfo | progressbar | progressbarback |
|
<!ELEMENT displaychannel (background | channelinfo | epginfo | progressbar | progressbarback |
|
||||||
statusinfo | audioinfo | screenresolution | channelgroup |
|
statusinfo | audioinfo | ecminfo | screenresolution | channelgroup |
|
||||||
signalquality | signalqualityback | devices | currentweather | scrapercontent |
|
signalquality | signalqualityback | devices | currentweather | scrapercontent |
|
||||||
datetime | time | message | customtokens)* >
|
datetime | time | message | customtokens)* >
|
||||||
<!ATTLIST displaychannel
|
<!ATTLIST displaychannel
|
||||||
@ -61,6 +61,12 @@
|
|||||||
condition CDATA #IMPLIED
|
condition CDATA #IMPLIED
|
||||||
>
|
>
|
||||||
|
|
||||||
|
<!ELEMENT ecminfo (area|areascroll)*>
|
||||||
|
<!ATTLIST ecminfo
|
||||||
|
debug CDATA #IMPLIED
|
||||||
|
condition CDATA #IMPLIED
|
||||||
|
>
|
||||||
|
|
||||||
<!ELEMENT screenresolution (area|areascroll)*>
|
<!ELEMENT screenresolution (area|areascroll)*>
|
||||||
<!ATTLIST screenresolution
|
<!ATTLIST screenresolution
|
||||||
debug CDATA #IMPLIED
|
debug CDATA #IMPLIED
|
||||||
|
@ -894,6 +894,7 @@ void cTemplateViewChannel::SetViewElements(void) {
|
|||||||
viewElementsAllowed.insert("progressbarback");
|
viewElementsAllowed.insert("progressbarback");
|
||||||
viewElementsAllowed.insert("statusinfo");
|
viewElementsAllowed.insert("statusinfo");
|
||||||
viewElementsAllowed.insert("audioinfo");
|
viewElementsAllowed.insert("audioinfo");
|
||||||
|
viewElementsAllowed.insert("ecminfo");
|
||||||
viewElementsAllowed.insert("screenresolution");
|
viewElementsAllowed.insert("screenresolution");
|
||||||
viewElementsAllowed.insert("signalquality");
|
viewElementsAllowed.insert("signalquality");
|
||||||
viewElementsAllowed.insert("signalqualityback");
|
viewElementsAllowed.insert("signalqualityback");
|
||||||
@ -936,6 +937,9 @@ string cTemplateViewChannel::GetViewElementName(eViewElement ve) {
|
|||||||
case veScreenResolution:
|
case veScreenResolution:
|
||||||
name = "Screen Resolution";
|
name = "Screen Resolution";
|
||||||
break;
|
break;
|
||||||
|
case veEcmInfo:
|
||||||
|
name = "ECM Info";
|
||||||
|
break;
|
||||||
case veSignalQuality:
|
case veSignalQuality:
|
||||||
name = "Signal Quality";
|
name = "Signal Quality";
|
||||||
break;
|
break;
|
||||||
@ -989,6 +993,8 @@ void cTemplateViewChannel::AddPixmap(string sViewElement, cTemplatePixmap *pix,
|
|||||||
ve = veStatusInfo;
|
ve = veStatusInfo;
|
||||||
} else if (!sViewElement.compare("audioinfo")) {
|
} else if (!sViewElement.compare("audioinfo")) {
|
||||||
ve = veAudioInfo;
|
ve = veAudioInfo;
|
||||||
|
} else if (!sViewElement.compare("ecminfo")) {
|
||||||
|
ve = veEcmInfo;
|
||||||
} else if (!sViewElement.compare("screenresolution")) {
|
} else if (!sViewElement.compare("screenresolution")) {
|
||||||
ve = veScreenResolution;
|
ve = veScreenResolution;
|
||||||
} else if (!sViewElement.compare("signalquality")) {
|
} else if (!sViewElement.compare("signalquality")) {
|
||||||
|
@ -41,6 +41,7 @@ enum eViewElement {
|
|||||||
veSignalQuality,
|
veSignalQuality,
|
||||||
veSignalQualityBack,
|
veSignalQualityBack,
|
||||||
veScraperContent,
|
veScraperContent,
|
||||||
|
veEcmInfo,
|
||||||
//DisplayMenu ViewElements
|
//DisplayMenu ViewElements
|
||||||
veHeader,
|
veHeader,
|
||||||
veButtons,
|
veButtons,
|
||||||
|
18
services/dvbapi.h
Normal file
18
services/dvbapi.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef __DVBAPISERVICES_H
|
||||||
|
#define __DVBAPISERVICES_H
|
||||||
|
|
||||||
|
struct sDVBAPIEcmInfo {
|
||||||
|
//in parameters
|
||||||
|
uint16_t sid;
|
||||||
|
//out parameters
|
||||||
|
uint16_t caid;
|
||||||
|
uint16_t pid;
|
||||||
|
uint32_t prid;
|
||||||
|
uint32_t ecmtime;
|
||||||
|
cString reader;
|
||||||
|
cString from;
|
||||||
|
cString protocol;
|
||||||
|
int8_t hops;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //__DVBAPISERVICES_H
|
@ -133,6 +133,24 @@
|
|||||||
<audioinfo>
|
<audioinfo>
|
||||||
</audioinfo>
|
</audioinfo>
|
||||||
|
|
||||||
|
<!-- Available Variables ecminfo:
|
||||||
|
{caid} id of currently used CA
|
||||||
|
{pid} pID
|
||||||
|
{prid} provider ID
|
||||||
|
{ecmtime} ecm time in ms
|
||||||
|
{hops} number of hops
|
||||||
|
{reader} name of used reader
|
||||||
|
{from} name of originating host
|
||||||
|
{protocol} used protocol of reader
|
||||||
|
-->
|
||||||
|
|
||||||
|
<ecminfo>
|
||||||
|
<area x="60%" y="95%" width="24%" height="5%" layer="4">
|
||||||
|
<drawtext x="0" y="5%" font="{semibold}" fontsize="40%" color="{clrWhite}" text="CAID: {caid} Reader: {reader}" />
|
||||||
|
<drawtext x="0" y="50%" font="{semibold}" fontsize="40%" color="{clrWhite}" text="ECM Time: {ecmtime} ms" />
|
||||||
|
</area>
|
||||||
|
</ecminfo>
|
||||||
|
|
||||||
<!-- Available Variables screenresolution:
|
<!-- Available Variables screenresolution:
|
||||||
{screenwidth} width of currently displayed channel in px
|
{screenwidth} width of currently displayed channel in px
|
||||||
{screenheight} height of currently displayed channel in px
|
{screenheight} height of currently displayed channel in px
|
||||||
@ -194,6 +212,7 @@
|
|||||||
{devices[channelid]} ID of the currently tuned channel
|
{devices[channelid]} ID of the currently tuned channel
|
||||||
{devices[source]} source of the currently tuned channel
|
{devices[source]} source of the currently tuned channel
|
||||||
-->
|
-->
|
||||||
|
<!--
|
||||||
<devices condition="{showdevices}">
|
<devices condition="{showdevices}">
|
||||||
<area x="56%" y="94%" width="28%" height="6%" layer="2">
|
<area x="56%" y="94%" width="28%" height="6%" layer="2">
|
||||||
<loop name="devices" x="0" y="0" orientation="horizontal" columnwidth="{areawidth}/{numdevices}" rowheight="{areaheight}">
|
<loop name="devices" x="0" y="0" orientation="horizontal" columnwidth="{areawidth}/{numdevices}" rowheight="{areaheight}">
|
||||||
@ -207,7 +226,7 @@
|
|||||||
</loop>
|
</loop>
|
||||||
</area>
|
</area>
|
||||||
</devices>
|
</devices>
|
||||||
|
-->
|
||||||
<!-- Available Variables scrapercontent:
|
<!-- Available Variables scrapercontent:
|
||||||
{posterpath} Full Path of Poster to use in image path attribute
|
{posterpath} Full Path of Poster to use in image path attribute
|
||||||
{posterwidth} width of poster in pixel
|
{posterwidth} width of poster in pixel
|
||||||
|
@ -71,6 +71,18 @@
|
|||||||
<audioinfo>
|
<audioinfo>
|
||||||
</audioinfo>
|
</audioinfo>
|
||||||
|
|
||||||
|
<!-- Available Variables ecminfo:
|
||||||
|
{caid} id of currently used CA
|
||||||
|
{pid} pID
|
||||||
|
{prid} provider ID
|
||||||
|
{ecmtime} ecm time in ms
|
||||||
|
{hops} number of hops
|
||||||
|
{reader} name of used reader
|
||||||
|
{from} name of originating host
|
||||||
|
{protocol} used protocol of reader
|
||||||
|
-->
|
||||||
|
<ecminfo>
|
||||||
|
</ecminfo>
|
||||||
|
|
||||||
<!-- Available Variables screenresolution:
|
<!-- Available Variables screenresolution:
|
||||||
{screenwidth} width of currently displayed channel in px
|
{screenwidth} width of currently displayed channel in px
|
||||||
|
@ -282,6 +282,23 @@ void cDisplayChannelView::ClearAudioInfo(void) {
|
|||||||
ClearViewElement(veAudioInfo);
|
ClearViewElement(veAudioInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cDisplayChannelView::DrawEncryptionInfo(int channelSid) {
|
||||||
|
if (!ExecuteViewElement(veEcmInfo)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
map < string, int > intTokens;
|
||||||
|
map < string, string > stringTokens;
|
||||||
|
|
||||||
|
if (SetEcmInfos(channelSid, stringTokens, intTokens)) {
|
||||||
|
ClearEncryptionInfo();
|
||||||
|
DrawViewElement(veEcmInfo, &stringTokens, &intTokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDisplayChannelView::ClearEncryptionInfo(void) {
|
||||||
|
ClearViewElement(veEcmInfo);
|
||||||
|
}
|
||||||
|
|
||||||
void cDisplayChannelView::DrawScreenResolution(void) {
|
void cDisplayChannelView::DrawScreenResolution(void) {
|
||||||
if (!ExecuteViewElement(veScreenResolution)) {
|
if (!ExecuteViewElement(veScreenResolution)) {
|
||||||
return;
|
return;
|
||||||
|
@ -34,6 +34,8 @@ public:
|
|||||||
void ClearStatusIcons(void);
|
void ClearStatusIcons(void);
|
||||||
void DrawAudioInfo(void);
|
void DrawAudioInfo(void);
|
||||||
void ClearAudioInfo(void);
|
void ClearAudioInfo(void);
|
||||||
|
void DrawEncryptionInfo(int channelSid);
|
||||||
|
void ClearEncryptionInfo(void);
|
||||||
void DrawScreenResolution(void);
|
void DrawScreenResolution(void);
|
||||||
void ClearScreenResolution(void);
|
void ClearScreenResolution(void);
|
||||||
void DrawScraperContent(const cEvent *event);
|
void DrawScraperContent(const cEvent *event);
|
||||||
|
@ -21,6 +21,11 @@ cViewHelpers::cViewHelpers(void) {
|
|||||||
lastMinute = -1;
|
lastMinute = -1;
|
||||||
lastSystemLoad = 0.0;
|
lastSystemLoad = 0.0;
|
||||||
lastMemUsage = -1;
|
lastMemUsage = -1;
|
||||||
|
lastEcmInfo.hops = -1;
|
||||||
|
lastEcmInfo.ecmtime = -1;
|
||||||
|
lastEcmInfo.caid = -1;
|
||||||
|
lastEcmInfo.pid = -1;
|
||||||
|
lastEcmInfo.prid = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cViewHelpers::~cViewHelpers() {
|
cViewHelpers::~cViewHelpers() {
|
||||||
@ -855,6 +860,55 @@ void cViewHelpers::SetCurrentSchedule(string recName, map < string, string > &st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cViewHelpers::SetEcmInfos(int channelSid, map < string, string > &stringTokens, map < string, int > &intTokens) {
|
||||||
|
static cPlugin *pDVBApi = cPluginManager::GetPlugin("dvbapi");
|
||||||
|
if (!pDVBApi)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sDVBAPIEcmInfo ecmInfo;
|
||||||
|
ecmInfo.sid = channelSid;
|
||||||
|
|
||||||
|
if (!pDVBApi->Service("GetEcmInfo", &ecmInfo)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ecmInfo.hops < 0 || ecmInfo.ecmtime <= 0)
|
||||||
|
return false;
|
||||||
|
if (CompareECMInfos(&ecmInfo))
|
||||||
|
return false;
|
||||||
|
lastEcmInfo = ecmInfo;
|
||||||
|
|
||||||
|
intTokens.insert(pair<string,int>("caid", ecmInfo.caid));
|
||||||
|
intTokens.insert(pair<string,int>("pid", ecmInfo.pid));
|
||||||
|
intTokens.insert(pair<string,int>("prid", ecmInfo.prid));
|
||||||
|
intTokens.insert(pair<string,int>("ecmtime", ecmInfo.ecmtime));
|
||||||
|
intTokens.insert(pair<string,int>("hops", ecmInfo.hops));
|
||||||
|
|
||||||
|
stringTokens.insert(pair<string,string>("reader", *ecmInfo.reader ? *ecmInfo.reader : ""));
|
||||||
|
stringTokens.insert(pair<string,string>("from", *ecmInfo.from ? *ecmInfo.from : ""));
|
||||||
|
stringTokens.insert(pair<string,string>("protocol", *ecmInfo.protocol ? *ecmInfo.protocol : ""));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cViewHelpers::CompareECMInfos(sDVBAPIEcmInfo *ecmInfo) {
|
||||||
|
if (ecmInfo->caid != lastEcmInfo.caid)
|
||||||
|
return false;
|
||||||
|
if (ecmInfo->pid != lastEcmInfo.pid)
|
||||||
|
return false;
|
||||||
|
if (ecmInfo->prid != lastEcmInfo.prid)
|
||||||
|
return false;
|
||||||
|
if (ecmInfo->ecmtime != lastEcmInfo.ecmtime)
|
||||||
|
return false;
|
||||||
|
if (ecmInfo->hops != lastEcmInfo.hops)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
* Private Functions
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
void cViewHelpers::RecName(string &path, string &name, string &folder) {
|
void cViewHelpers::RecName(string &path, string &name, string &folder) {
|
||||||
size_t delim = path.find_last_of('~');
|
size_t delim = path.find_last_of('~');
|
||||||
if (delim == string::npos) {
|
if (delim == string::npos) {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#ifndef __VIEWHELPERS_H
|
#ifndef __VIEWHELPERS_H
|
||||||
#define __VIEWHELPERS_H
|
#define __VIEWHELPERS_H
|
||||||
|
|
||||||
|
#include "../services/dvbapi.h"
|
||||||
|
|
||||||
class cViewHelpers {
|
class cViewHelpers {
|
||||||
private:
|
private:
|
||||||
int numDevices;
|
int numDevices;
|
||||||
@ -15,10 +17,12 @@ private:
|
|||||||
int lastMinute;
|
int lastMinute;
|
||||||
double lastSystemLoad;
|
double lastSystemLoad;
|
||||||
int lastMemUsage;
|
int lastMemUsage;
|
||||||
|
sDVBAPIEcmInfo lastEcmInfo;
|
||||||
void RecName(string &path, string &name, string &folder);
|
void RecName(string &path, string &name, string &folder);
|
||||||
void RecPoster(const cRecording *rec, int &posterWidth, int &posterHeight, string &path, bool &hasPoster);
|
void RecPoster(const cRecording *rec, int &posterWidth, int &posterHeight, string &path, bool &hasPoster);
|
||||||
void SetCurrentScheduleFromChannel(const cChannel *channel, map < string, string > &stringTokens, map < string, int > &intTokens);
|
void SetCurrentScheduleFromChannel(const cChannel *channel, map < string, string > &stringTokens, map < string, int > &intTokens);
|
||||||
void SetCurrentScheduleFromRecording(const cRecording *recording, map < string, string > &stringTokens, map < string, int > &intTokens);
|
void SetCurrentScheduleFromRecording(const cRecording *recording, map < string, string > &stringTokens, map < string, int > &intTokens);
|
||||||
|
bool CompareECMInfos(sDVBAPIEcmInfo *ecmInfo);
|
||||||
protected:
|
protected:
|
||||||
void InitDevices(void);
|
void InitDevices(void);
|
||||||
bool SetDevices(bool initial, bool light, map<string,int> *intTokens, vector<map<string,string> > *devices);
|
bool SetDevices(bool initial, bool light, map<string,int> *intTokens, vector<map<string,string> > *devices);
|
||||||
@ -37,6 +41,7 @@ protected:
|
|||||||
bool SetSystemMemory(map < string, string > &stringTokens, map < string, int > &intTokens);
|
bool SetSystemMemory(map < string, string > &stringTokens, map < string, int > &intTokens);
|
||||||
bool SetSystemTemperatures(map < string, string > &stringTokens, map < string, int > &intTokens);
|
bool SetSystemTemperatures(map < string, string > &stringTokens, map < string, int > &intTokens);
|
||||||
void SetCurrentSchedule(string recName, map < string, string > &stringTokens, map < string, int > &intTokens);
|
void SetCurrentSchedule(string recName, map < string, string > &stringTokens, map < string, int > &intTokens);
|
||||||
|
bool SetEcmInfos(int channelSid, map < string, string > &stringTokens, map < string, int > &intTokens);
|
||||||
public:
|
public:
|
||||||
cViewHelpers(void);
|
cViewHelpers(void);
|
||||||
virtual ~cViewHelpers(void);
|
virtual ~cViewHelpers(void);
|
||||||
|
Loading…
Reference in New Issue
Block a user