New alsaunmute utility
This commit is contained in:
parent
34adb91e53
commit
2351acf9f2
@ -4,17 +4,19 @@
|
||||
Summary: Advanced Linux Sound Architecture (ALSA) utilities
|
||||
Name: alsa-utils
|
||||
Version: %{version_pack}
|
||||
Release: 2
|
||||
Release: 3
|
||||
License: GPL
|
||||
Group: Applications/Multimedia
|
||||
URL: http://www.alsa-project.org/
|
||||
Source: ftp://ftp.alsa-project.org/pub/utils/alsa-utils-%{version_tar}%{?prever}.tar.bz2
|
||||
Source2: salsa.c
|
||||
Source3: alsacard.c
|
||||
Source4: alsaunmute.c
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
BuildRequires: alsa-lib-devel >= %{version}
|
||||
BuildRequires: ncurses-devel
|
||||
BuildRequires: gettext-devel
|
||||
BuildRequires: autoconf
|
||||
|
||||
|
||||
%description
|
||||
@ -30,6 +32,7 @@ autoreconf -f -i
|
||||
%{__make} %{?_smp_mflags}
|
||||
%{__cc} $RPM_OPT_FLAGS -o salsa %{SOURCE2} -lasound
|
||||
%{__cc} $RPM_OPT_FLAGS -o alsacard %{SOURCE3} -lasound
|
||||
%{__cc} $RPM_OPT_FLAGS -o alsaunmute %{SOURCE4} -lasound
|
||||
|
||||
%install
|
||||
%{__rm} -rf ${RPM_BUILD_ROOT}
|
||||
@ -44,6 +47,7 @@ ln -s ../../sbin/alsactl $RPM_BUILD_ROOT/%{_sbindir}/alsactl
|
||||
mkdir -p -m755 $RPM_BUILD_ROOT/etc/dev.d/sound
|
||||
install -m 755 salsa $RPM_BUILD_ROOT/etc/dev.d/sound/alsa.dev
|
||||
install -m 755 alsacard %{buildroot}%{_bindir}
|
||||
install -m 755 alsaunmute %{buildroot}%{_bindir}
|
||||
|
||||
%clean
|
||||
%{__rm} -rf $RPM_BUILD_ROOT
|
||||
@ -60,10 +64,12 @@ install -m 755 alsacard %{buildroot}%{_bindir}
|
||||
%{_mandir}/fr/man?/*
|
||||
/usr/share/sounds/alsa/*
|
||||
/usr/share/alsa/speaker-test/*
|
||||
%{_bindir}/alsacard
|
||||
|
||||
|
||||
%changelog
|
||||
* Thu Jul 11 2005 Martin Stransky <stransky@redhat.com> 1.0.9-3
|
||||
- New alsaunmute utility
|
||||
- Add autoconf to BuildRequires (#162483)
|
||||
|
||||
* Thu Jun 16 2005 Martin Stransky <stransky@redhat.com> 1.0.9-2
|
||||
- New upstream version
|
||||
|
||||
|
320
alsaunmute.c
Normal file
320
alsaunmute.c
Normal file
@ -0,0 +1,320 @@
|
||||
/* Copyright 2005 Red Hat, Inc.
|
||||
*
|
||||
* Portions extraced from various ALSA code:
|
||||
* Copyright (c) by Abramo Bagnara <abramo@alsa-project.org>
|
||||
* Jaroslav Kysela <perex@suse.cz>
|
||||
* Takashi Iwai <tiwai@suse.de>
|
||||
* Bernd Kaindl <bk@suse.de>
|
||||
* Jan ONDREJ (SAL) <ondrejj@salstar.sk>
|
||||
*
|
||||
* This software may be freely redistributed under the terms of the GNU
|
||||
* public license.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
#define TRUE (1==1)
|
||||
#define FALSE (1!=1)
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
typedef struct _CHANNEL {
|
||||
|
||||
char name[100];
|
||||
int play_volume;
|
||||
int play_switch;
|
||||
int rec_volume;
|
||||
int rec_switch;
|
||||
char driver[100];
|
||||
|
||||
} CHANNEL;
|
||||
|
||||
CHANNEL channels[] = {
|
||||
|
||||
// channel pl vol pl swt rec vol rec swt driver
|
||||
|
||||
{"Master", 75, 1, 0, 0, ""},
|
||||
{"Front", 75, 1, 0, 0, ""},
|
||||
{"PCM", 75, 1, 0, 0, ""},
|
||||
{"PCM-2", 75, 1, 0, 0, ""},
|
||||
{"Synth", 75, 1, 0, 0, ""},
|
||||
{"CD", 75, 1, 90, 1, ""},
|
||||
|
||||
// mute mic
|
||||
{"Mic", 0, 0, 0, 0, ""},
|
||||
|
||||
// Trident/YMFPCI/emu10k1
|
||||
{"Wave", 100, 1, 0, 0, ""},
|
||||
{"Music", 100, 1, 0, 0, ""},
|
||||
{"AC97", 100, 1, 0, 0, ""},
|
||||
|
||||
// CS4237B chipset
|
||||
{"Master Digital", 75, 1, 0, 0, ""},
|
||||
|
||||
// Envy24 chips with analog outs
|
||||
{"DAC", 75, 1, 0, 0, ""},
|
||||
|
||||
// Powermacs
|
||||
{"DRC Range", 75, 1, 0, 0, ""},
|
||||
|
||||
// some notebooks use headphone instead of master
|
||||
{"Headphone", 75, 1, 0, 0, ""},
|
||||
{"Playback", 100, 1, 0, 0, ""},
|
||||
|
||||
// turn off digital switches
|
||||
{"SB Live Analog/Digital Output Jack", 0, 0, 0, 0, ""},
|
||||
{"Audigy Analog/Digital Output Jack", 0, 0, 0, 0, ""},
|
||||
|
||||
// Specific config for ca0106
|
||||
{"Analog Front", 75, 1, 0, 0, "snd-ca0106"},
|
||||
{"Analog Rear", 75, 1, 0, 0, "snd-ca0106"},
|
||||
{"SPDIF Out", 0, 0, 0, 0, "snd-ca0106"},
|
||||
|
||||
// Specific config for snd-emu10k1
|
||||
{"Audigy Analog/Digital Output Jack", 0,1,0, 0, "snd-emu10k1"},
|
||||
{"IEC958 Optical Raw", 0, 0, 0, 0, "snd-emu10k1"},
|
||||
{"Tone", 0, 0, 0, 0, "snd-emu10k1"},
|
||||
|
||||
// Specific config for snd-intel8x0
|
||||
{"External Amplifier", 0, 1, 0, 0, "snd-intel8x0"},
|
||||
|
||||
// Specific config for snd-intel8x0 (xw8000)
|
||||
{"Master Mono", 75, 1, 0, 0, "snd-intel8x0"},
|
||||
|
||||
// Specific config for snd_ens1371
|
||||
{"IEC958", 0, 0, 0, 0, "snd-ens1371"}
|
||||
};
|
||||
|
||||
char * strlwr(char *a)
|
||||
{
|
||||
char *ret = a;
|
||||
|
||||
while (*a != '\0') {
|
||||
if (isupper (*a))
|
||||
*a = tolower (*a);
|
||||
a++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
CHANNEL * channel_find(const char *p_name, const char *p_driver) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(channels) / sizeof(channels[0]); i++)
|
||||
if (!strcmp(channels[i].driver, p_driver) && !strcmp(channels[i].name, p_name))
|
||||
return (channels + i);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int calc_volume(long min, long max, int percent)
|
||||
{
|
||||
return ((int)(min + ((max - min) / 100.0f) * percent));
|
||||
}
|
||||
|
||||
int unmute_card(int index, const char *p_driver)
|
||||
{
|
||||
CHANNEL *p_chan;
|
||||
long pmin, pmax;
|
||||
long rmin, rmax;
|
||||
int rc = 0;
|
||||
char card[32];
|
||||
char channel_name[500];
|
||||
int c,vol;
|
||||
|
||||
snd_mixer_t *handle;
|
||||
snd_mixer_selem_id_t *sid;
|
||||
snd_mixer_elem_t *elem;
|
||||
snd_mixer_selem_id_alloca(&sid);
|
||||
|
||||
if(verbose) {
|
||||
fprintf(stderr,"Unmuting %s...\n",p_driver ? p_driver : "");
|
||||
}
|
||||
|
||||
sprintf(card, "hw:%d", index);
|
||||
if ((rc = snd_mixer_open(&handle, 0)) < 0) {
|
||||
if(verbose) {
|
||||
fprintf(stderr,"%s: error file %s, line %d...\n",__FUNCTION__,__FILE__,__LINE__);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
if ((rc = snd_mixer_attach(handle, card)) < 0) {
|
||||
if(verbose) {
|
||||
fprintf(stderr,"%s: error file %s, line %d...\n",__FUNCTION__,__FILE__,__LINE__);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
if ((rc = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
|
||||
if(verbose) {
|
||||
fprintf(stderr,"%s: error file %s, line %d...\n",__FUNCTION__,__FILE__,__LINE__);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
rc = snd_mixer_load(handle);
|
||||
if (rc < 0) {
|
||||
if(verbose) {
|
||||
fprintf(stderr,"%s: error file %s, line %d...\n",__FUNCTION__,__FILE__,__LINE__);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (elem = snd_mixer_first_elem(handle); elem;
|
||||
elem = snd_mixer_elem_next(elem)) {
|
||||
|
||||
snd_mixer_selem_get_id(elem, sid);
|
||||
strncpy(channel_name,snd_mixer_selem_id_get_name(sid),500);
|
||||
channel_name[499] = '\0';
|
||||
p_chan = channel_find(strlwr(channel_name),p_driver);
|
||||
if (!p_chan)
|
||||
continue;
|
||||
|
||||
for (c = 0; c < SND_MIXER_SCHN_LAST; c++) {
|
||||
|
||||
if (snd_mixer_selem_has_capture_channel(elem, c)) {
|
||||
if (snd_mixer_selem_has_capture_switch(elem)) {
|
||||
snd_mixer_selem_set_capture_switch(elem, c, p_chan->rec_switch);
|
||||
if(verbose) {
|
||||
fprintf(stderr,"Cap. Switch %s(%d) to %d\n",p_chan->name,c,p_chan->rec_switch);
|
||||
}
|
||||
}
|
||||
if (snd_mixer_selem_has_capture_volume(elem)) {
|
||||
snd_mixer_selem_get_capture_volume_range(elem, &rmin, &rmax);
|
||||
vol = calc_volume(rmin, rmax,p_chan->rec_volume);
|
||||
snd_mixer_selem_set_capture_volume(elem, c, vol);
|
||||
if(verbose) {
|
||||
fprintf(stderr,"Cap. Volume %s(%d) to %d\n",p_chan->name,c,vol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (snd_mixer_selem_has_playback_channel(elem, c)) {
|
||||
if (snd_mixer_selem_has_playback_switch(elem)) {
|
||||
snd_mixer_selem_set_playback_switch(elem, c, p_chan->play_switch);
|
||||
if(verbose) {
|
||||
fprintf(stderr,"Play. Switch %s(%d) to %d\n",p_chan->name,c,p_chan->play_switch);
|
||||
}
|
||||
}
|
||||
if (snd_mixer_selem_has_playback_volume(elem)) {
|
||||
snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax);
|
||||
vol = calc_volume(pmin, pmax,p_chan->play_volume);
|
||||
snd_mixer_selem_set_playback_volume(elem, c, vol);
|
||||
if(verbose) {
|
||||
fprintf(stderr,"Play. Volume %s(%d) to %d\n",p_chan->name,c,vol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return(TRUE);
|
||||
|
||||
out:
|
||||
snd_mixer_close(handle);
|
||||
return rc;
|
||||
}
|
||||
|
||||
char * check_driver_name(char *p_name)
|
||||
{
|
||||
char *p_tmp = strchr(p_name,'-');
|
||||
if(p_tmp) {
|
||||
*p_tmp = '_';
|
||||
}
|
||||
return(p_name);
|
||||
}
|
||||
|
||||
#define PROC_MODULES "/proc/asound/modules"
|
||||
|
||||
static char driver_name[100];
|
||||
|
||||
const char * get_card_driver(int index)
|
||||
{
|
||||
FILE *f = fopen(PROC_MODULES,"r");
|
||||
char tmp[100];
|
||||
char *p_tmp;
|
||||
int id;
|
||||
|
||||
if(!f)
|
||||
return(NULL);
|
||||
|
||||
while(fgets(tmp,100,f)) {
|
||||
sscanf(tmp," %d %s",&id,driver_name);
|
||||
if(id == index) {
|
||||
return(check_driver_name(driver_name));
|
||||
}
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
void check_data(void)
|
||||
{
|
||||
char *p_tmp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(channels) / sizeof(channels[0]); i++) {
|
||||
strlwr(channels[i].name);
|
||||
check_driver_name(channels[i].driver);
|
||||
}
|
||||
}
|
||||
|
||||
void usage(char *p_name)
|
||||
{
|
||||
printf("Alsa Unmute utility, Copyright 2005 Red Hat, Inc.\n");
|
||||
printf("This software may be freely redistributed under the terms of the GNU\n");
|
||||
printf("public license.\n\n");
|
||||
|
||||
printf("usage: %s card_number [-v]\n\n", p_name);
|
||||
printf(" card_number - number of unmuted card\n");
|
||||
printf(" [-v] - verbose mode\n\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
Unmute specified card
|
||||
alsaunmute 0
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *p_driver;
|
||||
int index;
|
||||
|
||||
if (argc < 2) {
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
index = atoi(argv[1]);
|
||||
p_driver = get_card_driver(index);
|
||||
|
||||
if (argc == 3 && (!strcmp(argv[2],"-v") || !strcmp(argv[2],"-V"))) {
|
||||
verbose = TRUE;
|
||||
}
|
||||
|
||||
if(!p_driver) {
|
||||
fprintf(stderr,"Wrong card index %d...\n",index);
|
||||
return(1);
|
||||
}
|
||||
|
||||
if(verbose) {
|
||||
fprintf(stderr,"Card %d Driver %s...\n",index,p_driver);
|
||||
}
|
||||
|
||||
check_data();
|
||||
|
||||
// default settings for all cards
|
||||
unmute_card(index,"");
|
||||
|
||||
// specific setting for selected card_number
|
||||
unmute_card(index,p_driver);
|
||||
|
||||
return (0);
|
||||
}
|
186
salsa.c
186
salsa.c
@ -23,140 +23,88 @@
|
||||
|
||||
int get_card_number()
|
||||
{
|
||||
char *devname, *action;
|
||||
|
||||
action = getenv("ACTION");
|
||||
if (!action || strcmp(action,"add"))
|
||||
return -1;
|
||||
devname = getenv("DEVNAME");
|
||||
if (!devname)
|
||||
return -1;
|
||||
if (!strncmp(devname,"/dev/snd/controlC",17))
|
||||
return atoi(devname+17);
|
||||
if (!strncmp(devname,"/dev/snd/pcmC",13))
|
||||
return atoi(devname+13);
|
||||
return -1;
|
||||
char *devname, *action;
|
||||
|
||||
action = getenv("ACTION");
|
||||
if (!action || strcmp(action, "add"))
|
||||
return -1;
|
||||
devname = getenv("DEVNAME");
|
||||
if (!devname)
|
||||
return -1;
|
||||
if (!strncmp(devname, "/dev/snd/controlC", 17))
|
||||
return atoi(devname + 17);
|
||||
if (!strncmp(devname, "/dev/snd/pcmC", 13))
|
||||
return atoi(devname + 13);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int has_config(int index)
|
||||
{
|
||||
int rc = 0;
|
||||
snd_config_t *config, *control;
|
||||
snd_input_t *in;
|
||||
snd_ctl_t *handle;
|
||||
snd_ctl_card_info_t *info;
|
||||
const char *id;
|
||||
char path[32];
|
||||
|
||||
rc = snd_config_top(&config);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
rc = snd_input_stdio_open(&in, ALSA_CONFIG_PATH, "r");
|
||||
if (rc >= 0) {
|
||||
rc = snd_config_load(config, in);
|
||||
snd_input_close(in);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
}
|
||||
sprintf(path, "hw:%d", index);
|
||||
rc = snd_ctl_open(&handle, path, 0);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
snd_ctl_card_info_alloca(&info);
|
||||
rc = snd_ctl_card_info(handle, info);
|
||||
if (rc < 0)
|
||||
goto out_close;
|
||||
id = snd_ctl_card_info_get_id(info);
|
||||
rc = snd_config_searchv(config, &control, "state", id, "control", 0);
|
||||
int rc = 0;
|
||||
snd_config_t *config, *control;
|
||||
snd_input_t *in;
|
||||
snd_ctl_t *handle;
|
||||
snd_ctl_card_info_t *info;
|
||||
const char *id;
|
||||
char path[32];
|
||||
|
||||
rc = snd_config_top(&config);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
rc = snd_input_stdio_open(&in, ALSA_CONFIG_PATH, "r");
|
||||
if (rc >= 0) {
|
||||
rc = snd_config_load(config, in);
|
||||
snd_input_close(in);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
}
|
||||
sprintf(path, "hw:%d", index);
|
||||
rc = snd_ctl_open(&handle, path, 0);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
snd_ctl_card_info_alloca(&info);
|
||||
rc = snd_ctl_card_info(handle, info);
|
||||
if (rc < 0)
|
||||
goto out_close;
|
||||
id = snd_ctl_card_info_get_id(info);
|
||||
rc = snd_config_searchv(config, &control, "state", id, "control", 0);
|
||||
out_close:
|
||||
snd_ctl_close(handle);
|
||||
snd_ctl_close(handle);
|
||||
out:
|
||||
return !rc;
|
||||
|
||||
return !rc;
|
||||
|
||||
}
|
||||
|
||||
int run_alsactl(int index)
|
||||
{
|
||||
char *args[] = { "/sbin/alsactl", "restore", NULL, NULL };
|
||||
char num[10];
|
||||
|
||||
sprintf(num,"%d",index);
|
||||
args[2] = num;
|
||||
execv(args[0],args);
|
||||
return 1;
|
||||
char *args[] = { "/sbin/alsactl", "restore", NULL, NULL };
|
||||
char num[10];
|
||||
|
||||
sprintf(num, "%d", index);
|
||||
args[2] = num;
|
||||
execv(args[0], args);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int frob_mixer(int index)
|
||||
void frob_mixer(int index)
|
||||
{
|
||||
int rc = 0;
|
||||
char card[32];
|
||||
snd_mixer_t *handle;
|
||||
snd_mixer_selem_id_t *sid;
|
||||
snd_mixer_elem_t *elem;
|
||||
snd_mixer_selem_id_alloca(&sid);
|
||||
|
||||
sprintf(card,"hw:%d",index);
|
||||
if ((rc = snd_mixer_open(&handle, 0)) < 0) {
|
||||
return rc;
|
||||
}
|
||||
if ((rc = snd_mixer_attach(handle, card)) < 0) {
|
||||
goto out;
|
||||
}
|
||||
if ((rc = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
|
||||
goto out;
|
||||
}
|
||||
rc = snd_mixer_load(handle);
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
for (elem = snd_mixer_first_elem(handle); elem; elem = snd_mixer_elem_next(elem)) {
|
||||
long pmin, pmax;
|
||||
int c;
|
||||
|
||||
snd_mixer_selem_get_id(elem, sid);
|
||||
snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax);
|
||||
for (c = 0; c < SND_MIXER_SCHN_LAST; c++) {
|
||||
if (snd_mixer_selem_has_capture_channel(elem, c)) {
|
||||
if (snd_mixer_selem_has_capture_volume(elem))
|
||||
snd_mixer_selem_set_capture_volume(elem, c, 0);
|
||||
if (!strcmp(snd_mixer_selem_id_get_name(sid),"CD")) {
|
||||
if (snd_mixer_selem_has_capture_switch(elem))
|
||||
snd_mixer_selem_set_capture_switch(elem, c, 1);
|
||||
} else {
|
||||
if (snd_mixer_selem_has_capture_switch(elem))
|
||||
snd_mixer_selem_set_capture_switch(elem, c, 0);
|
||||
if (snd_mixer_selem_has_playback_switch(elem))
|
||||
snd_mixer_selem_set_playback_switch(elem, c, 0);
|
||||
if (snd_mixer_selem_has_playback_volume(elem))
|
||||
snd_mixer_selem_set_playback_volume(elem, c, 0);
|
||||
}
|
||||
}
|
||||
if (snd_mixer_selem_has_playback_channel(elem, c)) {
|
||||
if (!snd_mixer_selem_has_capture_channel(elem, c) ||
|
||||
!strcmp(snd_mixer_selem_id_get_name(sid),"CD") ||
|
||||
!strcmp(snd_mixer_selem_id_get_name(sid),"Wave")) {
|
||||
if (snd_mixer_selem_has_playback_switch(elem))
|
||||
snd_mixer_selem_set_playback_switch(elem, c, 1);
|
||||
if (snd_mixer_selem_has_playback_volume(elem))
|
||||
snd_mixer_selem_set_playback_volume(elem, c, pmin + (pmax - pmin) * 0.75);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
snd_mixer_close(handle);
|
||||
return rc;
|
||||
char tmp[100];
|
||||
snprintf(tmp, 100, "%d", index);
|
||||
tmp[99] = '\0';
|
||||
execl("//usr//bin//alsaunmute","//usr//bin//alsaunmute", tmp, "-v", NULL);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = get_card_number();
|
||||
if (i < 0)
|
||||
return 0;
|
||||
if (has_config(i))
|
||||
return run_alsactl(i);
|
||||
else
|
||||
return frob_mixer(i);
|
||||
int i;
|
||||
|
||||
i = get_card_number();
|
||||
if (i < 0)
|
||||
return 0;
|
||||
if (has_config(i))
|
||||
return run_alsactl(i);
|
||||
else
|
||||
frob_mixer(i);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user