Merge branch 'master' of github.com:neutrinolabs/xrdp
This commit is contained in:
commit
e75767e4dd
@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "libxrdp.h"
|
||||
#include "xrdp_orders_rail.h"
|
||||
|
||||
/******************************************************************************/
|
||||
struct xrdp_session *EXPORT_CC
|
||||
|
@ -212,14 +212,17 @@ xrdp_orders_check(struct xrdp_orders *self, int max_size)
|
||||
}
|
||||
if (size > max_packet_size)
|
||||
{
|
||||
// this suggests someone calls this function without passing the correct
|
||||
// max_size so we end up putting more into the buffer than we indicate we can
|
||||
/* this suggests someone calls this function without passing the
|
||||
correct max_size so we end up putting more into the buffer
|
||||
than we indicate we can */
|
||||
g_writeln("error in xrdp_orders_check, size too big, its %d", size);
|
||||
// We where getting called with size allready greater than max_packet_size
|
||||
// Which I suspect was because the sending of text did not include the text len
|
||||
// to check the buffer size. So attempt to send the data anyway.
|
||||
// Lets write the data anyway, somewhere else may barf.
|
||||
// return 1;
|
||||
/* We where getting called with size already greater than
|
||||
max_packet_size
|
||||
Which I suspect was because the sending of text did not include
|
||||
the text len to check the buffer size. So attempt to send the data
|
||||
anyway.
|
||||
Lets write the data anyway, somewhere else may barf. */
|
||||
/* return 1; */
|
||||
}
|
||||
|
||||
if ((size + max_size + 100) > max_packet_size)
|
||||
@ -363,7 +366,8 @@ xrdp_orders_out_bounds(struct xrdp_orders *self, struct xrdp_rect *rect)
|
||||
/* right */
|
||||
if (bounds_flags & 0x04)
|
||||
{
|
||||
out_uint16_le(self->out_s, rect->right - 1); /* silly rdp right clip */
|
||||
/* silly rdp right clip */
|
||||
out_uint16_le(self->out_s, rect->right - 1);
|
||||
}
|
||||
else if (bounds_flags & 0x40)
|
||||
{
|
||||
@ -375,7 +379,8 @@ xrdp_orders_out_bounds(struct xrdp_orders *self, struct xrdp_rect *rect)
|
||||
/* bottom */
|
||||
if (bounds_flags & 0x08)
|
||||
{
|
||||
out_uint16_le(self->out_s, rect->bottom - 1); /* silly rdp bottom clip */
|
||||
/* silly rdp bottom clip */
|
||||
out_uint16_le(self->out_s, rect->bottom - 1);
|
||||
}
|
||||
else if (bounds_flags & 0x80)
|
||||
{
|
||||
@ -1184,8 +1189,8 @@ xrdp_orders_line(struct xrdp_orders *self, int mix_mode,
|
||||
|
||||
g_memset(&blank_pen, 0, sizeof(struct xrdp_pen));
|
||||
|
||||
/* if mix mode or rop are out of range, mstsc build 6000+ will parse the orders
|
||||
wrong */
|
||||
/* if mix mode or rop are out of range, mstsc build 6000+ will parse the
|
||||
orders wrong */
|
||||
if ((mix_mode < 1) || (mix_mode > 2)) /* TRANSPARENT(1) or OPAQUE(2) */
|
||||
{
|
||||
mix_mode = 1;
|
||||
@ -2336,8 +2341,8 @@ xrdp_orders_send_bitmap3(struct xrdp_orders *self,
|
||||
rfx_compose_message(context, fr_s, &rect, 1, (tui8 *)data, width,
|
||||
height, width * 4);
|
||||
bufsize = stream_get_length(fr_s);
|
||||
xrdp_orders_out_v3(self, cache_id, cache_idx, (char *)(fr_s->data), bufsize,
|
||||
width, height, bpp, ci->v3_codec_id);
|
||||
xrdp_orders_out_v3(self, cache_id, cache_idx, (char *)(fr_s->data),
|
||||
bufsize, width, height, bpp, ci->v3_codec_id);
|
||||
stream_detach(fr_s);
|
||||
stream_free(fr_s);
|
||||
free_stream(xr_s);
|
||||
|
@ -27,7 +27,7 @@
|
||||
#ifdef XRDP_DEBUG
|
||||
#define LOG_LEVEL 99
|
||||
#else
|
||||
#define LOG_LEVEL 0
|
||||
#define LOG_LEVEL 1
|
||||
#endif
|
||||
|
||||
#define LLOG(_level, _args) \
|
||||
@ -617,14 +617,19 @@ lfreerdp_pat_blt(rdpContext *context, PATBLT_ORDER *patblt)
|
||||
|
||||
server_bpp = mod->inst->settings->color_depth;
|
||||
client_bpp = mod->bpp;
|
||||
LLOGLN(0, ("lfreerdp_pat_blt: bpp %d %d", server_bpp, client_bpp));
|
||||
LLOGLN(10, ("lfreerdp_pat_blt: bpp %d %d", server_bpp, client_bpp));
|
||||
|
||||
fgcolor = convert_color(server_bpp, client_bpp,
|
||||
patblt->foreColor, mod->colormap);
|
||||
bgcolor = convert_color(server_bpp, client_bpp,
|
||||
patblt->backColor, mod->colormap);
|
||||
|
||||
if(fgcolor==bgcolor)
|
||||
LLOGLN(10, ("lfreerdp_pat_blt: nLeftRect %d nTopRect %d "
|
||||
"nWidth %d nHeight %d fgcolor 0x%8.8x bgcolor 0x%8.8x",
|
||||
patblt->nLeftRect, patblt->nTopRect,
|
||||
patblt->nWidth, patblt->nHeight, fgcolor, bgcolor));
|
||||
|
||||
if (fgcolor == bgcolor)
|
||||
{
|
||||
LLOGLN(0, ("Warning same color on both bg and fg"));
|
||||
}
|
||||
@ -691,6 +696,10 @@ lfreerdp_opaque_rect(rdpContext *context, OPAQUE_RECT_ORDER *opaque_rect)
|
||||
client_bpp = mod->bpp;
|
||||
fgcolor = convert_color(server_bpp, client_bpp,
|
||||
opaque_rect->color, mod->colormap);
|
||||
LLOGLN(10, ("lfreerdp_opaque_rect: nLeftRect %d nTopRect %d "
|
||||
"nWidth %d nHeight %d fgcolor 0x%8.8x",
|
||||
opaque_rect->nLeftRect, opaque_rect->nTopRect,
|
||||
opaque_rect->nWidth, opaque_rect->nHeight, fgcolor));
|
||||
mod->server_set_fgcolor(mod, fgcolor);
|
||||
mod->server_fill_rect(mod, opaque_rect->nLeftRect, opaque_rect->nTopRect,
|
||||
opaque_rect->nWidth, opaque_rect->nHeight);
|
||||
@ -749,6 +758,10 @@ lfreerdp_glyph_index(rdpContext *context, GLYPH_INDEX_ORDER *glyph_index)
|
||||
int client_bpp;
|
||||
int fgcolor;
|
||||
int bgcolor;
|
||||
int opLeft;
|
||||
int opTop;
|
||||
int opRight;
|
||||
int opBottom;
|
||||
|
||||
mod = ((struct mod_context *)context)->modi;
|
||||
LLOGLN(10, ("lfreerdp_glyph_index:"));
|
||||
@ -758,14 +771,39 @@ lfreerdp_glyph_index(rdpContext *context, GLYPH_INDEX_ORDER *glyph_index)
|
||||
glyph_index->foreColor, mod->colormap);
|
||||
bgcolor = convert_color(server_bpp, client_bpp,
|
||||
glyph_index->backColor, mod->colormap);
|
||||
LLOGLN(10, ("lfreerdp_glyph_index: "
|
||||
"bkLeft %d bkTop %d width %d height %d "
|
||||
"opLeft %d opTop %d width %d height %d "
|
||||
"cbData %d fgcolor 0x%8.8x bgcolor 0x%8.8x fOpRedundant %d",
|
||||
glyph_index->bkLeft, glyph_index->bkTop,
|
||||
glyph_index->bkRight - glyph_index->bkLeft,
|
||||
glyph_index->bkBottom - glyph_index->bkTop,
|
||||
glyph_index->opLeft, glyph_index->opTop,
|
||||
glyph_index->opRight - glyph_index->opLeft,
|
||||
glyph_index->opBottom - glyph_index->opTop,
|
||||
glyph_index->cbData, fgcolor, bgcolor, glyph_index->fOpRedundant));
|
||||
mod->server_set_bgcolor(mod, fgcolor);
|
||||
mod->server_set_fgcolor(mod, bgcolor);
|
||||
opLeft = glyph_index->opLeft;
|
||||
opTop = glyph_index->opTop;
|
||||
opRight = glyph_index->opRight;
|
||||
opBottom = glyph_index->opBottom;
|
||||
#if 1
|
||||
/* workarounds for freerdp not using fOpRedundant in
|
||||
glyph.c::update_gdi_glyph_index */
|
||||
if (glyph_index->fOpRedundant)
|
||||
{
|
||||
opLeft = glyph_index->bkLeft;
|
||||
opTop = glyph_index->bkTop;
|
||||
opRight = glyph_index->bkRight;
|
||||
opBottom =glyph_index->bkBottom;
|
||||
}
|
||||
#endif
|
||||
mod->server_draw_text(mod, glyph_index->cacheId, glyph_index->flAccel,
|
||||
glyph_index->fOpRedundant,
|
||||
glyph_index->bkLeft, glyph_index->bkTop,
|
||||
glyph_index->bkRight, glyph_index->bkBottom,
|
||||
glyph_index->opLeft, glyph_index->opTop,
|
||||
glyph_index->opRight, glyph_index->opBottom,
|
||||
opLeft, opTop, opRight, opBottom,
|
||||
glyph_index->x, glyph_index->y,
|
||||
(char *)(glyph_index->data), glyph_index->cbData);
|
||||
}
|
||||
@ -863,7 +901,7 @@ lfreerdp_cache_bitmapV2(rdpContext *context,
|
||||
|
||||
if (flags & 0x10) /* CBR2_DO_NOT_CACHE */
|
||||
{
|
||||
LLOGLN(0, ("lfreerdp_cache_bitmapV2: CBR2_DO_NOT_CACHE"));
|
||||
LLOGLN(10, ("lfreerdp_cache_bitmapV2: CBR2_DO_NOT_CACHE"));
|
||||
idx = 4096 - 1;
|
||||
}
|
||||
|
||||
@ -1049,6 +1087,13 @@ lfreerdp_get_pixel(void *bits, int width, int height, int bpp,
|
||||
pixel = (src8[start] & (0x80 >> shift)) != 0;
|
||||
return pixel ? 0xffffff : 0;
|
||||
}
|
||||
else if (bpp == 32)
|
||||
{
|
||||
src8 = (tui8 *)bits;
|
||||
src8 += y * delta + x * 4;
|
||||
pixel = ((int*)(src8))[0];
|
||||
return pixel;
|
||||
}
|
||||
else
|
||||
{
|
||||
LLOGLN(0, ("lfreerdp_get_pixel: unknown bpp %d", bpp));
|
||||
@ -1089,6 +1134,12 @@ lfreerdp_set_pixel(int pixel, void *bits, int width, int height, int bpp,
|
||||
dst8[1] = (pixel >> 8) & 0xff;
|
||||
dst8[2] = (pixel >> 16) & 0xff;
|
||||
}
|
||||
else if (bpp == 32)
|
||||
{
|
||||
dst8 = (tui8 *)bits;
|
||||
dst8 += y * delta + x * 4;
|
||||
((int*)(dst8))[0] = pixel;
|
||||
}
|
||||
else
|
||||
{
|
||||
LLOGLN(0, ("lfreerdp_set_pixel: unknown bpp %d", bpp));
|
||||
@ -1129,6 +1180,8 @@ lfreerdp_pointer_new(rdpContext *context,
|
||||
{
|
||||
struct mod *mod;
|
||||
int index;
|
||||
int bytes_per_pixel;
|
||||
int bits_per_pixel;
|
||||
tui8 *dst;
|
||||
tui8 *src;
|
||||
|
||||
@ -1143,40 +1196,47 @@ lfreerdp_pointer_new(rdpContext *context,
|
||||
pointer_new->colorPtrAttr.lengthAndMask));
|
||||
|
||||
index = pointer_new->colorPtrAttr.cacheIndex;
|
||||
if(index>=32)
|
||||
if (index >= 32)
|
||||
{
|
||||
LLOGLN(0,("pointer index too big"));
|
||||
LLOGLN(0, ("lfreerdp_pointer_new: pointer index too big"));
|
||||
return ;
|
||||
}
|
||||
// In this fix we remove the xorBpp check, even if
|
||||
// the mouse pointers are not correct we can use them.
|
||||
// Configure your destination not to use windows Aero as pointer scheme
|
||||
else if ( // pointer_new->xorBpp == 1 &&
|
||||
pointer_new->colorPtrAttr.width == 32 &&
|
||||
pointer_new->colorPtrAttr.height == 32 &&
|
||||
index < 32)
|
||||
if (pointer_new->xorBpp == 1 &&
|
||||
pointer_new->colorPtrAttr.width == 32 &&
|
||||
pointer_new->colorPtrAttr.height == 32)
|
||||
{
|
||||
LLOGLN(10, ("lfreerdp_pointer_new:"));
|
||||
mod->pointer_cache[index].hotx = pointer_new->colorPtrAttr.xPos;
|
||||
mod->pointer_cache[index].hoty = pointer_new->colorPtrAttr.yPos;
|
||||
|
||||
mod->pointer_cache[index].bpp = 0;
|
||||
dst = (tui8 *)(mod->pointer_cache[index].data);
|
||||
dst += 32 * 32 * 3 - 32 * 3;
|
||||
src = pointer_new->colorPtrAttr.xorMaskData;
|
||||
lfreerdp_convert_color_image(dst, 32, 32, 24, 32 * -3,
|
||||
src, 32, 32, 1, 32 / 8);
|
||||
|
||||
dst = (tui8 *)(mod->pointer_cache[index].mask);
|
||||
dst += ( 32 * 32 / 8) - (32 / 8);
|
||||
src = pointer_new->colorPtrAttr.andMaskData;
|
||||
lfreerdp_convert_color_image(dst, 32, 32, 1, 32 / -8,
|
||||
src, 32, 32, 1, 32 / 8);
|
||||
|
||||
//memcpy(mod->pointer_cache[index].mask,
|
||||
// pointer_new->colorPtrAttr.andMaskData, 32 * 32 / 8);
|
||||
|
||||
mod->server_set_pointer(mod, mod->pointer_cache[index].hotx,
|
||||
mod->pointer_cache[index].hoty, mod->pointer_cache[index].data,
|
||||
mod->pointer_cache[index].mask);
|
||||
}
|
||||
else if(pointer_new->xorBpp >= 8 &&
|
||||
pointer_new->colorPtrAttr.width == 32 &&
|
||||
pointer_new->colorPtrAttr.height == 32)
|
||||
{
|
||||
bytes_per_pixel = (pointer_new->xorBpp + 7) / 8;
|
||||
bits_per_pixel = pointer_new->xorBpp;
|
||||
LLOGLN(10, ("lfreerdp_pointer_new: bpp %d Bpp %d", bits_per_pixel,
|
||||
bytes_per_pixel));
|
||||
mod->pointer_cache[index].hotx = pointer_new->colorPtrAttr.xPos;
|
||||
mod->pointer_cache[index].hoty = pointer_new->colorPtrAttr.yPos;
|
||||
mod->pointer_cache[index].bpp = bits_per_pixel;
|
||||
memcpy(mod->pointer_cache[index].data,
|
||||
pointer_new->colorPtrAttr.xorMaskData,
|
||||
32 * 32 * bytes_per_pixel);
|
||||
memcpy(mod->pointer_cache[index].mask,
|
||||
pointer_new->colorPtrAttr.andMaskData,
|
||||
32 * (32 / 8));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1185,6 +1245,12 @@ lfreerdp_pointer_new(rdpContext *context,
|
||||
pointer_new->colorPtrAttr.height,index));
|
||||
}
|
||||
|
||||
mod->server_set_pointer_ex(mod, mod->pointer_cache[index].hotx,
|
||||
mod->pointer_cache[index].hoty,
|
||||
mod->pointer_cache[index].data,
|
||||
mod->pointer_cache[index].mask,
|
||||
mod->pointer_cache[index].bpp);
|
||||
|
||||
free(pointer_new->colorPtrAttr.xorMaskData);
|
||||
pointer_new->colorPtrAttr.xorMaskData = 0;
|
||||
free(pointer_new->colorPtrAttr.andMaskData);
|
||||
@ -1203,10 +1269,11 @@ lfreerdp_pointer_cached(rdpContext *context,
|
||||
mod = ((struct mod_context *)context)->modi;
|
||||
index = pointer_cached->cacheIndex;
|
||||
LLOGLN(10, ("lfreerdp_pointer_cached:%d", index));
|
||||
mod->server_set_pointer(mod, mod->pointer_cache[index].hotx,
|
||||
mod->pointer_cache[index].hoty,
|
||||
mod->pointer_cache[index].data,
|
||||
mod->pointer_cache[index].mask);
|
||||
mod->server_set_pointer_ex(mod, mod->pointer_cache[index].hotx,
|
||||
mod->pointer_cache[index].hoty,
|
||||
mod->pointer_cache[index].data,
|
||||
mod->pointer_cache[index].mask,
|
||||
mod->pointer_cache[index].bpp);
|
||||
}
|
||||
|
||||
static void DEFAULT_CC lfreerdp_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb)
|
||||
@ -1308,6 +1375,7 @@ lfreerdp_pre_connect(freerdp *instance)
|
||||
instance->settings->draw_nine_grid = 0;
|
||||
|
||||
instance->settings->glyph_cache = true;
|
||||
/* GLYPH_SUPPORT_FULL and GLYPH_SUPPORT_PARTIAL seem to be the same */
|
||||
instance->settings->glyphSupportLevel = GLYPH_SUPPORT_FULL;
|
||||
instance->settings->order_support[NEG_GLYPH_INDEX_INDEX] = 1;
|
||||
instance->settings->order_support[NEG_FAST_GLYPH_INDEX] = 0;
|
||||
|
@ -53,8 +53,9 @@ struct pointer_item
|
||||
{
|
||||
int hotx;
|
||||
int hoty;
|
||||
char data[32 * 32 * 3];
|
||||
char data[32 * 32 * 4];
|
||||
char mask[32 * 32 / 8];
|
||||
int bpp;
|
||||
};
|
||||
|
||||
#define CURRENT_MOD_VER 2
|
||||
@ -148,6 +149,8 @@ struct mod
|
||||
int (*server_monitored_desktop)(struct mod* mod,
|
||||
struct rail_monitored_desktop_order* mdo,
|
||||
int flags);
|
||||
int (*server_set_pointer_ex)(struct mod* mod, int x, int y, char* data,
|
||||
char* mask, int bpp);
|
||||
|
||||
long server_dumby[100 - 37]; /* align, 100 minus the number of server
|
||||
functions above */
|
||||
|
@ -314,6 +314,8 @@ process_message_channel_setup(struct stream *s)
|
||||
int index;
|
||||
int rv;
|
||||
struct chan_item *ci;
|
||||
struct chan_out_data *cod;
|
||||
struct chan_out_data *old_cod;
|
||||
|
||||
g_num_chan_items = 0;
|
||||
g_cliprdr_index = -1;
|
||||
@ -336,6 +338,25 @@ process_message_channel_setup(struct stream *s)
|
||||
g_memset(ci->name, 0, sizeof(ci->name));
|
||||
in_uint8a(s, ci->name, 8);
|
||||
in_uint16_le(s, ci->id);
|
||||
/* there might be leftover data from last session after reconnecting
|
||||
so free it */
|
||||
if (ci->head != 0)
|
||||
{
|
||||
cod = ci->head;
|
||||
while (1)
|
||||
{
|
||||
free_stream(cod->s);
|
||||
old_cod = cod;
|
||||
cod = cod->next;
|
||||
g_free(old_cod);
|
||||
if (ci->tail == old_cod)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ci->head = 0;
|
||||
ci->tail = 0;
|
||||
in_uint16_le(s, ci->flags);
|
||||
LOGM((LOG_LEVEL_DEBUG, "process_message_channel_setup: chan name '%s' "
|
||||
"id %d flags %8.8x", ci->name, ci->id, ci->flags));
|
||||
@ -386,6 +407,8 @@ process_message_channel_setup(struct stream *s)
|
||||
|
||||
if (g_rdpsnd_index >= 0)
|
||||
{
|
||||
/* gets reset to 1 by next send_data_from_chan_item */
|
||||
g_sent = 0; /* wait for response! */
|
||||
sound_init();
|
||||
}
|
||||
|
||||
|
@ -1490,6 +1490,14 @@ clipboard_data_in(struct stream *s, int chan_id, int chan_flags, int length,
|
||||
struct stream *ls;
|
||||
char *holdp;
|
||||
|
||||
if (!g_clip_up)
|
||||
{
|
||||
LOG(10, ("aborting clipboard_data_in - clipboard has not "
|
||||
"been initialized"));
|
||||
/* we return 0 here to indicate no protocol problem occured */
|
||||
return 0;
|
||||
}
|
||||
|
||||
LLOGLN(10, ("clipboard_data_in: chan_id %d "
|
||||
"chan_flags 0x%x length %d total_length %d "
|
||||
"in_request %d g_ins->size %d",
|
||||
|
@ -302,6 +302,7 @@ sound_send_wave_data_chunk(char *data, int data_bytes)
|
||||
if ((data_bytes < 4) || (data_bytes > 128 * 1024))
|
||||
{
|
||||
LOG(0, ("sound_send_wave_data_chunk: bad data_bytes %d", data_bytes));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* part one of 2 PDU wave info */
|
||||
|
@ -143,7 +143,7 @@ main(int argc, char **argv)
|
||||
enum logReturns error;
|
||||
int daemon = 1;
|
||||
int pid;
|
||||
char pid_s[8];
|
||||
char pid_s[32];
|
||||
char text[256];
|
||||
char pid_file[256];
|
||||
char cfg_file[256];
|
||||
@ -202,7 +202,8 @@ main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
error = g_file_read(fd, pid_s, 7);
|
||||
g_memset(pid_s, 0, sizeof(pid_s));
|
||||
error = g_file_read(fd, pid_s, 31);
|
||||
|
||||
if (-1 == error)
|
||||
{
|
||||
|
@ -4,6 +4,7 @@
|
||||
INCBASE = $(X11RDPBASE)/include
|
||||
LIBBASE = $(X11RDPBASE)/lib
|
||||
|
||||
INSTALL = /usr/bin/install -c
|
||||
XSRCBASE = ../build_dir/xorg-server-1.9.3
|
||||
|
||||
OBJS = rdpmain.o rdpdraw.o rdpinput.o rdpmisc.o rdpup.o rdprandr.o \
|
||||
@ -109,3 +110,6 @@ fbcmap.o: ../build_dir/xorg-server-1.9.3/fb/fbcmap.c
|
||||
|
||||
fbcmap_mi.o: ../build_dir/xorg-server-1.9.3/fb/fbcmap_mi.c
|
||||
$(CC) $(CFLAGS) -c ../build_dir/xorg-server-1.9.3/fb/fbcmap_mi.c
|
||||
|
||||
install: all
|
||||
$(INSTALL) X11rdp $(X11RDPBASE)/bin/X11rdp
|
||||
|
@ -534,6 +534,7 @@ lib_mod_process_orders(struct mod *mod, int type, struct stream *s)
|
||||
int width;
|
||||
int height;
|
||||
int fgcolor;
|
||||
int bgcolor;
|
||||
int opcode;
|
||||
char *bmpdata;
|
||||
char cur_data[32 * (32 * 3)];
|
||||
@ -594,6 +595,10 @@ lib_mod_process_orders(struct mod *mod, int type, struct stream *s)
|
||||
in_uint32_le(s, fgcolor);
|
||||
rv = mod->server_set_fgcolor(mod, fgcolor);
|
||||
break;
|
||||
case 13: /* server_set_bgcolor */
|
||||
in_uint32_le(s, bgcolor);
|
||||
rv = mod->server_set_bgcolor(mod, bgcolor);
|
||||
break;
|
||||
case 14:
|
||||
in_uint16_le(s, opcode);
|
||||
rv = mod->server_set_opcode(mod, opcode);
|
||||
|
Loading…
Reference in New Issue
Block a user