From 45fc9f32c8fe29d9b51685c750d0632ece7c2982 Mon Sep 17 00:00:00 2001 From: Antenore Gatta Date: Wed, 6 Sep 2023 12:09:28 +0000 Subject: Automatic doc build by remmina-ci --- public/rdp__cliprdr_8c_source.html | 6 +-- public/rdp__event_8c.html | 52 +++++++++---------- public/rdp__event_8c_source.html | 54 +++++++++---------- public/rdp__event_8h.html | 14 ++--- public/rdp__event_8h_source.html | 14 ++--- public/rdp__graphics_8c_source.html | 2 +- public/rdp__plugin_8c.html | 100 ++++++++++++++++++------------------ public/rdp__plugin_8c_source.html | 82 ++++++++++++++--------------- 8 files changed, 163 insertions(+), 161 deletions(-) diff --git a/public/rdp__cliprdr_8c_source.html b/public/rdp__cliprdr_8c_source.html index 42087d1d9..a8b02577c 100644 --- a/public/rdp__cliprdr_8c_source.html +++ b/public/rdp__cliprdr_8c_source.html @@ -104,7 +104,7 @@ $(document).ready(function(){initNavTree('rdp__cliprdr_8c_source.html','');});
int timeval_diff(struct timeval *start, struct timeval *end)
Definition: rdp_cliprdr.c:417
pthread_mutex_t srv_data_mutex
Definition: rdp_plugin.h:146
void remmina_rdp_clipboard_abort_client_format_data_request(rfContext *rfi)
Definition: rdp_cliprdr.c:947
-
void * remmina_rdp_event_queue_ui_sync_retptr(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1472
+
void * remmina_rdp_event_queue_ui_sync_retptr(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1475
static UINT remmina_rdp_cliprdr_server_format_data_request(CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest)
Definition: rdp_cliprdr.c:396
rfClipboard * clipboard
Definition: rdp_plugin.h:297
static void crlf2lf(UINT8 *data, size_t *size)
Definition: rdp_cliprdr.c:124
@@ -126,11 +126,11 @@ $(document).ready(function(){initNavTree('rdp__cliprdr_8c_source.html','');});
static void remmina_rdp_cliprdr_mt_get_format_list(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_cliprdr.c:773
Definition: rdp_plugin.h:237
GtkWidget * drawing_area
Definition: rdp_plugin.h:355
-
int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1460
+
int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1463
int remmina_rdp_cliprdr_server_file_contents_request(CliprdrClientContext *context, CLIPRDR_FILE_CONTENTS_REQUEST *fileContentsRequest)
Definition: rdp_cliprdr.c:146
static void remmina_rdp_cliprdr_send_client_capabilities(rfClipboard *clipboard)
Definition: rdp_cliprdr.c:184
-
void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1454
+
void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1457
Definition: rdp_plugin.h:243
struct remmina_plugin_rdp_event::@42::@46 clipboard_formatlist
void remmina_rdp_cliprdr_empty_clipboard(GtkClipboard *gtkClipboard, rfClipboard *clipboard)
Definition: rdp_cliprdr.c:703
diff --git a/public/rdp__event_8c.html b/public/rdp__event_8c.html index 5eb46fa7c..a5be2650d 100644 --- a/public/rdp__event_8c.html +++ b/public/rdp__event_8c.html @@ -257,7 +257,7 @@ Functions
-

Definition at line 1161 of file rdp_event.c.

+

Definition at line 1164 of file rdp_event.c.

@@ -285,7 +285,7 @@ Functions
-

Definition at line 1092 of file rdp_event.c.

+

Definition at line 1095 of file rdp_event.c.

@@ -323,7 +323,7 @@ Functions
-

Definition at line 1190 of file rdp_event.c.

+

Definition at line 1193 of file rdp_event.c.

@@ -361,7 +361,7 @@ Functions
-

Definition at line 1266 of file rdp_event.c.

+

Definition at line 1269 of file rdp_event.c.

@@ -457,7 +457,7 @@ Functions
-

Definition at line 1221 of file rdp_event.c.

+

Definition at line 1224 of file rdp_event.c.

@@ -487,7 +487,7 @@ Functions
-

Definition at line 1025 of file rdp_event.c.

+

Definition at line 1028 of file rdp_event.c.

@@ -508,7 +508,7 @@ Functions

Fixme: This comment needed for TS_SUPPRESS_OUTPUT_PDU But it works only when we stay in the same window mode, if we switch to fullscreen, for instance, the object refernce is lost, so we loose these events.

-

Definition at line 909 of file rdp_event.c.

+

Definition at line 912 of file rdp_event.c.

@@ -546,7 +546,7 @@ Functions
-

Definition at line 729 of file rdp_event.c.

+

Definition at line 732 of file rdp_event.c.

@@ -590,7 +590,7 @@ Functions
-

Definition at line 602 of file rdp_event.c.

+

Definition at line 605 of file rdp_event.c.

@@ -626,7 +626,7 @@ Functions
-

Definition at line 870 of file rdp_event.c.

+

Definition at line 873 of file rdp_event.c.

@@ -802,7 +802,7 @@ Functions
-

Definition at line 763 of file rdp_event.c.

+

Definition at line 766 of file rdp_event.c.

@@ -910,7 +910,7 @@ Functions
-

Definition at line 673 of file rdp_event.c.

+

Definition at line 676 of file rdp_event.c.

@@ -968,7 +968,7 @@ Functions
-

Definition at line 1329 of file rdp_event.c.

+

Definition at line 1332 of file rdp_event.c.

@@ -1006,7 +1006,7 @@ Functions
-

Definition at line 1342 of file rdp_event.c.

+

Definition at line 1345 of file rdp_event.c.

@@ -1034,7 +1034,7 @@ Functions
-

Definition at line 1375 of file rdp_event.c.

+

Definition at line 1378 of file rdp_event.c.

@@ -1072,7 +1072,7 @@ Functions
-

Definition at line 1406 of file rdp_event.c.

+

Definition at line 1409 of file rdp_event.c.

@@ -1102,7 +1102,7 @@ Functions
-

Definition at line 1454 of file rdp_event.c.

+

Definition at line 1457 of file rdp_event.c.

@@ -1132,7 +1132,7 @@ Functions
-

Definition at line 1460 of file rdp_event.c.

+

Definition at line 1463 of file rdp_event.c.

@@ -1162,7 +1162,7 @@ Functions
-

Definition at line 1472 of file rdp_event.c.

+

Definition at line 1475 of file rdp_event.c.

@@ -1200,7 +1200,7 @@ Functions
-

Definition at line 1182 of file rdp_event.c.

+

Definition at line 1185 of file rdp_event.c.

@@ -1442,7 +1442,7 @@ Functions
-

Definition at line 1228 of file rdp_event.c.

+

Definition at line 1231 of file rdp_event.c.

@@ -1518,7 +1518,7 @@ Functions
-

Definition at line 1309 of file rdp_event.c.

+

Definition at line 1312 of file rdp_event.c.

@@ -1538,7 +1538,7 @@ Functions
-

Definition at line 1041 of file rdp_event.c.

+

Definition at line 1044 of file rdp_event.c.

@@ -1636,7 +1636,7 @@ Functions
-

Definition at line 1115 of file rdp_event.c.

+

Definition at line 1118 of file rdp_event.c.

@@ -1722,7 +1722,7 @@ Functions
-

Definition at line 1319 of file rdp_event.c.

+

Definition at line 1322 of file rdp_event.c.

@@ -1760,7 +1760,7 @@ Functions
-

Definition at line 1303 of file rdp_event.c.

+

Definition at line 1306 of file rdp_event.c.

diff --git a/public/rdp__event_8c_source.html b/public/rdp__event_8c_source.html index 1e98d8f16..c7b27677e 100644 --- a/public/rdp__event_8c_source.html +++ b/public/rdp__event_8c_source.html @@ -86,18 +86,18 @@ $(document).ready(function(){initNavTree('rdp__event_8c_source.html','');});
rdp_event.c
-Go to the documentation of this file.
1 /*
2  * Remmina - The GTK Remote Desktop Client
3  * Copyright (C) 2010 Jay Sorg
4  * Copyright (C) 2010-2011 Vic Lee
5  * Copyright (C) 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
7  * Copyright (C) 2016-2022 Antenore Gatta, Giovanni Panozzo
8  * Copyright (C) 2022-2023 Antenore Gatta, Giovanni Panozzo, Hiroyuki Tanaka
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  *
25  * In addition, as a special exception, the copyright holders give
26  * permission to link the code of portions of this program with the
27  * OpenSSL library under certain conditions as described in each
28  * individual source file, and distribute linked combinations
29  * including the two.
30  * You must obey the GNU General Public License in all respects
31  * for all of the code used other than OpenSSL. * If you modify
32  * file(s) with this exception, you may extend this exception to your
33  * version of the file(s), but you are not obligated to do so. * If you
34  * do not wish to do so, delete this exception statement from your
35  * version. * If you delete this exception statement from all source
36  * files in the program, then also delete it here.
37  *
38  */
39 
40 #include "rdp_cliprdr.h"
41 #include "rdp_event.h"
42 #include "rdp_monitor.h"
43 #include "rdp_settings.h"
44 #include <gdk/gdkkeysyms.h>
45 #ifdef GDK_WINDOWING_X11
46 #include <cairo/cairo-xlib.h>
47 #else
48 #include <cairo/cairo.h>
49 #endif
50 #include <freerdp/locale/keyboard.h>
51 
53 {
54  TRACE_CALL(__func__);
55  rfContext *rfi = GET_PLUGIN_DATA(gp);
56  rdpGdi *gdi;
57 
58  if (rfi == NULL)
59  return false;
60 
62  int do_suppress = !remmina_plugin_service->file_get_int(remminafile, "no-suppress", FALSE);
63 
64  if (do_suppress) {
65  gdi = ((rdpContext *)rfi)->gdi;
66 
67  REMMINA_PLUGIN_DEBUG("Map event received, disabling TS_SUPPRESS_OUTPUT_PDU ");
68  gdi_send_suppress_output(gdi, FALSE);
69  }
70 
71  return FALSE;
72 }
73 
75 {
76  TRACE_CALL(__func__);
77  rfContext *rfi = GET_PLUGIN_DATA(gp);
78  rdpGdi *gdi;
79 
80  if (rfi == NULL)
81  return false;
82 
83  GtkWidget *toplevel = gtk_widget_get_toplevel(GTK_WIDGET(gp));
84  GdkWindow *window = gtk_widget_get_window(toplevel);
85 
86  if (gdk_window_get_fullscreen_mode(window) == GDK_FULLSCREEN_ON_ALL_MONITORS) {
87  REMMINA_PLUGIN_DEBUG("Unmap event received, but cannot enable TS_SUPPRESS_OUTPUT_PDU when in fullscreen");
88  return FALSE;
89  }
90 
92  int do_suppress = !remmina_plugin_service->file_get_int(remminafile, "no-suppress", FALSE);
93 
94  if (do_suppress) {
95  gdi = ((rdpContext *)rfi)->gdi;
96 
97  REMMINA_PLUGIN_DEBUG("Unmap event received, enabling TS_SUPPRESS_OUTPUT_PDU ");
98  gdi_send_suppress_output(gdi, TRUE);
99  }
100 
101  return FALSE;
102 }
103 
104 static gboolean remmina_rdp_event_on_focus_in(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
105 {
106  TRACE_CALL(__func__);
107 
108  rfContext *rfi = GET_PLUGIN_DATA(gp);
109  rdpInput *input;
110  GdkModifierType state;
111 
112 #if GTK_CHECK_VERSION(3, 20, 0)
113  GdkSeat *seat;
114 #else
115  GdkDeviceManager *manager;
116 #endif
117  GdkDevice *keyboard = NULL;
118 
119  const gchar *wname = gtk_widget_get_name(gtk_widget_get_toplevel(widget));
120  REMMINA_PLUGIN_DEBUG("Top level name is: %s", wname);
121 
122  if (!rfi || !rfi->connected || rfi->is_reconnecting)
123  return FALSE;
124 
125  input = rfi->instance->input;
126  UINT32 toggle_keys_state = 0;
127 
128 #if GTK_CHECK_VERSION(3, 20, 0)
129  seat = gdk_display_get_default_seat(gdk_display_get_default());
130  keyboard = gdk_seat_get_pointer(seat);
131 #else
132  manager = gdk_display_get_device_manager(gdk_display_get_default());
133  keyboard = gdk_device_manager_get_client_pointer(manager);
134 #endif
135  gdk_window_get_device_position(gdk_get_default_root_window(), keyboard, NULL, NULL, &state);
136 
137  if (state & GDK_LOCK_MASK)
138  toggle_keys_state |= KBD_SYNC_CAPS_LOCK;
139  if (state & GDK_MOD2_MASK)
140  toggle_keys_state |= KBD_SYNC_NUM_LOCK;
141  if (state & GDK_MOD5_MASK)
142  toggle_keys_state |= KBD_SYNC_SCROLL_LOCK;
143 
144  input->SynchronizeEvent(input, toggle_keys_state);
145  input->KeyboardEvent(input, KBD_FLAGS_RELEASE, 0x0F);
146 
147  return FALSE;
148 }
149 
151 {
152  TRACE_CALL(__func__);
153  rfContext *rfi = GET_PLUGIN_DATA(gp);
154  RemminaPluginRdpEvent *event;
155 
156  /* Called by the main GTK thread to send an event to the libfreerdp thread */
157 
158  if (!rfi || !rfi->connected || rfi->is_reconnecting)
159  return;
160 
161  if (rfi->event_queue) {
162 #if GLIB_CHECK_VERSION(2,67,3)
163  event = g_memdup2(e, sizeof(RemminaPluginRdpEvent));
164 #else
165  event = g_memdup(e, sizeof(RemminaPluginRdpEvent));
166 #endif
167  g_async_queue_push(rfi->event_queue, event);
168 
169  if (write(rfi->event_pipe[1], "\0", 1)) {
170  }
171  }
172 }
173 
175 {
176  TRACE_CALL(__func__);
177  rfContext *rfi = GET_PLUGIN_DATA(gp);
178  RemminaPluginRdpEvent rdp_event = { 0 };
179  int i;
180 
181  /* Send all release key events for previously pressed keys */
182  for (i = 0; i < rfi->pressed_keys->len; i++) {
183  rdp_event = g_array_index(rfi->pressed_keys, RemminaPluginRdpEvent, i);
184  if ((rdp_event.type == REMMINA_RDP_EVENT_TYPE_SCANCODE ||
186  rdp_event.key_event.up == false) {
187  rdp_event.key_event.up = true;
188  remmina_rdp_event_event_push(gp, &rdp_event);
189  }
190  }
191 
192  g_array_set_size(rfi->pressed_keys, 0);
193 }
194 
196 {
197  TRACE_CALL(__func__);
198  gint i;
199  rfContext *rfi = GET_PLUGIN_DATA(gp);
200  RemminaPluginRdpEvent rdp_event_2 = { 0 };
201 
203 
204  if ((rdp_event.type == REMMINA_RDP_EVENT_TYPE_SCANCODE ||
206  rdp_event.key_event.up) {
207  /* Unregister the keycode only */
208  for (i = 0; i < rfi->pressed_keys->len; i++) {
209  rdp_event_2 = g_array_index(rfi->pressed_keys, RemminaPluginRdpEvent, i);
210 
211  if (rdp_event_2.key_event.key_code == rdp_event.key_event.key_code &&
212  rdp_event_2.key_event.unicode_code == rdp_event.key_event.unicode_code &&
213  rdp_event_2.key_event.extended == rdp_event.key_event.extended) {
214  g_array_remove_index_fast(rfi->pressed_keys, i);
215  break;
216  }
217  }
218  }
219 }
220 
222 {
223  TRACE_CALL(__func__);
224  rfContext *rfi = GET_PLUGIN_DATA(gp);
225 
226  if (!rdp_event.key_event.key_code)
227  return;
228 
229  if (rdp_event.key_event.up)
230  remmina_rdp_event_release_key(gp, rdp_event);
231  else
232  g_array_append_val(rfi->pressed_keys, rdp_event);
233 }
234 
235 
236 static void remmina_rdp_event_scale_area(RemminaProtocolWidget *gp, gint *x, gint *y, gint *w, gint *h)
237 {
238  TRACE_CALL(__func__);
239  gint width, height;
240  gint sx, sy, sw, sh;
241  rfContext *rfi = GET_PLUGIN_DATA(gp);
242 
243  if (!rfi || !rfi->connected || rfi->is_reconnecting || !rfi->surface)
244  return;
245 
248 
249  if ((width == 0) || (height == 0))
250  return;
251 
252  if ((rfi->scale_width == width) && (rfi->scale_height == height)) {
253  /* Same size, just copy the pixels */
254  *x = MIN(MAX(0, *x), width - 1);
255  *y = MIN(MAX(0, *y), height - 1);
256  *w = MIN(width - *x, *w);
257  *h = MIN(height - *y, *h);
258  return;
259  }
260 
261  /* We have to extend the scaled region one scaled pixel, to avoid gaps */
262 
263  sx = MIN(MAX(0, (*x) * rfi->scale_width / width
264  - rfi->scale_width / width - 2), rfi->scale_width - 1);
265 
266  sy = MIN(MAX(0, (*y) * rfi->scale_height / height
267  - rfi->scale_height / height - 2), rfi->scale_height - 1);
268 
269  sw = MIN(rfi->scale_width - sx, (*w) * rfi->scale_width / width
270  + rfi->scale_width / width + 4);
271 
272  sh = MIN(rfi->scale_height - sy, (*h) * rfi->scale_height / height
273  + rfi->scale_height / height + 4);
274 
275  *x = sx;
276  *y = sy;
277  *w = sw;
278  *h = sh;
279 }
280 
282 {
283  TRACE_CALL(__func__);
284  rfContext *rfi = GET_PLUGIN_DATA(gp);
285  gint x, y, w, h, i;
286 
287  for (i = 0; i < ui->reg.ninvalid; i++) {
288  x = ui->reg.ureg[i].x;
289  y = ui->reg.ureg[i].y;
290  w = ui->reg.ureg[i].w;
291  h = ui->reg.ureg[i].h;
292 
294  remmina_rdp_event_scale_area(gp, &x, &y, &w, &h);
295 
296  gtk_widget_queue_draw_area(rfi->drawing_area, x, y, w, h);
297  }
298  g_free(ui->reg.ureg);
299 }
300 
301 void remmina_rdp_event_update_rect(RemminaProtocolWidget *gp, gint x, gint y, gint w, gint h)
302 {
303  TRACE_CALL(__func__);
304  rfContext *rfi = GET_PLUGIN_DATA(gp);
305 
307  remmina_rdp_event_scale_area(gp, &x, &y, &w, &h);
308 
309  gtk_widget_queue_draw_area(rfi->drawing_area, x, y, w, h);
310 }
311 
313 {
314  TRACE_CALL(__func__);
315  GtkAllocation a;
316  gint rdwidth, rdheight;
317  gint gpwidth, gpheight;
318  rfContext *rfi = GET_PLUGIN_DATA(gp);
319 
320  gtk_widget_get_allocation(GTK_WIDGET(gp), &a);
321  gpwidth = a.width;
322  gpheight = a.height;
323 
325  if ((gpwidth > 1) && (gpheight > 1)) {
328 
329  rfi->scale_width = gpwidth;
330  rfi->scale_height = gpheight;
331 
332  rfi->scale_x = (gdouble)rfi->scale_width / (gdouble)rdwidth;
333  rfi->scale_y = (gdouble)rfi->scale_height / (gdouble)rdheight;
334  }
335  } else {
336  rfi->scale_width = 0;
337  rfi->scale_height = 0;
338  rfi->scale_x = 0;
339  rfi->scale_y = 0;
340  }
341 }
342 
343 static gboolean remmina_rdp_event_on_draw(GtkWidget *widget, cairo_t *context, RemminaProtocolWidget *gp)
344 {
345  TRACE_CALL(__func__);
346  rfContext *rfi = GET_PLUGIN_DATA(gp);
347  guint width, height;
348  gchar *msg;
349  cairo_text_extents_t extents;
350 
351  if (!rfi || !rfi->connected)
352  return FALSE;
353 
354 
355  if (rfi->is_reconnecting) {
356  /* FreeRDP is reconnecting, just show a message to the user */
357 
358  width = gtk_widget_get_allocated_width(widget);
359  height = gtk_widget_get_allocated_height(widget);
360 
361  /* Draw text */
362  msg = g_strdup_printf(_("Reconnection attempt %d of %d…"),
364 
365  cairo_select_font_face(context, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
366  cairo_set_font_size(context, 24);
367  cairo_set_source_rgb(context, 0.9, 0.9, 0.9);
368  cairo_text_extents(context, msg, &extents);
369  cairo_move_to(context, (width - (extents.width + extents.x_bearing)) / 2, (height - (extents.height + extents.y_bearing)) / 2);
370  cairo_show_text(context, msg);
371  g_free(msg);
372  } else {
373  /* Standard drawing: We copy the surface from RDP */
374 
375  if (!rfi->surface)
376  return FALSE;
377 
379  cairo_scale(context, rfi->scale_x, rfi->scale_y);
380 
381  cairo_surface_flush(rfi->surface);
382  cairo_set_source_surface(context, rfi->surface, 0, 0);
383  cairo_surface_mark_dirty(rfi->surface);
384 
385  cairo_set_operator(context, CAIRO_OPERATOR_SOURCE); // Ignore alpha channel from FreeRDP
386  cairo_paint(context);
387  }
388 
389  return TRUE;
390 }
391 
393 {
394  TRACE_CALL(__func__);
395  rfContext *rfi = GET_PLUGIN_DATA(gp);
396 
397  RemminaPluginRdpEvent rdp_event = { 0 };
398  GtkAllocation a;
399  gint desktopOrientation, desktopScaleFactor, deviceScaleFactor;
400 
401  RemminaFile *remminafile;
402 
403  if (!rfi || !rfi->connected || rfi->is_reconnecting)
404  return FALSE;
405 
407 
409  return FALSE;
410 
412  gint gpwidth, gpheight, prevwidth, prevheight;
413 
414  gchar *monitorids = NULL;
415  guint32 maxwidth = 0;
416  guint32 maxheight = 0;
417 
418  remmina_rdp_monitor_get(rfi, &monitorids, &maxwidth, &maxheight);
419 
420  REMMINA_PLUGIN_DEBUG("Sending preconfigured monitor layout");
421  if (rfi->dispcontext && rfi->dispcontext->SendMonitorLayout) {
422  remmina_rdp_settings_get_orientation_scale_prefs(&desktopOrientation, &desktopScaleFactor, &deviceScaleFactor);
423  gtk_widget_get_allocation(GTK_WIDGET(gp), &a);
424  gpwidth = a.width;
425  gpheight = a.height;
428 
429  if ((gpwidth != prevwidth || gpheight != prevheight) && gpwidth >= 200 && gpheight >= 200) {
430  if (rfi->rdpgfxchan) {
431  /* Workaround for FreeRDP issue #5417 */
432  if (gpwidth < AVC_MIN_DESKTOP_WIDTH)
433  gpwidth = AVC_MIN_DESKTOP_WIDTH;
434  if (gpheight < AVC_MIN_DESKTOP_HEIGHT)
435  gpheight = AVC_MIN_DESKTOP_HEIGHT;
436  }
438  if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) {
439  const rdpMonitor *base = freerdp_settings_get_pointer(rfi->settings, FreeRDP_MonitorDefArray);
440  for (gint i = 0; i < freerdp_settings_get_uint32(rfi->settings, FreeRDP_MonitorCount); ++i) {
441  const rdpMonitor *current = &base[i];
442  REMMINA_PLUGIN_DEBUG("Sending display layout n° %d", i);
443  rdp_event.monitor_layout.Flags = current->is_primary;
444  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Flags: %i", rdp_event.monitor_layout.Flags);
445  rdp_event.monitor_layout.Left = current->x;
446  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Left: %i", rdp_event.monitor_layout.Left);
447  rdp_event.monitor_layout.Top = current->y;
448  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Top: %i", rdp_event.monitor_layout.Top);
449  rdp_event.monitor_layout.width = current->width;
450  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - width: %i", rdp_event.monitor_layout.width);
451  rdp_event.monitor_layout.height = current->height;
452  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - height: %i", rdp_event.monitor_layout.height);
453  rdp_event.monitor_layout.physicalWidth = current->attributes.physicalWidth;
454  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - physicalWidth: %i", rdp_event.monitor_layout.physicalWidth);
455  rdp_event.monitor_layout.physicalHeight = current->attributes.physicalHeight;
456  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - PhysicalHeight: %i", rdp_event.monitor_layout.physicalHeight);
457  if (current->attributes.orientation)
458  rdp_event.monitor_layout.desktopOrientation = current->attributes.orientation;
459  else
460  rdp_event.monitor_layout.desktopOrientation = rdp_event.monitor_layout.desktopOrientation;
461  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - desktopOrientation: %i", rdp_event.monitor_layout.desktopOrientation);
462  rdp_event.monitor_layout.desktopScaleFactor = rdp_event.monitor_layout.desktopScaleFactor;
463  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - ScaleFactorflag: %i", rdp_event.monitor_layout.desktopScaleFactor);
464  rdp_event.monitor_layout.deviceScaleFactor = rdp_event.monitor_layout.deviceScaleFactor;
465  }
466  remmina_rdp_event_event_push(gp, &rdp_event);
467  } else {
468  rdp_event.monitor_layout.width = gpwidth;
469  rdp_event.monitor_layout.height = gpheight;
470  rdp_event.monitor_layout.desktopOrientation = desktopOrientation;
471  rdp_event.monitor_layout.desktopScaleFactor = desktopScaleFactor;
472  rdp_event.monitor_layout.deviceScaleFactor = deviceScaleFactor;
473  remmina_rdp_event_event_push(gp, &rdp_event);
474  }
475  }
476  }
477 
478  g_free(monitorids);
479 
480  return FALSE;
481 }
482 
484 {
485  TRACE_CALL(__func__);
486  rfContext *rfi = GET_PLUGIN_DATA(gp);
487 
488  if (!rfi || !rfi->connected || rfi->is_reconnecting)
489  return;
491  g_source_remove(rfi->delayed_monitor_layout_handler);
493  }
495  rfi->delayed_monitor_layout_handler = g_timeout_add(500, (GSourceFunc)remmina_rdp_event_delayed_monitor_layout, gp);
496 }
497 
498 static gboolean remmina_rdp_event_on_configure(GtkWidget *widget, GdkEventConfigure *event, RemminaProtocolWidget *gp)
499 {
500  TRACE_CALL(__func__);
501  /* Called when gp changes its size or position */
502 
503  rfContext *rfi = GET_PLUGIN_DATA(gp);
504 
505  if (!rfi || !rfi->connected || rfi->is_reconnecting)
506  return FALSE;
507 
509 
510  /* If the scaler is not active, schedule a delayed remote resolution change */
512 
513 
514  return FALSE;
515 }
516 
517 static void remmina_rdp_event_translate_pos(RemminaProtocolWidget *gp, int ix, int iy, UINT16 *ox, UINT16 *oy)
518 {
519  TRACE_CALL(__func__);
520  rfContext *rfi = GET_PLUGIN_DATA(gp);
521 
522  /*
523  * Translate a position from local window coordinates (ix,iy) to
524  * RDP coordinates and put result on (*ox,*uy)
525  * */
526 
527  if (!rfi || !rfi->connected || rfi->is_reconnecting)
528  return;
529 
530  if ((rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED) && (rfi->scale_width >= 1) && (rfi->scale_height >= 1)) {
531  *ox = (UINT16)(ix * remmina_plugin_service->protocol_plugin_get_width(gp) / rfi->scale_width);
532  *oy = (UINT16)(iy * remmina_plugin_service->protocol_plugin_get_height(gp) / rfi->scale_height);
533  } else {
534  *ox = (UINT16)ix;
535  *oy = (UINT16)iy;
536  }
537 }
538 
539 static void remmina_rdp_event_reverse_translate_pos_reverse(RemminaProtocolWidget *gp, int ix, int iy, int *ox, int *oy)
540 {
541  TRACE_CALL(__func__);
542  rfContext *rfi = GET_PLUGIN_DATA(gp);
543 
544  /*
545  * Translate a position from RDP coordinates (ix,iy) to
546  * local window coordinates and put result on (*ox,*uy)
547  * */
548 
549  if (!rfi || !rfi->connected || rfi->is_reconnecting)
550  return;
551 
552  if ((rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED) && (rfi->scale_width >= 1) && (rfi->scale_height >= 1)) {
555  } else {
556  *ox = ix;
557  *oy = iy;
558  }
559 }
560 
562  TRACE_CALL(__func__);
563  RemminaPluginRdpEvent rdp_event = { 0 };
564  RemminaFile *remminafile;
565  rfContext *rfi = GET_PLUGIN_DATA(gp);
566 
568  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
569  return;
570 
572  rdp_event.mouse_event.flags = PTR_FLAGS_MOVE;
573  rdp_event.mouse_event.extended = FALSE;
574  rdp_event.mouse_event.x = rfi->last_x;
575  rdp_event.mouse_event.y = rfi->last_y;
576  remmina_rdp_event_event_push(gp, &rdp_event);
577 }
578 
579 static gboolean remmina_rdp_event_on_motion(GtkWidget *widget, GdkEventMotion *event, RemminaProtocolWidget *gp)
580 {
581  TRACE_CALL(__func__);
582  RemminaPluginRdpEvent rdp_event = { 0 };
583  RemminaFile *remminafile;
584  rfContext *rfi = GET_PLUGIN_DATA(gp);
585 
587  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
588  return FALSE;
589 
591  rdp_event.mouse_event.flags = PTR_FLAGS_MOVE;
592  rdp_event.mouse_event.extended = FALSE;
593 
594  remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
595  rfi->last_x = rdp_event.mouse_event.x;
596  rfi->last_y = rdp_event.mouse_event.y;
597  remmina_rdp_event_event_push(gp, &rdp_event);
598 
599  return TRUE;
600 }
601 
602 static gboolean remmina_rdp_event_on_button(GtkWidget *widget, GdkEventButton *event, RemminaProtocolWidget *gp)
603 {
604  TRACE_CALL(__func__);
605  gint flag;
606  gboolean extended = FALSE;
607  RemminaPluginRdpEvent rdp_event = { 0 };
608  gint primary, secondary;
609 
610  RemminaFile *remminafile;
611 
613  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
614  return FALSE;
615 
616  /* We bypass 2button-press and 3button-press events */
617  if ((event->type != GDK_BUTTON_PRESS) && (event->type != GDK_BUTTON_RELEASE))
618  return TRUE;
619 
620  flag = 0;
621 
622  if (remmina_plugin_service->file_get_int(remminafile, "left-handed", FALSE)) {
623  primary = PTR_FLAGS_BUTTON2;
624  secondary = PTR_FLAGS_BUTTON1;
625  } else {
626  primary = PTR_FLAGS_BUTTON1;
627  secondary = PTR_FLAGS_BUTTON2;
628  }
629 
630  switch (event->button) {
631  case 1:
632  flag |= primary;
633  break;
634  case 2:
635  flag |= PTR_FLAGS_BUTTON3;
636  break;
637  case 3:
638  flag |= secondary;
639  break;
640  case 8: /* back */
641  case 97: /* Xming */
642  extended = TRUE;
643  flag |= PTR_XFLAGS_BUTTON1;
644  break;
645  case 9: /* forward */
646  case 112: /* Xming */
647  extended = TRUE;
648  flag |= PTR_XFLAGS_BUTTON2;
649  break;
650  default:
651  return FALSE;
652  }
653 
654  if (event->type == GDK_BUTTON_PRESS) {
655  if (extended)
656  flag |= PTR_XFLAGS_DOWN;
657  else
658  flag |= PTR_FLAGS_DOWN;
659  }
660 
662  remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
663 
664  if (flag != 0) {
665  rdp_event.mouse_event.flags = flag;
666  rdp_event.mouse_event.extended = extended;
667  remmina_rdp_event_event_push(gp, &rdp_event);
668  }
669 
670  return TRUE;
671 }
672 
673 static gboolean remmina_rdp_event_on_scroll(GtkWidget *widget, GdkEventScroll *event, RemminaProtocolWidget *gp)
674 {
675  TRACE_CALL(__func__);
676  gint flag;
677  RemminaPluginRdpEvent rdp_event = { 0 };
678  float windows_delta;
679  RemminaFile *remminafile;
680 
682  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
683  return FALSE;
684 
685  flag = 0;
687 
688  /* See [MS-RDPBCGR] TS_POINTER_EVENT and WM_MOUSEWHEEL message */
689 
690  switch (event->direction) {
691  case GDK_SCROLL_UP:
692  flag = PTR_FLAGS_WHEEL | 0x0078; // 120 is one scroll unit defined in WM_MOUSEWHEEL
693  break;
694 
695  case GDK_SCROLL_DOWN:
696  flag = PTR_FLAGS_WHEEL | 0x0188; // -120 (one scroll unit) in 9 bits two's complement
697  break;
698 
699 #if GTK_CHECK_VERSION(3, 4, 0)
700  case GDK_SCROLL_SMOOTH:
701 
702  if (event->delta_y == 0.0)
703  return FALSE;
704 
705  windows_delta = event->delta_y * -120;
706 
707  if (windows_delta > 255)
708  windows_delta = 255;
709  if (windows_delta < -256)
710  windows_delta = -256;
711 
712  flag = PTR_FLAGS_WHEEL | ((short)windows_delta & WheelRotationMask);
713 
714  break;
715 #endif
716 
717  default:
718  return FALSE;
719  }
720 
721  rdp_event.mouse_event.flags = flag;
722  rdp_event.mouse_event.extended = FALSE;
723  remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
724  remmina_rdp_event_event_push(gp, &rdp_event);
725 
726  return TRUE;
727 }
728 
729 static void remmina_rdp_event_init_keymap(rfContext *rfi, const gchar *strmap)
730 {
731  long int v1, v2;
732  const char *s;
733  char *endptr;
735 
736  if (strmap == NULL || strmap[0] == 0) {
737  rfi->keymap = NULL;
738  return;
739  }
740  s = strmap;
741  rfi->keymap = g_array_new(FALSE, TRUE, sizeof(RemminaPluginRdpKeymapEntry));
742  while (1) {
743  v1 = strtol(s, &endptr, 10);
744  if (endptr == s) break;
745  s = endptr;
746  if (*s != ':') break;
747  s++;
748  v2 = strtol(s, &endptr, 10);
749  if (endptr == s) break;
750  s = endptr;
751  ke.orig_keycode = v1 & 0x7fffffff;
752  ke.translated_keycode = v2 & 0x7fffffff;
753  g_array_append_val(rfi->keymap, ke);
754  if (*s != ',') break;
755  s++;
756  }
757  if (rfi->keymap->len == 0) {
758  g_array_unref(rfi->keymap);
759  rfi->keymap = NULL;
760  }
761 }
762 
763 static gboolean remmina_rdp_event_on_key(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
764 {
765  TRACE_CALL(__func__);
766  guint32 unicode_keyval;
767  guint16 hardware_keycode;
768  rfContext *rfi = GET_PLUGIN_DATA(gp);
769  RemminaPluginRdpEvent rdp_event;
771  RemminaFile *remminafile;
772  DWORD scancode = 0;
773  int ik;
774 
775  if (!rfi || !rfi->connected || rfi->is_reconnecting)
776  return FALSE;
777 
779  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
780  return FALSE;
781 
782 #ifdef ENABLE_GTK_INSPECTOR_KEY
783  /* GTK inspector key is propagated up. Disabled by default.
784  * enable it by defining ENABLE_GTK_INSPECTOR_KEY */
785  if ((event->state & GDK_CONTROL_MASK) != 0 && (event->keyval == GDK_KEY_I || event->keyval == GDK_KEY_D))
786  return FALSE;
787 
788 #endif
789 
791  rdp_event.key_event.up = (event->type == GDK_KEY_PRESS ? false : true);
792  rdp_event.key_event.extended = false;
793 
794  switch (event->keyval) {
795  case GDK_KEY_Pause:
796  /*
797  * See https://msdn.microsoft.com/en-us/library/cc240584.aspx
798  * 2.2.8.1.1.3.1.1.1 Keyboard Event (TS_KEYBOARD_EVENT)
799  * for pause key management
800  */
801  rdp_event.key_event.key_code = 0x1D;
802  rdp_event.key_event.up = false;
803  remmina_rdp_event_event_push(gp, &rdp_event);
804  rdp_event.key_event.key_code = 0x45;
805  rdp_event.key_event.up = false;
806  remmina_rdp_event_event_push(gp, &rdp_event);
807  rdp_event.key_event.key_code = 0x1D;
808  rdp_event.key_event.up = true;
809  remmina_rdp_event_event_push(gp, &rdp_event);
810  rdp_event.key_event.key_code = 0x45;
811  rdp_event.key_event.up = true;
812  remmina_rdp_event_event_push(gp, &rdp_event);
813  break;
814 
815  default:
816  if (!rfi->use_client_keymap) {
817  hardware_keycode = event->hardware_keycode;
818  if (rfi->keymap) {
819  for (ik = 0; ik < rfi->keymap->len; ik++) {
820  kep = &g_array_index(rfi->keymap, RemminaPluginRdpKeymapEntry, ik);
821  if (hardware_keycode == kep->orig_keycode) {
822  hardware_keycode = kep->translated_keycode;
823  break;
824  }
825  }
826  }
827  scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(hardware_keycode);
828  if (scancode) {
829  rdp_event.key_event.key_code = scancode & 0xFF;
830  rdp_event.key_event.extended = scancode & 0x100;
831  remmina_rdp_event_event_push(gp, &rdp_event);
832  keypress_list_add(gp, rdp_event);
833  }
834  } else {
835  unicode_keyval = gdk_keyval_to_unicode(event->keyval);
836  /* Decide when whe should send a keycode or a Unicode character.
837  * - All non char keys (Shift, Alt, Super) should be sent as keycode
838  * - Space should be sent as keycode (see issue #1364)
839  * - All special keys (F1-F10, numeric pad, Home/End/Arrows/PgUp/PgDn/Insert/Delete) keycode
840  * - All key pressed while Ctrl or Alt or Super is down are not decoded by gdk_keyval_to_unicode(), so send it as keycode
841  * - All keycodes not translatable to unicode chars, as keycode
842  * - The rest as Unicode char
843  */
844  if (event->keyval >= 0xfe00 || // Arrows, Shift, Alt, Fn, num keypad…
845  event->hardware_keycode == 0x41 || // Spacebar
846  unicode_keyval == 0 || // Impossible to translate
847  (event->state & (GDK_MOD1_MASK | GDK_CONTROL_MASK | GDK_SUPER_MASK)) != 0 // A modifier not recognized by gdk_keyval_to_unicode()
848  ) {
849  scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(event->hardware_keycode);
850  rdp_event.key_event.key_code = scancode & 0xFF;
851  rdp_event.key_event.extended = scancode & 0x100;
852  if (rdp_event.key_event.key_code) {
853  remmina_rdp_event_event_push(gp, &rdp_event);
854  keypress_list_add(gp, rdp_event);
855  }
856  } else {
858  rdp_event.key_event.unicode_code = unicode_keyval;
859  rdp_event.key_event.extended = false;
860  remmina_rdp_event_event_push(gp, &rdp_event);
861  keypress_list_add(gp, rdp_event);
862  }
863  }
864  break;
865  }
866 
867  return TRUE;
868 }
869 
870 gboolean remmina_rdp_event_on_clipboard(GtkClipboard *gtkClipboard, GdkEvent *event, RemminaProtocolWidget *gp)
871 {
872  /* Signal handler for GTK clipboard owner-change */
873  TRACE_CALL(__func__);
874  RemminaPluginRdpEvent rdp_event = { 0 };
875  CLIPRDR_FORMAT_LIST *pFormatList;
876  GObject *new_owner;
877 
878  /* Usually "owner-change" is fired when a user presses "COPY" on the client
879  * OR when this plugin calls gtk_clipboard_set_with_owner()
880  * after receiving a RDP server format list in remmina_rdp_cliprdr_server_format_list()
881  * In the latter case, we must ignore owner change */
882 
883  REMMINA_PLUGIN_DEBUG("gp=%p: owner-change event received", gp);
884 
885  rfContext *rfi = GET_PLUGIN_DATA(gp);
886 
887  if (rfi)
889 
890  new_owner = gtk_clipboard_get_owner(gtkClipboard);
891  if (new_owner != (GObject *)gp) {
892  /* To do: avoid this when the new owner is another remmina protocol widget of
893  * the same remmina application */
894  REMMINA_PLUGIN_DEBUG("gp=%p owner-change: new owner is different than me: new=%p me=%p",
895  gp, new_owner, gp);
896 
897  REMMINA_PLUGIN_DEBUG("gp=%p owner-change: new owner is not me: Sending local clipboard format list to server.",
898  gp, new_owner, gp);
901  rdp_event.clipboard_formatlist.pFormatList = pFormatList;
902  remmina_rdp_event_event_push(gp, &rdp_event);
903  } else {
904  REMMINA_PLUGIN_DEBUG(" ... but I'm the owner!");
905  }
906  return TRUE;
907 }
908 
910 {
911  TRACE_CALL(__func__);
912  gchar *s;
913  gint flags;
914  rfContext *rfi = GET_PLUGIN_DATA(gp);
915  GtkClipboard *clipboard;
916  RemminaFile *remminafile;
917 
918  gboolean disable_smooth_scrolling = FALSE;
919 
920  if (!rfi) return;
922 
923  /* we get first the global preferences */
924  s = remmina_plugin_service->pref_get_value("rdp_disable_smooth_scrolling");
925  disable_smooth_scrolling = (s && s[0] == '1' ? TRUE : FALSE);
926  g_free(s), s = NULL;
927  /* Otherwise we use the connection profile specific setting */
928  disable_smooth_scrolling = remmina_plugin_service->file_get_int(remminafile, "disable-smooth-scrolling", disable_smooth_scrolling);
929 
930  REMMINA_PLUGIN_DEBUG("Disable smooth scrolling is set to %d", disable_smooth_scrolling);
931 
932  rfi->drawing_area = gtk_drawing_area_new();
933  gtk_widget_show(rfi->drawing_area);
934  gtk_container_add(GTK_CONTAINER(gp), rfi->drawing_area);
935 
936  gtk_widget_add_events(rfi->drawing_area, GDK_POINTER_MOTION_MASK
937  | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
938  | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK
939  | GDK_SCROLL_MASK | GDK_FOCUS_CHANGE_MASK);
940 
941  if (!disable_smooth_scrolling) {
942  REMMINA_PLUGIN_DEBUG("Adding GDK_SMOOTH_SCROLL_MASK");
943  gtk_widget_add_events(rfi->drawing_area, GDK_SMOOTH_SCROLL_MASK);
944  }
945 
946  gtk_widget_set_can_focus(rfi->drawing_area, TRUE);
947 
949 
950  s = remmina_plugin_service->pref_get_value("rdp_use_client_keymap");
951  rfi->use_client_keymap = (s && s[0] == '1' ? TRUE : FALSE);
952  g_free(s), s = NULL;
953 
954  /* Read special keymap from profile file, if exists */
956 
957  if (rfi->use_client_keymap && rfi->keymap)
958  fprintf(stderr, "RDP profile error: you cannot define both rdp_map_hardware_keycode and have 'Use client keyboard mapping' enabled\n");
959 
960  g_signal_connect(G_OBJECT(rfi->drawing_area), "draw",
961  G_CALLBACK(remmina_rdp_event_on_draw), gp);
962  g_signal_connect(G_OBJECT(rfi->drawing_area), "configure-event",
963  G_CALLBACK(remmina_rdp_event_on_configure), gp);
964  g_signal_connect(G_OBJECT(rfi->drawing_area), "motion-notify-event",
965  G_CALLBACK(remmina_rdp_event_on_motion), gp);
966  g_signal_connect(G_OBJECT(rfi->drawing_area), "button-press-event",
967  G_CALLBACK(remmina_rdp_event_on_button), gp);
968  g_signal_connect(G_OBJECT(rfi->drawing_area), "button-release-event",
969  G_CALLBACK(remmina_rdp_event_on_button), gp);
970  g_signal_connect(G_OBJECT(rfi->drawing_area), "scroll-event",
971  G_CALLBACK(remmina_rdp_event_on_scroll), gp);
972  g_signal_connect(G_OBJECT(rfi->drawing_area), "key-press-event",
973  G_CALLBACK(remmina_rdp_event_on_key), gp);
974  g_signal_connect(G_OBJECT(rfi->drawing_area), "key-release-event",
975  G_CALLBACK(remmina_rdp_event_on_key), gp);
976  g_signal_connect(G_OBJECT(rfi->drawing_area), "focus-in-event",
977  G_CALLBACK(remmina_rdp_event_on_focus_in), gp);
984  //g_signal_connect(G_OBJECT(gtk_widget_get_toplevel(rfi->drawing_area)), "map-event",
985  // G_CALLBACK(remmina_rdp_event_on_map), gp);
986  //g_signal_connect(G_OBJECT(gtk_widget_get_toplevel(rfi->drawing_area)), "unmap-event",
987  // G_CALLBACK(remmina_rdp_event_on_unmap), gp);
988 
989  if (!remmina_plugin_service->file_get_int(remminafile, "disableclipboard", FALSE)) {
990  clipboard = gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD);
991  rfi->clipboard.clipboard_handler = g_signal_connect(clipboard, "owner-change", G_CALLBACK(remmina_rdp_event_on_clipboard), gp);
992  }
993 
994  rfi->pressed_keys = g_array_new(FALSE, TRUE, sizeof(RemminaPluginRdpEvent));
995  rfi->event_queue = g_async_queue_new_full(g_free);
996  rfi->ui_queue = g_async_queue_new();
997  pthread_mutex_init(&rfi->ui_queue_mutex, NULL);
998 
999  if (pipe(rfi->event_pipe)) {
1000  g_print("Error creating pipes.\n");
1001  rfi->event_pipe[0] = -1;
1002  rfi->event_pipe[1] = -1;
1003  rfi->event_handle = NULL;
1004  } else {
1005  flags = fcntl(rfi->event_pipe[0], F_GETFL, 0);
1006  fcntl(rfi->event_pipe[0], F_SETFL, flags | O_NONBLOCK);
1007  rfi->event_handle = CreateFileDescriptorEvent(NULL, FALSE, FALSE, rfi->event_pipe[0], WINPR_FD_READ);
1008  if (!rfi->event_handle)
1009  g_print("CreateFileDescriptorEvent() failed\n");
1010  }
1011 
1012  rfi->object_table = g_hash_table_new_full(NULL, NULL, NULL, g_free);
1013 
1014  rfi->display = gdk_display_get_default();
1015 
1016 #if GTK_CHECK_VERSION(3, 22, 0)
1017  GdkVisual *visual = gdk_screen_get_system_visual(
1018  gdk_display_get_default_screen(rfi->display));
1019  rfi->bpp = gdk_visual_get_depth(visual);
1020 #else
1021  rfi->bpp = gdk_visual_get_best_depth();
1022 #endif
1023 }
1024 
1026 {
1027  TRACE_CALL(__func__);
1028 
1029  switch (obj->type) {
1031  free(obj->nocodec.bitmap);
1032  break;
1033 
1034  default:
1035  break;
1036  }
1037 
1038  g_free(obj);
1039 }
1040 
1042 {
1043  TRACE_CALL(__func__);
1044  rfContext *rfi = GET_PLUGIN_DATA(gp);
1046 
1047  if (!rfi) return;
1048 
1049  /* unregister the clipboard monitor */
1050  if (rfi->clipboard.clipboard_handler) {
1051  g_signal_handler_disconnect(G_OBJECT(gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD)), rfi->clipboard.clipboard_handler);
1052  rfi->clipboard.clipboard_handler = 0;
1053  }
1054  if (rfi->delayed_monitor_layout_handler) {
1055  g_source_remove(rfi->delayed_monitor_layout_handler);
1057  }
1058  if (rfi->ui_handler) {
1059  g_source_remove(rfi->ui_handler);
1060  rfi->ui_handler = 0;
1061  }
1062  while ((ui = (RemminaPluginRdpUiObject *)g_async_queue_try_pop(rfi->ui_queue)) != NULL)
1064  if (rfi->surface) {
1065  cairo_surface_mark_dirty(rfi->surface);
1066  cairo_surface_destroy(rfi->surface);
1067  rfi->surface = NULL;
1068  }
1069 
1070  g_hash_table_destroy(rfi->object_table);
1071 
1072  g_array_free(rfi->pressed_keys, TRUE);
1073  if (rfi->keymap) {
1074  g_array_free(rfi->keymap, TRUE);
1075  rfi->keymap = NULL;
1076  }
1077  g_async_queue_unref(rfi->event_queue);
1078  rfi->event_queue = NULL;
1079  g_async_queue_unref(rfi->ui_queue);
1080  rfi->ui_queue = NULL;
1081  pthread_mutex_destroy(&rfi->ui_queue_mutex);
1082 
1083  if (rfi->event_handle) {
1084  CloseHandle(rfi->event_handle);
1085  rfi->event_handle = NULL;
1086  }
1087 
1088  close(rfi->event_pipe[0]);
1089  close(rfi->event_pipe[1]);
1090 }
1091 
1093 {
1094  int stride;
1095  rdpGdi *gdi;
1096 
1097  if (!rfi)
1098  return;
1099 
1100  gdi = ((rdpContext *)rfi)->gdi;
1101 
1102  if (!gdi)
1103  return;
1104 
1105  if (rfi->surface) {
1106  cairo_surface_mark_dirty(rfi->surface);
1107  cairo_surface_destroy(rfi->surface);
1108  rfi->surface = NULL;
1109  }
1110  stride = cairo_format_stride_for_width(rfi->cairo_format, gdi->width);
1111  rfi->surface = cairo_image_surface_create_for_data((unsigned char *)gdi->primary_buffer, rfi->cairo_format, gdi->width, gdi->height, stride);
1112  cairo_surface_flush(rfi->surface);
1113 }
1114 
1116 {
1117  TRACE_CALL(__func__);
1118  gint width, height;
1119  rdpGdi *gdi;
1120  rfContext *rfi = GET_PLUGIN_DATA(gp);
1121 
1124 
1125  gdi = ((rdpContext *)rfi)->gdi;
1126 
1128 
1129  /* See if we also must rellocate rfi->surface with different width and height,
1130  * this usually happens after a DesktopResize RDP event*/
1131 
1132  if (rfi->surface && (cairo_image_surface_get_width(rfi->surface) != gdi->width ||
1133  cairo_image_surface_get_height(rfi->surface) != gdi->height)) {
1134  /* Destroys and recreate rfi->surface with new width and height */
1135  cairo_surface_mark_dirty(rfi->surface);
1136  cairo_surface_destroy(rfi->surface);
1137  rfi->surface = NULL;
1139  } else if (rfi->surface == NULL) {
1141  }
1142 
1143  /* Send gdi->width and gdi->height obtained from remote server to gp plugin,
1144  * so they will be saved when closing connection */
1145  if (width != gdi->width)
1147  if (height != gdi->height)
1149 
1151 
1153  /* In scaled mode and autores mode, drawing_area will get its dimensions from its parent */
1154  gtk_widget_set_size_request(rfi->drawing_area, -1, -1);
1155  else
1156  /* In non scaled mode, the plugins forces dimensions of drawing area */
1157  gtk_widget_set_size_request(rfi->drawing_area, width, height);
1159 }
1160 
1162 {
1163  TRACE_CALL(__func__);
1164  rfContext *rfi = GET_PLUGIN_DATA(gp);
1165  rdpGdi *gdi;
1166 
1167  gdi = ((rdpContext *)rfi)->gdi;
1168 
1169  gtk_widget_realize(rfi->drawing_area);
1170 
1172  gtk_widget_queue_draw_area(rfi->drawing_area, 0, 0, gdi->width, gdi->height);
1173 
1175 
1177  const gchar *host = freerdp_settings_get_string (rfi->settings, FreeRDP_ServerHostname);
1178  // TRANSLATORS: the placeholder may be either an IP/FQDN or a server hostname
1179  REMMINA_PLUGIN_AUDIT(_("Connected to %s via RDP"), host);
1180 }
1181 
1183 {
1184  TRACE_CALL(__func__);
1185  rfContext *rfi = GET_PLUGIN_DATA(gp);
1186 
1187  gdk_window_invalidate_rect(gtk_widget_get_window(rfi->drawing_area), NULL, TRUE);
1188 }
1189 
1191 {
1192  TRACE_CALL(__func__);
1193  GdkPixbuf *pixbuf;
1194  rfContext *rfi = GET_PLUGIN_DATA(gp);
1195  rdpPointer *pointer = (rdpPointer *)ui->cursor.pointer;
1196  cairo_surface_t *surface;
1197  UINT8 *data = malloc(pointer->width * pointer->height * 4);
1198 
1199  if (!freerdp_image_copy_from_pointer_data(
1200  (BYTE *)data, PIXEL_FORMAT_BGRA32,
1201  pointer->width * 4, 0, 0, pointer->width, pointer->height,
1202  pointer->xorMaskData, pointer->lengthXorMask,
1203  pointer->andMaskData, pointer->lengthAndMask,
1204  pointer->xorBpp, &(ui->cursor.context->gdi->palette))) {
1205  free(data);
1206  return FALSE;
1207  }
1208 
1209  surface = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, pointer->width, pointer->height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pointer->width));
1210  cairo_surface_flush(surface);
1211  pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, pointer->width, pointer->height);
1212  cairo_surface_mark_dirty(surface);
1213  cairo_surface_destroy(surface);
1214  free(data);
1215  ((rfPointer *)ui->cursor.pointer)->cursor = gdk_cursor_new_from_pixbuf(rfi->display, pixbuf, pointer->xPos, pointer->yPos);
1216  g_object_unref(pixbuf);
1217 
1218  return TRUE;
1219 }
1220 
1222 {
1223  TRACE_CALL(__func__);
1224  g_object_unref(ui->cursor.pointer->cursor);
1225  ui->cursor.pointer->cursor = NULL;
1226 }
1227 
1229 {
1230  TRACE_CALL(__func__);
1231  GdkWindow *w, *nw;
1232  gint nx, ny, wx, wy;
1233 
1234 #if GTK_CHECK_VERSION(3, 20, 0)
1235  GdkSeat *seat;
1236 #else
1237  GdkDeviceManager *manager;
1238 #endif
1239  GdkDevice *dev;
1240  rfContext *rfi = GET_PLUGIN_DATA(gp);
1241 
1242  if (rfi == NULL)
1243  return FALSE;
1244 
1245  w = gtk_widget_get_window(rfi->drawing_area);
1246 #if GTK_CHECK_VERSION(3, 20, 0)
1247  seat = gdk_display_get_default_seat(gdk_display_get_default());
1248  dev = gdk_seat_get_pointer(seat);
1249 #else
1250  manager = gdk_display_get_device_manager(gdk_display_get_default());
1251  dev = gdk_device_manager_get_client_pointer(manager);
1252 #endif
1253 
1254  nw = gdk_device_get_window_at_position(dev, NULL, NULL);
1255 
1256  if (nw == w) {
1257  nx = 0;
1258  ny = 0;
1260  gdk_window_get_root_coords(w, nx, ny, &wx, &wy);
1261  gdk_device_warp(dev, gdk_window_get_screen(w), wx, wy);
1262  }
1263  return TRUE;
1264 }
1265 
1267 {
1268  TRACE_CALL(__func__);
1269  rfContext *rfi = GET_PLUGIN_DATA(gp);
1270 
1271  switch (ui->cursor.type) {
1273  ui->retval = remmina_rdp_event_create_cursor(gp, ui) ? 1 : 0;
1274  break;
1275 
1278  break;
1279 
1281  gdk_window_set_cursor(gtk_widget_get_window(rfi->drawing_area), ui->cursor.pointer->cursor);
1282  ui->retval = 1;
1283  break;
1284 
1286  ui->retval = remmina_rdp_event_set_pointer_position(gp, ui->pos.x, ui->pos.y) ? 1 : 0;
1287  break;
1288 
1290  gdk_window_set_cursor(gtk_widget_get_window(rfi->drawing_area),
1291  gdk_cursor_new_for_display(gdk_display_get_default(),
1292  GDK_BLANK_CURSOR));
1293  ui->retval = 1;
1294  break;
1295 
1297  gdk_window_set_cursor(gtk_widget_get_window(rfi->drawing_area), NULL);
1298  ui->retval = 1;
1299  break;
1300  }
1301 }
1302 
1304 {
1305  TRACE_CALL(__func__);
1307 }
1308 
1310 {
1311  TRACE_CALL(__func__);
1312  rfContext *rfi = GET_PLUGIN_DATA(gp);
1313 
1314  if (!rfi || !rfi->connected || rfi->is_reconnecting)
1315  return;
1317 }
1318 
1320 {
1321  TRACE_CALL(__func__);
1322  rfContext *rfi = GET_PLUGIN_DATA(gp);
1323 
1324  cairo_surface_mark_dirty(rfi->surface);
1325  cairo_surface_destroy(rfi->surface);
1326  rfi->surface = NULL;
1327 }
1328 
1330 {
1331  TRACE_CALL(__func__);
1332  switch (ui->event.type) {
1335  break;
1338  break;
1339  }
1340 }
1341 
1343 {
1344  TRACE_CALL(__func__);
1345  switch (ui->type) {
1348  break;
1349 
1352  break;
1353 
1356  break;
1357 
1358  case REMMINA_RDP_UI_CURSOR:
1359  remmina_rdp_event_cursor(gp, ui);
1360  break;
1361 
1364  break;
1365 
1366  case REMMINA_RDP_UI_EVENT:
1368  break;
1369 
1370  default:
1371  break;
1372  }
1373 }
1374 
1376 {
1377  TRACE_CALL(__func__);
1378 
1379  rfContext *rfi = GET_PLUGIN_DATA(gp);
1381 
1382  pthread_mutex_lock(&rfi->ui_queue_mutex);
1383  ui = (RemminaPluginRdpUiObject *)g_async_queue_try_pop(rfi->ui_queue);
1384  if (ui) {
1385  pthread_mutex_lock(&ui->sync_wait_mutex);
1386  if (!rfi->thread_cancelled)
1388  // Should we signal the caller thread to unlock ?
1389  if (ui->sync) {
1390  ui->complete = TRUE;
1391  pthread_cond_signal(&ui->sync_wait_cond);
1392  pthread_mutex_unlock(&ui->sync_wait_mutex);
1393  } else {
1395  }
1396 
1397  pthread_mutex_unlock(&rfi->ui_queue_mutex);
1398  return TRUE;
1399  } else {
1400  rfi->ui_handler = 0;
1401  pthread_mutex_unlock(&rfi->ui_queue_mutex);
1402  return FALSE;
1403  }
1404 }
1405 
1407 {
1408  TRACE_CALL(__func__);
1409  rfContext *rfi = GET_PLUGIN_DATA(gp);
1410  gboolean ui_sync_save;
1411  int oldcanceltype;
1412 
1413  if (!rfi || rfi->thread_cancelled)
1414  return;
1415 
1418  return;
1419  }
1420 
1421  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldcanceltype);
1422 
1423  pthread_mutex_lock(&rfi->ui_queue_mutex);
1424 
1425  ui_sync_save = ui->sync;
1426  ui->complete = FALSE;
1427 
1428  if (ui_sync_save) {
1429  pthread_mutex_init(&ui->sync_wait_mutex, NULL);
1430  pthread_cond_init(&ui->sync_wait_cond, NULL);
1431  }
1432 
1433  ui->complete = FALSE;
1434 
1435  g_async_queue_push(rfi->ui_queue, ui);
1436 
1437  if (!rfi->ui_handler)
1438  rfi->ui_handler = IDLE_ADD((GSourceFunc)remmina_rdp_event_process_ui_queue, gp);
1439 
1440  if (ui_sync_save) {
1441  /* Wait for main thread function completion before returning */
1442  pthread_mutex_lock(&ui->sync_wait_mutex);
1443  pthread_mutex_unlock(&rfi->ui_queue_mutex);
1444  while (!ui->complete)
1445  pthread_cond_wait(&ui->sync_wait_cond, &ui->sync_wait_mutex);
1446  pthread_cond_destroy(&ui->sync_wait_cond);
1447  pthread_mutex_destroy(&ui->sync_wait_mutex);
1448  } else {
1449  pthread_mutex_unlock(&rfi->ui_queue_mutex);
1450  }
1451  pthread_setcanceltype(oldcanceltype, NULL);
1452 }
1453 
1455 {
1456  ui->sync = FALSE;
1458 }
1459 
1461 {
1462  TRACE_CALL(__func__);
1463  int retval;
1464 
1465  ui->sync = TRUE;
1467  retval = ui->retval;
1469  return retval;
1470 }
1471 
1473 {
1474  TRACE_CALL(__func__);
1475  void *rp;
1476 
1477  ui->sync = TRUE;
1479  rp = ui->retptr;
1481  return rp;
1482 }
+Go to the documentation of this file.
1 /*
2  * Remmina - The GTK Remote Desktop Client
3  * Copyright (C) 2010 Jay Sorg
4  * Copyright (C) 2010-2011 Vic Lee
5  * Copyright (C) 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
7  * Copyright (C) 2016-2022 Antenore Gatta, Giovanni Panozzo
8  * Copyright (C) 2022-2023 Antenore Gatta, Giovanni Panozzo, Hiroyuki Tanaka
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  *
25  * In addition, as a special exception, the copyright holders give
26  * permission to link the code of portions of this program with the
27  * OpenSSL library under certain conditions as described in each
28  * individual source file, and distribute linked combinations
29  * including the two.
30  * You must obey the GNU General Public License in all respects
31  * for all of the code used other than OpenSSL. * If you modify
32  * file(s) with this exception, you may extend this exception to your
33  * version of the file(s), but you are not obligated to do so. * If you
34  * do not wish to do so, delete this exception statement from your
35  * version. * If you delete this exception statement from all source
36  * files in the program, then also delete it here.
37  *
38  */
39 
40 #include "rdp_cliprdr.h"
41 #include "rdp_event.h"
42 #include "rdp_monitor.h"
43 #include "rdp_settings.h"
44 #include <gdk/gdkkeysyms.h>
45 #ifdef GDK_WINDOWING_X11
46 #include <cairo/cairo-xlib.h>
47 #else
48 #include <cairo/cairo.h>
49 #endif
50 #include <freerdp/locale/keyboard.h>
51 
53 {
54  TRACE_CALL(__func__);
55  rfContext *rfi = GET_PLUGIN_DATA(gp);
56  rdpGdi *gdi;
57 
58  if (rfi == NULL)
59  return false;
60 
62  int do_suppress = !remmina_plugin_service->file_get_int(remminafile, "no-suppress", FALSE);
63 
64  if (do_suppress) {
65  gdi = ((rdpContext *)rfi)->gdi;
66 
67  REMMINA_PLUGIN_DEBUG("Map event received, disabling TS_SUPPRESS_OUTPUT_PDU ");
68  gdi_send_suppress_output(gdi, FALSE);
69  }
70 
71  return FALSE;
72 }
73 
75 {
76  TRACE_CALL(__func__);
77  rfContext *rfi = GET_PLUGIN_DATA(gp);
78  rdpGdi *gdi;
79 
80  if (rfi == NULL)
81  return false;
82 
83  GtkWidget *toplevel = gtk_widget_get_toplevel(GTK_WIDGET(gp));
84  GdkWindow *window = gtk_widget_get_window(toplevel);
85 
86  if (gdk_window_get_fullscreen_mode(window) == GDK_FULLSCREEN_ON_ALL_MONITORS) {
87  REMMINA_PLUGIN_DEBUG("Unmap event received, but cannot enable TS_SUPPRESS_OUTPUT_PDU when in fullscreen");
88  return FALSE;
89  }
90 
92  int do_suppress = !remmina_plugin_service->file_get_int(remminafile, "no-suppress", FALSE);
93 
94  if (do_suppress) {
95  gdi = ((rdpContext *)rfi)->gdi;
96 
97  REMMINA_PLUGIN_DEBUG("Unmap event received, enabling TS_SUPPRESS_OUTPUT_PDU ");
98  gdi_send_suppress_output(gdi, TRUE);
99  }
100 
101  return FALSE;
102 }
103 
104 static gboolean remmina_rdp_event_on_focus_in(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
105 {
106  TRACE_CALL(__func__);
107 
108  rfContext *rfi = GET_PLUGIN_DATA(gp);
109  rdpInput *input;
110  GdkModifierType state;
111 
112 #if GTK_CHECK_VERSION(3, 20, 0)
113  GdkSeat *seat;
114 #else
115  GdkDeviceManager *manager;
116 #endif
117  GdkDevice *keyboard = NULL;
118 
119  const gchar *wname = gtk_widget_get_name(gtk_widget_get_toplevel(widget));
120  REMMINA_PLUGIN_DEBUG("Top level name is: %s", wname);
121 
122  if (!rfi || !rfi->connected || rfi->is_reconnecting)
123  return FALSE;
124 
125  input = rfi->instance->input;
126  UINT32 toggle_keys_state = 0;
127 
128 #if GTK_CHECK_VERSION(3, 20, 0)
129  seat = gdk_display_get_default_seat(gdk_display_get_default());
130  keyboard = gdk_seat_get_pointer(seat);
131 #else
132  manager = gdk_display_get_device_manager(gdk_display_get_default());
133  keyboard = gdk_device_manager_get_client_pointer(manager);
134 #endif
135  gdk_window_get_device_position(gdk_get_default_root_window(), keyboard, NULL, NULL, &state);
136 
137  if (state & GDK_LOCK_MASK)
138  toggle_keys_state |= KBD_SYNC_CAPS_LOCK;
139  if (state & GDK_MOD2_MASK)
140  toggle_keys_state |= KBD_SYNC_NUM_LOCK;
141  if (state & GDK_MOD5_MASK)
142  toggle_keys_state |= KBD_SYNC_SCROLL_LOCK;
143 
144  input->SynchronizeEvent(input, toggle_keys_state);
145  input->KeyboardEvent(input, KBD_FLAGS_RELEASE, 0x0F);
146 
147  return FALSE;
148 }
149 
151 {
152  TRACE_CALL(__func__);
153  rfContext *rfi = GET_PLUGIN_DATA(gp);
154  RemminaPluginRdpEvent *event;
155 
156  /* Called by the main GTK thread to send an event to the libfreerdp thread */
157 
158  if (!rfi || !rfi->connected || rfi->is_reconnecting)
159  return;
160 
161  if (rfi->event_queue) {
162 #if GLIB_CHECK_VERSION(2,67,3)
163  event = g_memdup2(e, sizeof(RemminaPluginRdpEvent));
164 #else
165  event = g_memdup(e, sizeof(RemminaPluginRdpEvent));
166 #endif
167  g_async_queue_push(rfi->event_queue, event);
168 
169  if (write(rfi->event_pipe[1], "\0", 1)) {
170  }
171  }
172 }
173 
175 {
176  TRACE_CALL(__func__);
177  rfContext *rfi = GET_PLUGIN_DATA(gp);
178  RemminaPluginRdpEvent rdp_event = { 0 };
179  int i;
180 
181  /* Send all release key events for previously pressed keys */
182  for (i = 0; i < rfi->pressed_keys->len; i++) {
183  rdp_event = g_array_index(rfi->pressed_keys, RemminaPluginRdpEvent, i);
184  if ((rdp_event.type == REMMINA_RDP_EVENT_TYPE_SCANCODE ||
186  rdp_event.key_event.up == false) {
187  rdp_event.key_event.up = true;
188  remmina_rdp_event_event_push(gp, &rdp_event);
189  }
190  }
191 
192  g_array_set_size(rfi->pressed_keys, 0);
193 }
194 
196 {
197  TRACE_CALL(__func__);
198  gint i;
199  rfContext *rfi = GET_PLUGIN_DATA(gp);
200  RemminaPluginRdpEvent rdp_event_2 = { 0 };
201 
203 
204  if ((rdp_event.type == REMMINA_RDP_EVENT_TYPE_SCANCODE ||
206  rdp_event.key_event.up) {
207  /* Unregister the keycode only */
208  for (i = 0; i < rfi->pressed_keys->len; i++) {
209  rdp_event_2 = g_array_index(rfi->pressed_keys, RemminaPluginRdpEvent, i);
210 
211  if (rdp_event_2.key_event.key_code == rdp_event.key_event.key_code &&
212  rdp_event_2.key_event.unicode_code == rdp_event.key_event.unicode_code &&
213  rdp_event_2.key_event.extended == rdp_event.key_event.extended) {
214  g_array_remove_index_fast(rfi->pressed_keys, i);
215  break;
216  }
217  }
218  }
219 }
220 
222 {
223  TRACE_CALL(__func__);
224  rfContext *rfi = GET_PLUGIN_DATA(gp);
225 
226  if (!rdp_event.key_event.key_code)
227  return;
228 
229  if (rdp_event.key_event.up)
230  remmina_rdp_event_release_key(gp, rdp_event);
231  else
232  g_array_append_val(rfi->pressed_keys, rdp_event);
233 }
234 
235 
236 static void remmina_rdp_event_scale_area(RemminaProtocolWidget *gp, gint *x, gint *y, gint *w, gint *h)
237 {
238  TRACE_CALL(__func__);
239  gint width, height;
240  gint sx, sy, sw, sh;
241  rfContext *rfi = GET_PLUGIN_DATA(gp);
242 
243  if (!rfi || !rfi->connected || rfi->is_reconnecting || !rfi->surface)
244  return;
245 
248 
249  if ((width == 0) || (height == 0))
250  return;
251 
252  if ((rfi->scale_width == width) && (rfi->scale_height == height)) {
253  /* Same size, just copy the pixels */
254  *x = MIN(MAX(0, *x), width - 1);
255  *y = MIN(MAX(0, *y), height - 1);
256  *w = MIN(width - *x, *w);
257  *h = MIN(height - *y, *h);
258  return;
259  }
260 
261  /* We have to extend the scaled region one scaled pixel, to avoid gaps */
262 
263  sx = MIN(MAX(0, (*x) * rfi->scale_width / width
264  - rfi->scale_width / width - 2), rfi->scale_width - 1);
265 
266  sy = MIN(MAX(0, (*y) * rfi->scale_height / height
267  - rfi->scale_height / height - 2), rfi->scale_height - 1);
268 
269  sw = MIN(rfi->scale_width - sx, (*w) * rfi->scale_width / width
270  + rfi->scale_width / width + 4);
271 
272  sh = MIN(rfi->scale_height - sy, (*h) * rfi->scale_height / height
273  + rfi->scale_height / height + 4);
274 
275  *x = sx;
276  *y = sy;
277  *w = sw;
278  *h = sh;
279 }
280 
282 {
283  TRACE_CALL(__func__);
284  rfContext *rfi = GET_PLUGIN_DATA(gp);
285  gint x, y, w, h, i;
286 
287  for (i = 0; i < ui->reg.ninvalid; i++) {
288  x = ui->reg.ureg[i].x;
289  y = ui->reg.ureg[i].y;
290  w = ui->reg.ureg[i].w;
291  h = ui->reg.ureg[i].h;
292 
294  remmina_rdp_event_scale_area(gp, &x, &y, &w, &h);
295 
296  gtk_widget_queue_draw_area(rfi->drawing_area, x, y, w, h);
297  }
298  g_free(ui->reg.ureg);
299 }
300 
301 void remmina_rdp_event_update_rect(RemminaProtocolWidget *gp, gint x, gint y, gint w, gint h)
302 {
303  TRACE_CALL(__func__);
304  rfContext *rfi = GET_PLUGIN_DATA(gp);
305 
307  remmina_rdp_event_scale_area(gp, &x, &y, &w, &h);
308 
309  gtk_widget_queue_draw_area(rfi->drawing_area, x, y, w, h);
310 }
311 
313 {
314  TRACE_CALL(__func__);
315  GtkAllocation a;
316  gint rdwidth, rdheight;
317  gint gpwidth, gpheight;
318  rfContext *rfi = GET_PLUGIN_DATA(gp);
319 
320  gtk_widget_get_allocation(GTK_WIDGET(gp), &a);
321  gpwidth = a.width;
322  gpheight = a.height;
323 
325  if ((gpwidth > 1) && (gpheight > 1)) {
328 
329  rfi->scale_width = gpwidth;
330  rfi->scale_height = gpheight;
331 
332  rfi->scale_x = (gdouble)rfi->scale_width / (gdouble)rdwidth;
333  rfi->scale_y = (gdouble)rfi->scale_height / (gdouble)rdheight;
334  }
335  } else {
336  rfi->scale_width = 0;
337  rfi->scale_height = 0;
338  rfi->scale_x = 0;
339  rfi->scale_y = 0;
340  }
341 }
342 
343 static gboolean remmina_rdp_event_on_draw(GtkWidget *widget, cairo_t *context, RemminaProtocolWidget *gp)
344 {
345  TRACE_CALL(__func__);
346  rfContext *rfi = GET_PLUGIN_DATA(gp);
347  guint width, height;
348  gchar *msg;
349  cairo_text_extents_t extents;
350 
351  if (!rfi || !rfi->connected)
352  return FALSE;
353 
354 
355  if (rfi->is_reconnecting) {
356  /* FreeRDP is reconnecting, just show a message to the user */
357 
358  width = gtk_widget_get_allocated_width(widget);
359  height = gtk_widget_get_allocated_height(widget);
360 
361  /* Draw text */
362  msg = g_strdup_printf(_("Reconnection attempt %d of %d…"),
364 
365  cairo_select_font_face(context, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
366  cairo_set_font_size(context, 24);
367  cairo_set_source_rgb(context, 0.9, 0.9, 0.9);
368  cairo_text_extents(context, msg, &extents);
369  cairo_move_to(context, (width - (extents.width + extents.x_bearing)) / 2, (height - (extents.height + extents.y_bearing)) / 2);
370  cairo_show_text(context, msg);
371  g_free(msg);
372  } else {
373  /* Standard drawing: We copy the surface from RDP */
374 
375  if (!rfi->surface)
376  return FALSE;
377 
379  cairo_scale(context, rfi->scale_x, rfi->scale_y);
380 
381  cairo_surface_flush(rfi->surface);
382  cairo_set_source_surface(context, rfi->surface, 0, 0);
383  cairo_surface_mark_dirty(rfi->surface);
384 
385  cairo_set_operator(context, CAIRO_OPERATOR_SOURCE); // Ignore alpha channel from FreeRDP
386  cairo_paint(context);
387  }
388 
389  return TRUE;
390 }
391 
393 {
394  TRACE_CALL(__func__);
395  rfContext *rfi = GET_PLUGIN_DATA(gp);
396 
397  RemminaPluginRdpEvent rdp_event = { 0 };
398  GtkAllocation a;
399  gint desktopOrientation, desktopScaleFactor, deviceScaleFactor;
400 
401  RemminaFile *remminafile;
402 
403  if (!rfi || !rfi->connected || rfi->is_reconnecting)
404  return FALSE;
405 
407 
409  return FALSE;
410 
412  gint gpwidth, gpheight, prevwidth, prevheight;
413 
414  gchar *monitorids = NULL;
415  guint32 maxwidth = 0;
416  guint32 maxheight = 0;
417 
418  remmina_rdp_monitor_get(rfi, &monitorids, &maxwidth, &maxheight);
419 
420  REMMINA_PLUGIN_DEBUG("Sending preconfigured monitor layout");
421  if (rfi->dispcontext && rfi->dispcontext->SendMonitorLayout) {
422  remmina_rdp_settings_get_orientation_scale_prefs(&desktopOrientation, &desktopScaleFactor, &deviceScaleFactor);
423  gtk_widget_get_allocation(GTK_WIDGET(gp), &a);
424  gpwidth = a.width;
425  gpheight = a.height;
428 
429  if ((gpwidth != prevwidth || gpheight != prevheight) && gpwidth >= 200 && gpheight >= 200) {
430  if (rfi->rdpgfxchan) {
431  /* Workaround for FreeRDP issue #5417 */
432  if (gpwidth < AVC_MIN_DESKTOP_WIDTH)
433  gpwidth = AVC_MIN_DESKTOP_WIDTH;
434  if (gpheight < AVC_MIN_DESKTOP_HEIGHT)
435  gpheight = AVC_MIN_DESKTOP_HEIGHT;
436  }
438  if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) {
439  const rdpMonitor *base = freerdp_settings_get_pointer(rfi->settings, FreeRDP_MonitorDefArray);
440  for (gint i = 0; i < freerdp_settings_get_uint32(rfi->settings, FreeRDP_MonitorCount); ++i) {
441  const rdpMonitor *current = &base[i];
442  REMMINA_PLUGIN_DEBUG("Sending display layout n° %d", i);
443  rdp_event.monitor_layout.Flags = current->is_primary;
444  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Flags: %i", rdp_event.monitor_layout.Flags);
445  rdp_event.monitor_layout.Left = current->x;
446  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Left: %i", rdp_event.monitor_layout.Left);
447  rdp_event.monitor_layout.Top = current->y;
448  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - Top: %i", rdp_event.monitor_layout.Top);
449  rdp_event.monitor_layout.width = current->width;
450  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - width: %i", rdp_event.monitor_layout.width);
451  rdp_event.monitor_layout.height = current->height;
452  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - height: %i", rdp_event.monitor_layout.height);
453  rdp_event.monitor_layout.physicalWidth = current->attributes.physicalWidth;
454  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - physicalWidth: %i", rdp_event.monitor_layout.physicalWidth);
455  rdp_event.monitor_layout.physicalHeight = current->attributes.physicalHeight;
456  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - PhysicalHeight: %i", rdp_event.monitor_layout.physicalHeight);
457  if (current->attributes.orientation)
458  rdp_event.monitor_layout.desktopOrientation = current->attributes.orientation;
459  else
460  rdp_event.monitor_layout.desktopOrientation = rdp_event.monitor_layout.desktopOrientation;
461  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - desktopOrientation: %i", rdp_event.monitor_layout.desktopOrientation);
462  rdp_event.monitor_layout.desktopScaleFactor = rdp_event.monitor_layout.desktopScaleFactor;
463  REMMINA_PLUGIN_DEBUG("EVNT MON LAYOUT - ScaleFactorflag: %i", rdp_event.monitor_layout.desktopScaleFactor);
464  rdp_event.monitor_layout.deviceScaleFactor = rdp_event.monitor_layout.deviceScaleFactor;
465  }
466  remmina_rdp_event_event_push(gp, &rdp_event);
467  } else {
468  rdp_event.monitor_layout.width = gpwidth;
469  rdp_event.monitor_layout.height = gpheight;
470  rdp_event.monitor_layout.desktopOrientation = desktopOrientation;
471  rdp_event.monitor_layout.desktopScaleFactor = desktopScaleFactor;
472  rdp_event.monitor_layout.deviceScaleFactor = deviceScaleFactor;
473  remmina_rdp_event_event_push(gp, &rdp_event);
474  }
475  }
476  }
477 
478  g_free(monitorids);
479 
480  return FALSE;
481 }
482 
484 {
485  TRACE_CALL(__func__);
486  rfContext *rfi = GET_PLUGIN_DATA(gp);
487 
488  if (!rfi || !rfi->connected || rfi->is_reconnecting)
489  return;
491  g_source_remove(rfi->delayed_monitor_layout_handler);
493  }
495  rfi->delayed_monitor_layout_handler = g_timeout_add(500, (GSourceFunc)remmina_rdp_event_delayed_monitor_layout, gp);
496 }
497 
498 static gboolean remmina_rdp_event_on_configure(GtkWidget *widget, GdkEventConfigure *event, RemminaProtocolWidget *gp)
499 {
500  TRACE_CALL(__func__);
501  /* Called when gp changes its size or position */
502 
503  rfContext *rfi = GET_PLUGIN_DATA(gp);
504 
505  if (!rfi || !rfi->connected || rfi->is_reconnecting)
506  return FALSE;
507 
509 
510  /* If the scaler is not active, schedule a delayed remote resolution change */
512 
513 
514  return FALSE;
515 }
516 
517 static void remmina_rdp_event_translate_pos(RemminaProtocolWidget *gp, int ix, int iy, UINT16 *ox, UINT16 *oy)
518 {
519  TRACE_CALL(__func__);
520  rfContext *rfi = GET_PLUGIN_DATA(gp);
521 
522  /*
523  * Translate a position from local window coordinates (ix,iy) to
524  * RDP coordinates and put result on (*ox,*uy)
525  * */
526 
527  if (!rfi || !rfi->connected || rfi->is_reconnecting)
528  return;
529 
530  if ((rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED) && (rfi->scale_width >= 1) && (rfi->scale_height >= 1)) {
531  *ox = (UINT16)(ix * remmina_plugin_service->protocol_plugin_get_width(gp) / rfi->scale_width);
532  *oy = (UINT16)(iy * remmina_plugin_service->protocol_plugin_get_height(gp) / rfi->scale_height);
533  } else {
534  *ox = (UINT16)ix;
535  *oy = (UINT16)iy;
536  }
537 }
538 
539 static void remmina_rdp_event_reverse_translate_pos_reverse(RemminaProtocolWidget *gp, int ix, int iy, int *ox, int *oy)
540 {
541  TRACE_CALL(__func__);
542  rfContext *rfi = GET_PLUGIN_DATA(gp);
543 
544  /*
545  * Translate a position from RDP coordinates (ix,iy) to
546  * local window coordinates and put result on (*ox,*uy)
547  * */
548 
549  if (!rfi || !rfi->connected || rfi->is_reconnecting)
550  return;
551 
552  if ((rfi->scale == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED) && (rfi->scale_width >= 1) && (rfi->scale_height >= 1)) {
555  } else {
556  *ox = ix;
557  *oy = iy;
558  }
559 }
560 
562  TRACE_CALL(__func__);
563  RemminaPluginRdpEvent rdp_event = { 0 };
564  RemminaFile *remminafile;
565  rfContext *rfi = GET_PLUGIN_DATA(gp);
566 
568  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
569  return;
570 
572  rdp_event.mouse_event.flags = PTR_FLAGS_MOVE;
573  rdp_event.mouse_event.extended = FALSE;
574  rdp_event.mouse_event.x = rfi->last_x;
575  rdp_event.mouse_event.y = rfi->last_y;
576  remmina_rdp_event_event_push(gp, &rdp_event);
577 }
578 
579 static gboolean remmina_rdp_event_on_motion(GtkWidget *widget, GdkEventMotion *event, RemminaProtocolWidget *gp)
580 {
581  TRACE_CALL(__func__);
582  RemminaPluginRdpEvent rdp_event = { 0 };
583  RemminaFile *remminafile;
584  rfContext *rfi = GET_PLUGIN_DATA(gp);
585 
587  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
588  return FALSE;
589 
591  rdp_event.mouse_event.flags = PTR_FLAGS_MOVE;
592  rdp_event.mouse_event.extended = FALSE;
593 
594  remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
595  if (rfi != NULL){
596  rfi->last_x = rdp_event.mouse_event.x;
597  rfi->last_y = rdp_event.mouse_event.y;
598  }
599 
600  remmina_rdp_event_event_push(gp, &rdp_event);
601 
602  return TRUE;
603 }
604 
605 static gboolean remmina_rdp_event_on_button(GtkWidget *widget, GdkEventButton *event, RemminaProtocolWidget *gp)
606 {
607  TRACE_CALL(__func__);
608  gint flag;
609  gboolean extended = FALSE;
610  RemminaPluginRdpEvent rdp_event = { 0 };
611  gint primary, secondary;
612 
613  RemminaFile *remminafile;
614 
616  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
617  return FALSE;
618 
619  /* We bypass 2button-press and 3button-press events */
620  if ((event->type != GDK_BUTTON_PRESS) && (event->type != GDK_BUTTON_RELEASE))
621  return TRUE;
622 
623  flag = 0;
624 
625  if (remmina_plugin_service->file_get_int(remminafile, "left-handed", FALSE)) {
626  primary = PTR_FLAGS_BUTTON2;
627  secondary = PTR_FLAGS_BUTTON1;
628  } else {
629  primary = PTR_FLAGS_BUTTON1;
630  secondary = PTR_FLAGS_BUTTON2;
631  }
632 
633  switch (event->button) {
634  case 1:
635  flag |= primary;
636  break;
637  case 2:
638  flag |= PTR_FLAGS_BUTTON3;
639  break;
640  case 3:
641  flag |= secondary;
642  break;
643  case 8: /* back */
644  case 97: /* Xming */
645  extended = TRUE;
646  flag |= PTR_XFLAGS_BUTTON1;
647  break;
648  case 9: /* forward */
649  case 112: /* Xming */
650  extended = TRUE;
651  flag |= PTR_XFLAGS_BUTTON2;
652  break;
653  default:
654  return FALSE;
655  }
656 
657  if (event->type == GDK_BUTTON_PRESS) {
658  if (extended)
659  flag |= PTR_XFLAGS_DOWN;
660  else
661  flag |= PTR_FLAGS_DOWN;
662  }
663 
665  remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
666 
667  if (flag != 0) {
668  rdp_event.mouse_event.flags = flag;
669  rdp_event.mouse_event.extended = extended;
670  remmina_rdp_event_event_push(gp, &rdp_event);
671  }
672 
673  return TRUE;
674 }
675 
676 static gboolean remmina_rdp_event_on_scroll(GtkWidget *widget, GdkEventScroll *event, RemminaProtocolWidget *gp)
677 {
678  TRACE_CALL(__func__);
679  gint flag;
680  RemminaPluginRdpEvent rdp_event = { 0 };
681  float windows_delta;
682  RemminaFile *remminafile;
683 
685  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
686  return FALSE;
687 
688  flag = 0;
690 
691  /* See [MS-RDPBCGR] TS_POINTER_EVENT and WM_MOUSEWHEEL message */
692 
693  switch (event->direction) {
694  case GDK_SCROLL_UP:
695  flag = PTR_FLAGS_WHEEL | 0x0078; // 120 is one scroll unit defined in WM_MOUSEWHEEL
696  break;
697 
698  case GDK_SCROLL_DOWN:
699  flag = PTR_FLAGS_WHEEL | 0x0188; // -120 (one scroll unit) in 9 bits two's complement
700  break;
701 
702 #if GTK_CHECK_VERSION(3, 4, 0)
703  case GDK_SCROLL_SMOOTH:
704 
705  if (event->delta_y == 0.0)
706  return FALSE;
707 
708  windows_delta = event->delta_y * -120;
709 
710  if (windows_delta > 255)
711  windows_delta = 255;
712  if (windows_delta < -256)
713  windows_delta = -256;
714 
715  flag = PTR_FLAGS_WHEEL | ((short)windows_delta & WheelRotationMask);
716 
717  break;
718 #endif
719 
720  default:
721  return FALSE;
722  }
723 
724  rdp_event.mouse_event.flags = flag;
725  rdp_event.mouse_event.extended = FALSE;
726  remmina_rdp_event_translate_pos(gp, event->x, event->y, &rdp_event.mouse_event.x, &rdp_event.mouse_event.y);
727  remmina_rdp_event_event_push(gp, &rdp_event);
728 
729  return TRUE;
730 }
731 
732 static void remmina_rdp_event_init_keymap(rfContext *rfi, const gchar *strmap)
733 {
734  long int v1, v2;
735  const char *s;
736  char *endptr;
738 
739  if (strmap == NULL || strmap[0] == 0) {
740  rfi->keymap = NULL;
741  return;
742  }
743  s = strmap;
744  rfi->keymap = g_array_new(FALSE, TRUE, sizeof(RemminaPluginRdpKeymapEntry));
745  while (1) {
746  v1 = strtol(s, &endptr, 10);
747  if (endptr == s) break;
748  s = endptr;
749  if (*s != ':') break;
750  s++;
751  v2 = strtol(s, &endptr, 10);
752  if (endptr == s) break;
753  s = endptr;
754  ke.orig_keycode = v1 & 0x7fffffff;
755  ke.translated_keycode = v2 & 0x7fffffff;
756  g_array_append_val(rfi->keymap, ke);
757  if (*s != ',') break;
758  s++;
759  }
760  if (rfi->keymap->len == 0) {
761  g_array_unref(rfi->keymap);
762  rfi->keymap = NULL;
763  }
764 }
765 
766 static gboolean remmina_rdp_event_on_key(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
767 {
768  TRACE_CALL(__func__);
769  guint32 unicode_keyval;
770  guint16 hardware_keycode;
771  rfContext *rfi = GET_PLUGIN_DATA(gp);
772  RemminaPluginRdpEvent rdp_event;
774  RemminaFile *remminafile;
775  DWORD scancode = 0;
776  int ik;
777 
778  if (!rfi || !rfi->connected || rfi->is_reconnecting)
779  return FALSE;
780 
782  if (remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE))
783  return FALSE;
784 
785 #ifdef ENABLE_GTK_INSPECTOR_KEY
786  /* GTK inspector key is propagated up. Disabled by default.
787  * enable it by defining ENABLE_GTK_INSPECTOR_KEY */
788  if ((event->state & GDK_CONTROL_MASK) != 0 && (event->keyval == GDK_KEY_I || event->keyval == GDK_KEY_D))
789  return FALSE;
790 
791 #endif
792 
794  rdp_event.key_event.up = (event->type == GDK_KEY_PRESS ? false : true);
795  rdp_event.key_event.extended = false;
796 
797  switch (event->keyval) {
798  case GDK_KEY_Pause:
799  /*
800  * See https://msdn.microsoft.com/en-us/library/cc240584.aspx
801  * 2.2.8.1.1.3.1.1.1 Keyboard Event (TS_KEYBOARD_EVENT)
802  * for pause key management
803  */
804  rdp_event.key_event.key_code = 0x1D;
805  rdp_event.key_event.up = false;
806  remmina_rdp_event_event_push(gp, &rdp_event);
807  rdp_event.key_event.key_code = 0x45;
808  rdp_event.key_event.up = false;
809  remmina_rdp_event_event_push(gp, &rdp_event);
810  rdp_event.key_event.key_code = 0x1D;
811  rdp_event.key_event.up = true;
812  remmina_rdp_event_event_push(gp, &rdp_event);
813  rdp_event.key_event.key_code = 0x45;
814  rdp_event.key_event.up = true;
815  remmina_rdp_event_event_push(gp, &rdp_event);
816  break;
817 
818  default:
819  if (!rfi->use_client_keymap) {
820  hardware_keycode = event->hardware_keycode;
821  if (rfi->keymap) {
822  for (ik = 0; ik < rfi->keymap->len; ik++) {
823  kep = &g_array_index(rfi->keymap, RemminaPluginRdpKeymapEntry, ik);
824  if (hardware_keycode == kep->orig_keycode) {
825  hardware_keycode = kep->translated_keycode;
826  break;
827  }
828  }
829  }
830  scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(hardware_keycode);
831  if (scancode) {
832  rdp_event.key_event.key_code = scancode & 0xFF;
833  rdp_event.key_event.extended = scancode & 0x100;
834  remmina_rdp_event_event_push(gp, &rdp_event);
835  keypress_list_add(gp, rdp_event);
836  }
837  } else {
838  unicode_keyval = gdk_keyval_to_unicode(event->keyval);
839  /* Decide when whe should send a keycode or a Unicode character.
840  * - All non char keys (Shift, Alt, Super) should be sent as keycode
841  * - Space should be sent as keycode (see issue #1364)
842  * - All special keys (F1-F10, numeric pad, Home/End/Arrows/PgUp/PgDn/Insert/Delete) keycode
843  * - All key pressed while Ctrl or Alt or Super is down are not decoded by gdk_keyval_to_unicode(), so send it as keycode
844  * - All keycodes not translatable to unicode chars, as keycode
845  * - The rest as Unicode char
846  */
847  if (event->keyval >= 0xfe00 || // Arrows, Shift, Alt, Fn, num keypad…
848  event->hardware_keycode == 0x41 || // Spacebar
849  unicode_keyval == 0 || // Impossible to translate
850  (event->state & (GDK_MOD1_MASK | GDK_CONTROL_MASK | GDK_SUPER_MASK)) != 0 // A modifier not recognized by gdk_keyval_to_unicode()
851  ) {
852  scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(event->hardware_keycode);
853  rdp_event.key_event.key_code = scancode & 0xFF;
854  rdp_event.key_event.extended = scancode & 0x100;
855  if (rdp_event.key_event.key_code) {
856  remmina_rdp_event_event_push(gp, &rdp_event);
857  keypress_list_add(gp, rdp_event);
858  }
859  } else {
861  rdp_event.key_event.unicode_code = unicode_keyval;
862  rdp_event.key_event.extended = false;
863  remmina_rdp_event_event_push(gp, &rdp_event);
864  keypress_list_add(gp, rdp_event);
865  }
866  }
867  break;
868  }
869 
870  return TRUE;
871 }
872 
873 gboolean remmina_rdp_event_on_clipboard(GtkClipboard *gtkClipboard, GdkEvent *event, RemminaProtocolWidget *gp)
874 {
875  /* Signal handler for GTK clipboard owner-change */
876  TRACE_CALL(__func__);
877  RemminaPluginRdpEvent rdp_event = { 0 };
878  CLIPRDR_FORMAT_LIST *pFormatList;
879  GObject *new_owner;
880 
881  /* Usually "owner-change" is fired when a user presses "COPY" on the client
882  * OR when this plugin calls gtk_clipboard_set_with_owner()
883  * after receiving a RDP server format list in remmina_rdp_cliprdr_server_format_list()
884  * In the latter case, we must ignore owner change */
885 
886  REMMINA_PLUGIN_DEBUG("gp=%p: owner-change event received", gp);
887 
888  rfContext *rfi = GET_PLUGIN_DATA(gp);
889 
890  if (rfi)
892 
893  new_owner = gtk_clipboard_get_owner(gtkClipboard);
894  if (new_owner != (GObject *)gp) {
895  /* To do: avoid this when the new owner is another remmina protocol widget of
896  * the same remmina application */
897  REMMINA_PLUGIN_DEBUG("gp=%p owner-change: new owner is different than me: new=%p me=%p",
898  gp, new_owner, gp);
899 
900  REMMINA_PLUGIN_DEBUG("gp=%p owner-change: new owner is not me: Sending local clipboard format list to server.",
901  gp, new_owner, gp);
904  rdp_event.clipboard_formatlist.pFormatList = pFormatList;
905  remmina_rdp_event_event_push(gp, &rdp_event);
906  } else {
907  REMMINA_PLUGIN_DEBUG(" ... but I'm the owner!");
908  }
909  return TRUE;
910 }
911 
913 {
914  TRACE_CALL(__func__);
915  gchar *s;
916  gint flags;
917  rfContext *rfi = GET_PLUGIN_DATA(gp);
918  GtkClipboard *clipboard;
919  RemminaFile *remminafile;
920 
921  gboolean disable_smooth_scrolling = FALSE;
922 
923  if (!rfi) return;
925 
926  /* we get first the global preferences */
927  s = remmina_plugin_service->pref_get_value("rdp_disable_smooth_scrolling");
928  disable_smooth_scrolling = (s && s[0] == '1' ? TRUE : FALSE);
929  g_free(s), s = NULL;
930  /* Otherwise we use the connection profile specific setting */
931  disable_smooth_scrolling = remmina_plugin_service->file_get_int(remminafile, "disable-smooth-scrolling", disable_smooth_scrolling);
932 
933  REMMINA_PLUGIN_DEBUG("Disable smooth scrolling is set to %d", disable_smooth_scrolling);
934 
935  rfi->drawing_area = gtk_drawing_area_new();
936  gtk_widget_show(rfi->drawing_area);
937  gtk_container_add(GTK_CONTAINER(gp), rfi->drawing_area);
938 
939  gtk_widget_add_events(rfi->drawing_area, GDK_POINTER_MOTION_MASK
940  | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
941  | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK
942  | GDK_SCROLL_MASK | GDK_FOCUS_CHANGE_MASK);
943 
944  if (!disable_smooth_scrolling) {
945  REMMINA_PLUGIN_DEBUG("Adding GDK_SMOOTH_SCROLL_MASK");
946  gtk_widget_add_events(rfi->drawing_area, GDK_SMOOTH_SCROLL_MASK);
947  }
948 
949  gtk_widget_set_can_focus(rfi->drawing_area, TRUE);
950 
952 
953  s = remmina_plugin_service->pref_get_value("rdp_use_client_keymap");
954  rfi->use_client_keymap = (s && s[0] == '1' ? TRUE : FALSE);
955  g_free(s), s = NULL;
956 
957  /* Read special keymap from profile file, if exists */
959 
960  if (rfi->use_client_keymap && rfi->keymap)
961  fprintf(stderr, "RDP profile error: you cannot define both rdp_map_hardware_keycode and have 'Use client keyboard mapping' enabled\n");
962 
963  g_signal_connect(G_OBJECT(rfi->drawing_area), "draw",
964  G_CALLBACK(remmina_rdp_event_on_draw), gp);
965  g_signal_connect(G_OBJECT(rfi->drawing_area), "configure-event",
966  G_CALLBACK(remmina_rdp_event_on_configure), gp);
967  g_signal_connect(G_OBJECT(rfi->drawing_area), "motion-notify-event",
968  G_CALLBACK(remmina_rdp_event_on_motion), gp);
969  g_signal_connect(G_OBJECT(rfi->drawing_area), "button-press-event",
970  G_CALLBACK(remmina_rdp_event_on_button), gp);
971  g_signal_connect(G_OBJECT(rfi->drawing_area), "button-release-event",
972  G_CALLBACK(remmina_rdp_event_on_button), gp);
973  g_signal_connect(G_OBJECT(rfi->drawing_area), "scroll-event",
974  G_CALLBACK(remmina_rdp_event_on_scroll), gp);
975  g_signal_connect(G_OBJECT(rfi->drawing_area), "key-press-event",
976  G_CALLBACK(remmina_rdp_event_on_key), gp);
977  g_signal_connect(G_OBJECT(rfi->drawing_area), "key-release-event",
978  G_CALLBACK(remmina_rdp_event_on_key), gp);
979  g_signal_connect(G_OBJECT(rfi->drawing_area), "focus-in-event",
980  G_CALLBACK(remmina_rdp_event_on_focus_in), gp);
987  //g_signal_connect(G_OBJECT(gtk_widget_get_toplevel(rfi->drawing_area)), "map-event",
988  // G_CALLBACK(remmina_rdp_event_on_map), gp);
989  //g_signal_connect(G_OBJECT(gtk_widget_get_toplevel(rfi->drawing_area)), "unmap-event",
990  // G_CALLBACK(remmina_rdp_event_on_unmap), gp);
991 
992  if (!remmina_plugin_service->file_get_int(remminafile, "disableclipboard", FALSE)) {
993  clipboard = gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD);
994  rfi->clipboard.clipboard_handler = g_signal_connect(clipboard, "owner-change", G_CALLBACK(remmina_rdp_event_on_clipboard), gp);
995  }
996 
997  rfi->pressed_keys = g_array_new(FALSE, TRUE, sizeof(RemminaPluginRdpEvent));
998  rfi->event_queue = g_async_queue_new_full(g_free);
999  rfi->ui_queue = g_async_queue_new();
1000  pthread_mutex_init(&rfi->ui_queue_mutex, NULL);
1001 
1002  if (pipe(rfi->event_pipe)) {
1003  g_print("Error creating pipes.\n");
1004  rfi->event_pipe[0] = -1;
1005  rfi->event_pipe[1] = -1;
1006  rfi->event_handle = NULL;
1007  } else {
1008  flags = fcntl(rfi->event_pipe[0], F_GETFL, 0);
1009  fcntl(rfi->event_pipe[0], F_SETFL, flags | O_NONBLOCK);
1010  rfi->event_handle = CreateFileDescriptorEvent(NULL, FALSE, FALSE, rfi->event_pipe[0], WINPR_FD_READ);
1011  if (!rfi->event_handle)
1012  g_print("CreateFileDescriptorEvent() failed\n");
1013  }
1014 
1015  rfi->object_table = g_hash_table_new_full(NULL, NULL, NULL, g_free);
1016 
1017  rfi->display = gdk_display_get_default();
1018 
1019 #if GTK_CHECK_VERSION(3, 22, 0)
1020  GdkVisual *visual = gdk_screen_get_system_visual(
1021  gdk_display_get_default_screen(rfi->display));
1022  rfi->bpp = gdk_visual_get_depth(visual);
1023 #else
1024  rfi->bpp = gdk_visual_get_best_depth();
1025 #endif
1026 }
1027 
1029 {
1030  TRACE_CALL(__func__);
1031 
1032  switch (obj->type) {
1034  free(obj->nocodec.bitmap);
1035  break;
1036 
1037  default:
1038  break;
1039  }
1040 
1041  g_free(obj);
1042 }
1043 
1045 {
1046  TRACE_CALL(__func__);
1047  rfContext *rfi = GET_PLUGIN_DATA(gp);
1049 
1050  if (!rfi) return;
1051 
1052  /* unregister the clipboard monitor */
1053  if (rfi->clipboard.clipboard_handler) {
1054  g_signal_handler_disconnect(G_OBJECT(gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD)), rfi->clipboard.clipboard_handler);
1055  rfi->clipboard.clipboard_handler = 0;
1056  }
1057  if (rfi->delayed_monitor_layout_handler) {
1058  g_source_remove(rfi->delayed_monitor_layout_handler);
1060  }
1061  if (rfi->ui_handler) {
1062  g_source_remove(rfi->ui_handler);
1063  rfi->ui_handler = 0;
1064  }
1065  while ((ui = (RemminaPluginRdpUiObject *)g_async_queue_try_pop(rfi->ui_queue)) != NULL)
1067  if (rfi->surface) {
1068  cairo_surface_mark_dirty(rfi->surface);
1069  cairo_surface_destroy(rfi->surface);
1070  rfi->surface = NULL;
1071  }
1072 
1073  g_hash_table_destroy(rfi->object_table);
1074 
1075  g_array_free(rfi->pressed_keys, TRUE);
1076  if (rfi->keymap) {
1077  g_array_free(rfi->keymap, TRUE);
1078  rfi->keymap = NULL;
1079  }
1080  g_async_queue_unref(rfi->event_queue);
1081  rfi->event_queue = NULL;
1082  g_async_queue_unref(rfi->ui_queue);
1083  rfi->ui_queue = NULL;
1084  pthread_mutex_destroy(&rfi->ui_queue_mutex);
1085 
1086  if (rfi->event_handle) {
1087  CloseHandle(rfi->event_handle);
1088  rfi->event_handle = NULL;
1089  }
1090 
1091  close(rfi->event_pipe[0]);
1092  close(rfi->event_pipe[1]);
1093 }
1094 
1096 {
1097  int stride;
1098  rdpGdi *gdi;
1099 
1100  if (!rfi)
1101  return;
1102 
1103  gdi = ((rdpContext *)rfi)->gdi;
1104 
1105  if (!gdi)
1106  return;
1107 
1108  if (rfi->surface) {
1109  cairo_surface_mark_dirty(rfi->surface);
1110  cairo_surface_destroy(rfi->surface);
1111  rfi->surface = NULL;
1112  }
1113  stride = cairo_format_stride_for_width(rfi->cairo_format, gdi->width);
1114  rfi->surface = cairo_image_surface_create_for_data((unsigned char *)gdi->primary_buffer, rfi->cairo_format, gdi->width, gdi->height, stride);
1115  cairo_surface_flush(rfi->surface);
1116 }
1117 
1119 {
1120  TRACE_CALL(__func__);
1121  gint width, height;
1122  rdpGdi *gdi;
1123  rfContext *rfi = GET_PLUGIN_DATA(gp);
1124 
1127 
1128  gdi = ((rdpContext *)rfi)->gdi;
1129 
1131 
1132  /* See if we also must rellocate rfi->surface with different width and height,
1133  * this usually happens after a DesktopResize RDP event*/
1134 
1135  if (rfi->surface && (cairo_image_surface_get_width(rfi->surface) != gdi->width ||
1136  cairo_image_surface_get_height(rfi->surface) != gdi->height)) {
1137  /* Destroys and recreate rfi->surface with new width and height */
1138  cairo_surface_mark_dirty(rfi->surface);
1139  cairo_surface_destroy(rfi->surface);
1140  rfi->surface = NULL;
1142  } else if (rfi->surface == NULL) {
1144  }
1145 
1146  /* Send gdi->width and gdi->height obtained from remote server to gp plugin,
1147  * so they will be saved when closing connection */
1148  if (width != gdi->width)
1150  if (height != gdi->height)
1152 
1154 
1156  /* In scaled mode and autores mode, drawing_area will get its dimensions from its parent */
1157  gtk_widget_set_size_request(rfi->drawing_area, -1, -1);
1158  else
1159  /* In non scaled mode, the plugins forces dimensions of drawing area */
1160  gtk_widget_set_size_request(rfi->drawing_area, width, height);
1162 }
1163 
1165 {
1166  TRACE_CALL(__func__);
1167  rfContext *rfi = GET_PLUGIN_DATA(gp);
1168  rdpGdi *gdi;
1169 
1170  gdi = ((rdpContext *)rfi)->gdi;
1171 
1172  gtk_widget_realize(rfi->drawing_area);
1173 
1175  gtk_widget_queue_draw_area(rfi->drawing_area, 0, 0, gdi->width, gdi->height);
1176 
1178 
1180  const gchar *host = freerdp_settings_get_string (rfi->settings, FreeRDP_ServerHostname);
1181  // TRANSLATORS: the placeholder may be either an IP/FQDN or a server hostname
1182  REMMINA_PLUGIN_AUDIT(_("Connected to %s via RDP"), host);
1183 }
1184 
1186 {
1187  TRACE_CALL(__func__);
1188  rfContext *rfi = GET_PLUGIN_DATA(gp);
1189 
1190  gdk_window_invalidate_rect(gtk_widget_get_window(rfi->drawing_area), NULL, TRUE);
1191 }
1192 
1194 {
1195  TRACE_CALL(__func__);
1196  GdkPixbuf *pixbuf;
1197  rfContext *rfi = GET_PLUGIN_DATA(gp);
1198  rdpPointer *pointer = (rdpPointer *)ui->cursor.pointer;
1199  cairo_surface_t *surface;
1200  UINT8 *data = malloc(pointer->width * pointer->height * 4);
1201 
1202  if (!freerdp_image_copy_from_pointer_data(
1203  (BYTE *)data, PIXEL_FORMAT_BGRA32,
1204  pointer->width * 4, 0, 0, pointer->width, pointer->height,
1205  pointer->xorMaskData, pointer->lengthXorMask,
1206  pointer->andMaskData, pointer->lengthAndMask,
1207  pointer->xorBpp, &(ui->cursor.context->gdi->palette))) {
1208  free(data);
1209  return FALSE;
1210  }
1211 
1212  surface = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, pointer->width, pointer->height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pointer->width));
1213  cairo_surface_flush(surface);
1214  pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, pointer->width, pointer->height);
1215  cairo_surface_mark_dirty(surface);
1216  cairo_surface_destroy(surface);
1217  free(data);
1218  ((rfPointer *)ui->cursor.pointer)->cursor = gdk_cursor_new_from_pixbuf(rfi->display, pixbuf, pointer->xPos, pointer->yPos);
1219  g_object_unref(pixbuf);
1220 
1221  return TRUE;
1222 }
1223 
1225 {
1226  TRACE_CALL(__func__);
1227  g_object_unref(ui->cursor.pointer->cursor);
1228  ui->cursor.pointer->cursor = NULL;
1229 }
1230 
1232 {
1233  TRACE_CALL(__func__);
1234  GdkWindow *w, *nw;
1235  gint nx, ny, wx, wy;
1236 
1237 #if GTK_CHECK_VERSION(3, 20, 0)
1238  GdkSeat *seat;
1239 #else
1240  GdkDeviceManager *manager;
1241 #endif
1242  GdkDevice *dev;
1243  rfContext *rfi = GET_PLUGIN_DATA(gp);
1244 
1245  if (rfi == NULL)
1246  return FALSE;
1247 
1248  w = gtk_widget_get_window(rfi->drawing_area);
1249 #if GTK_CHECK_VERSION(3, 20, 0)
1250  seat = gdk_display_get_default_seat(gdk_display_get_default());
1251  dev = gdk_seat_get_pointer(seat);
1252 #else
1253  manager = gdk_display_get_device_manager(gdk_display_get_default());
1254  dev = gdk_device_manager_get_client_pointer(manager);
1255 #endif
1256 
1257  nw = gdk_device_get_window_at_position(dev, NULL, NULL);
1258 
1259  if (nw == w) {
1260  nx = 0;
1261  ny = 0;
1263  gdk_window_get_root_coords(w, nx, ny, &wx, &wy);
1264  gdk_device_warp(dev, gdk_window_get_screen(w), wx, wy);
1265  }
1266  return TRUE;
1267 }
1268 
1270 {
1271  TRACE_CALL(__func__);
1272  rfContext *rfi = GET_PLUGIN_DATA(gp);
1273 
1274  switch (ui->cursor.type) {
1276  ui->retval = remmina_rdp_event_create_cursor(gp, ui) ? 1 : 0;
1277  break;
1278 
1281  break;
1282 
1284  gdk_window_set_cursor(gtk_widget_get_window(rfi->drawing_area), ui->cursor.pointer->cursor);
1285  ui->retval = 1;
1286  break;
1287 
1289  ui->retval = remmina_rdp_event_set_pointer_position(gp, ui->pos.x, ui->pos.y) ? 1 : 0;
1290  break;
1291 
1293  gdk_window_set_cursor(gtk_widget_get_window(rfi->drawing_area),
1294  gdk_cursor_new_for_display(gdk_display_get_default(),
1295  GDK_BLANK_CURSOR));
1296  ui->retval = 1;
1297  break;
1298 
1300  gdk_window_set_cursor(gtk_widget_get_window(rfi->drawing_area), NULL);
1301  ui->retval = 1;
1302  break;
1303  }
1304 }
1305 
1307 {
1308  TRACE_CALL(__func__);
1310 }
1311 
1313 {
1314  TRACE_CALL(__func__);
1315  rfContext *rfi = GET_PLUGIN_DATA(gp);
1316 
1317  if (!rfi || !rfi->connected || rfi->is_reconnecting)
1318  return;
1320 }
1321 
1323 {
1324  TRACE_CALL(__func__);
1325  rfContext *rfi = GET_PLUGIN_DATA(gp);
1326 
1327  cairo_surface_mark_dirty(rfi->surface);
1328  cairo_surface_destroy(rfi->surface);
1329  rfi->surface = NULL;
1330 }
1331 
1333 {
1334  TRACE_CALL(__func__);
1335  switch (ui->event.type) {
1338  break;
1341  break;
1342  }
1343 }
1344 
1346 {
1347  TRACE_CALL(__func__);
1348  switch (ui->type) {
1351  break;
1352 
1355  break;
1356 
1359  break;
1360 
1361  case REMMINA_RDP_UI_CURSOR:
1362  remmina_rdp_event_cursor(gp, ui);
1363  break;
1364 
1367  break;
1368 
1369  case REMMINA_RDP_UI_EVENT:
1371  break;
1372 
1373  default:
1374  break;
1375  }
1376 }
1377 
1379 {
1380  TRACE_CALL(__func__);
1381 
1382  rfContext *rfi = GET_PLUGIN_DATA(gp);
1384 
1385  pthread_mutex_lock(&rfi->ui_queue_mutex);
1386  ui = (RemminaPluginRdpUiObject *)g_async_queue_try_pop(rfi->ui_queue);
1387  if (ui) {
1388  pthread_mutex_lock(&ui->sync_wait_mutex);
1389  if (!rfi->thread_cancelled)
1391  // Should we signal the caller thread to unlock ?
1392  if (ui->sync) {
1393  ui->complete = TRUE;
1394  pthread_cond_signal(&ui->sync_wait_cond);
1395  pthread_mutex_unlock(&ui->sync_wait_mutex);
1396  } else {
1398  }
1399 
1400  pthread_mutex_unlock(&rfi->ui_queue_mutex);
1401  return TRUE;
1402  } else {
1403  rfi->ui_handler = 0;
1404  pthread_mutex_unlock(&rfi->ui_queue_mutex);
1405  return FALSE;
1406  }
1407 }
1408 
1410 {
1411  TRACE_CALL(__func__);
1412  rfContext *rfi = GET_PLUGIN_DATA(gp);
1413  gboolean ui_sync_save;
1414  int oldcanceltype;
1415 
1416  if (!rfi || rfi->thread_cancelled)
1417  return;
1418 
1421  return;
1422  }
1423 
1424  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldcanceltype);
1425 
1426  pthread_mutex_lock(&rfi->ui_queue_mutex);
1427 
1428  ui_sync_save = ui->sync;
1429  ui->complete = FALSE;
1430 
1431  if (ui_sync_save) {
1432  pthread_mutex_init(&ui->sync_wait_mutex, NULL);
1433  pthread_cond_init(&ui->sync_wait_cond, NULL);
1434  }
1435 
1436  ui->complete = FALSE;
1437 
1438  g_async_queue_push(rfi->ui_queue, ui);
1439 
1440  if (!rfi->ui_handler)
1441  rfi->ui_handler = IDLE_ADD((GSourceFunc)remmina_rdp_event_process_ui_queue, gp);
1442 
1443  if (ui_sync_save) {
1444  /* Wait for main thread function completion before returning */
1445  pthread_mutex_lock(&ui->sync_wait_mutex);
1446  pthread_mutex_unlock(&rfi->ui_queue_mutex);
1447  while (!ui->complete)
1448  pthread_cond_wait(&ui->sync_wait_cond, &ui->sync_wait_mutex);
1449  pthread_cond_destroy(&ui->sync_wait_cond);
1450  pthread_mutex_destroy(&ui->sync_wait_mutex);
1451  } else {
1452  pthread_mutex_unlock(&rfi->ui_queue_mutex);
1453  }
1454  pthread_setcanceltype(oldcanceltype, NULL);
1455 }
1456 
1458 {
1459  ui->sync = FALSE;
1461 }
1462 
1464 {
1465  TRACE_CALL(__func__);
1466  int retval;
1467 
1468  ui->sync = TRUE;
1470  retval = ui->retval;
1472  return retval;
1473 }
1474 
1476 {
1477  TRACE_CALL(__func__);
1478  void *rp;
1479 
1480  ui->sync = TRUE;
1482  rp = ui->retptr;
1484  return rp;
1485 }
struct remmina_plugin_rdp_event::@42::@45 mouse_event
gboolean thread_cancelled
Definition: rdp_plugin.h:332
-
static void remmina_rdp_event_free_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1221
+
static void remmina_rdp_event_free_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1224
gboolean is_reconnecting
Definition: rdp_plugin.h:344
gulong clipboard_handler
Definition: rdp_plugin.h:140
-
static void remmina_rdp_event_create_cairo_surface(rfContext *rfi)
Definition: rdp_event.c:1092
+
static void remmina_rdp_event_create_cairo_surface(rfContext *rfi)
Definition: rdp_event.c:1095
RemminaScaleMode(* remmina_protocol_widget_get_current_scale_mode)(RemminaProtocolWidget *gp)
Definition: plugin.h:172
-
static void remmina_rdp_event_process_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1329
+
static void remmina_rdp_event_process_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1332
guint delayed_monitor_layout_handler
Definition: rdp_plugin.h:360
struct remmina_plugin_rdp_ui_object::@50::@53 cursor
static void remmina_rdp_event_update_scale_factor(RemminaProtocolWidget *gp)
Definition: rdp_event.c:312
@@ -122,30 +122,30 @@ $(document).ready(function(){initNavTree('rdp__event_8c_source.html','');});
void remmina_rdp_clipboard_abort_client_format_data_request(rfContext *rfi)
Definition: rdp_cliprdr.c:947
GdkDisplay * display
Definition: rdp_plugin.h:364
-
void * remmina_rdp_event_queue_ui_sync_retptr(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1472
+
void * remmina_rdp_event_queue_ui_sync_retptr(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1475
struct remmina_plugin_rdp_event::@42::@49 monitor_layout
GAsyncQueue * ui_queue
Definition: rdp_plugin.h:375
void remmina_rdp_event_update_rect(RemminaProtocolWidget *gp, gint x, gint y, gint w, gint h)
Definition: rdp_event.c:301
pthread_mutex_t sync_wait_mutex
Definition: rdp_plugin.h:269
int reconnect_nattempt
Definition: rdp_plugin.h:352
-
static gboolean remmina_rdp_event_process_ui_queue(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1375
-
static BOOL remmina_rdp_event_create_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1190
+
static gboolean remmina_rdp_event_process_ui_queue(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1378
+
static BOOL remmina_rdp_event_create_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1193
static void remmina_rdp_event_release_key(RemminaProtocolWidget *gp, RemminaPluginRdpEvent rdp_event)
Definition: rdp_event.c:195
-
static void remmina_rdp_event_queue_ui(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1406
+
static void remmina_rdp_event_queue_ui(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1409
gint(* protocol_plugin_get_width)(RemminaProtocolWidget *gp)
Definition: plugin.h:168
gdouble scale_x
Definition: rdp_plugin.h:358
gint(* file_get_int)(RemminaFile *remminafile, const gchar *setting, gint default_value)
Definition: plugin.h:222
-
static gboolean remmina_rdp_event_on_key(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:763
-
void remmina_rdp_event_free_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *obj)
Definition: rdp_event.c:1025
+
static gboolean remmina_rdp_event_on_key(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:766
+
void remmina_rdp_event_free_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *obj)
Definition: rdp_event.c:1028
static gboolean remmina_rdp_event_on_motion(GtkWidget *widget, GdkEventMotion *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:579
void(* protocol_plugin_update_align)(RemminaProtocolWidget *gp)
Definition: plugin.h:187
void(* protocol_plugin_signal_connection_opened)(RemminaProtocolWidget *gp)
Definition: plugin.h:186
void remmina_rdp_event_process_clipboard(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_cliprdr.c:914
int reconnect_maxattempts
Definition: rdp_plugin.h:351
-
static void remmina_rdp_ui_event_update_scale(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1303
+
static void remmina_rdp_ui_event_update_scale(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1306
static gboolean remmina_rdp_event_on_focus_in(GtkWidget *widget, GdkEventKey *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:104
RemminaPluginRdpEventType type
Definition: rdp_plugin.h:191
UINT16 last_x
Definition: rdp_plugin.h:383
@@ -161,20 +161,20 @@ $(document).ready(function(){initNavTree('rdp__event_8c_source.html','');});
GtkWidget * drawing_area
Definition: rdp_plugin.h:355
cairo_format_t cairo_format
Definition: rdp_plugin.h:367
static gboolean remmina_rdp_event_on_configure(GtkWidget *widget, GdkEventConfigure *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:498
-
int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1460
-
void remmina_rdp_event_init(RemminaProtocolWidget *gp)
Definition: rdp_event.c:909
+
int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1463
+
void remmina_rdp_event_init(RemminaProtocolWidget *gp)
Definition: rdp_event.c:912
gboolean use_client_keymap
Definition: rdp_plugin.h:361
-
static gboolean remmina_rdp_event_on_scroll(GtkWidget *widget, GdkEventScroll *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:673
+
static gboolean remmina_rdp_event_on_scroll(GtkWidget *widget, GdkEventScroll *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:676
gchar *(* pref_get_value)(const gchar *key)
Definition: plugin.h:227
-
static void remmina_rdp_event_reconnect_progress(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1182
+
static void remmina_rdp_event_reconnect_progress(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1185
GArray * keymap
Definition: rdp_plugin.h:388
UINT16 last_y
Definition: rdp_plugin.h:384
unsigned orig_keycode
Definition: rdp_plugin.h:315
static void remmina_rdp_event_scale_area(RemminaProtocolWidget *gp, gint *x, gint *y, gint *w, gint *h)
Definition: rdp_event.c:236
-
void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1454
-
static gboolean remmina_rdp_event_on_button(GtkWidget *widget, GdkEventButton *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:602
+
void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1457
+
static gboolean remmina_rdp_event_on_button(GtkWidget *widget, GdkEventButton *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:605
struct remmina_plugin_rdp_event::@42::@44 key_event
struct remmina_plugin_rdp_event::@42::@46 clipboard_formatlist
@@ -185,21 +185,21 @@ $(document).ready(function(){initNavTree('rdp__event_8c_source.html','');});
CLIPRDR_FORMAT_LIST * remmina_rdp_cliprdr_get_client_format_list(RemminaProtocolWidget *gp)
Definition: rdp_cliprdr.c:709
pthread_cond_t sync_wait_cond
Definition: rdp_plugin.h:270
rfClipboard clipboard
Definition: rdp_plugin.h:386
-
static void remmina_rdp_event_init_keymap(rfContext *rfi, const gchar *strmap)
Definition: rdp_event.c:729
+
static void remmina_rdp_event_init_keymap(rfContext *rfi, const gchar *strmap)
Definition: rdp_event.c:732
HANDLE event_handle
Definition: rdp_plugin.h:382
static void remmina_rdp_event_translate_pos(RemminaProtocolWidget *gp, int ix, int iy, UINT16 *ox, UINT16 *oy)
Definition: rdp_event.c:517
-
static void remmina_rdp_ui_event_destroy_cairo_surface(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1319
-
void remmina_rdp_event_uninit(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1041
+
static void remmina_rdp_ui_event_destroy_cairo_surface(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1322
+
void remmina_rdp_event_uninit(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1044
void remmina_rdp_mouse_jitter(RemminaProtocolWidget *gp)
Definition: rdp_event.c:561
RemminaFile *(* protocol_plugin_get_file)(RemminaProtocolWidget *gp)
Definition: plugin.h:178
GHashTable * object_table
Definition: rdp_plugin.h:373
-
gboolean remmina_rdp_event_on_clipboard(GtkClipboard *gtkClipboard, GdkEvent *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:870
+
gboolean remmina_rdp_event_on_clipboard(GtkClipboard *gtkClipboard, GdkEvent *event, RemminaProtocolWidget *gp)
Definition: rdp_event.c:873
static void remmina_rdp_event_reverse_translate_pos_reverse(RemminaProtocolWidget *gp, int ix, int iy, int *ox, int *oy)
Definition: rdp_event.c:539
-
static void remmina_rdp_event_process_ui_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1342
+
static void remmina_rdp_event_process_ui_event(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1345
static void keypress_list_add(RemminaProtocolWidget *gp, RemminaPluginRdpEvent rdp_event)
Definition: rdp_event.c:221
gboolean connected
Definition: rdp_plugin.h:343
@@ -207,16 +207,16 @@ $(document).ready(function(){initNavTree('rdp__event_8c_source.html','');});
freerdp * instance
Definition: rdp_plugin.h:327
DispClientContext * dispcontext
Definition: rdp_plugin.h:335
-
static BOOL remmina_rdp_event_set_pointer_position(RemminaProtocolWidget *gp, gint x, gint y)
Definition: rdp_event.c:1228
+
static BOOL remmina_rdp_event_set_pointer_position(RemminaProtocolWidget *gp, gint x, gint y)
Definition: rdp_event.c:1231
void(* protocol_plugin_register_hostkey)(RemminaProtocolWidget *gp, GtkWidget *widget)
Definition: plugin.h:180
-
static void remmina_rdp_event_connected(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1161
+
static void remmina_rdp_event_connected(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1164
GArray * pressed_keys
Definition: rdp_plugin.h:379
-
void remmina_rdp_event_update_scale(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1115
+
void remmina_rdp_event_update_scale(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1118
rdpSettings * settings
Definition: rdp_plugin.h:326
gint scale_height
Definition: rdp_plugin.h:357
void(* protocol_plugin_set_height)(RemminaProtocolWidget *gp, gint height)
Definition: plugin.h:171
Definition: rdp_plugin.h:314
-
void remmina_rdp_event_unfocus(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1309
+
void remmina_rdp_event_unfocus(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1312
struct remmina_plugin_rdp_ui_object::@50::@55 nocodec
@@ -225,7 +225,7 @@ $(document).ready(function(){initNavTree('rdp__event_8c_source.html','');});
void remmina_rdp_event_event_push(RemminaProtocolWidget *gp, const RemminaPluginRdpEvent *e)
Definition: rdp_event.c:150
-
static void remmina_rdp_event_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1266
+
static void remmina_rdp_event_cursor(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1269
gboolean remmina_rdp_event_on_map(RemminaProtocolWidget *gp)
Definition: rdp_event.c:52
struct remmina_plugin_rdp_ui_object::@50::@58 pos
gboolean(* is_main_thread)(void)
Definition: plugin.h:250
diff --git a/public/rdp__event_8h.html b/public/rdp__event_8h.html index 82f570a95..ac09de5d6 100644 --- a/public/rdp__event_8h.html +++ b/public/rdp__event_8h.html @@ -136,7 +136,7 @@ Functions

Fixme: This comment needed for TS_SUPPRESS_OUTPUT_PDU But it works only when we stay in the same window mode, if we switch to fullscreen, for instance, the object refernce is lost, so we loose these events.

-

Definition at line 909 of file rdp_event.c.

+

Definition at line 912 of file rdp_event.c.

@@ -206,7 +206,7 @@ Functions
-

Definition at line 1454 of file rdp_event.c.

+

Definition at line 1457 of file rdp_event.c.

@@ -236,7 +236,7 @@ Functions
-

Definition at line 1460 of file rdp_event.c.

+

Definition at line 1463 of file rdp_event.c.

@@ -266,7 +266,7 @@ Functions
-

Definition at line 1472 of file rdp_event.c.

+

Definition at line 1475 of file rdp_event.c.

@@ -306,7 +306,7 @@ Functions
-

Definition at line 1309 of file rdp_event.c.

+

Definition at line 1312 of file rdp_event.c.

@@ -326,7 +326,7 @@ Functions
-

Definition at line 1041 of file rdp_event.c.

+

Definition at line 1044 of file rdp_event.c.

@@ -394,7 +394,7 @@ Functions
-

Definition at line 1115 of file rdp_event.c.

+

Definition at line 1118 of file rdp_event.c.

diff --git a/public/rdp__event_8h_source.html b/public/rdp__event_8h_source.html index 14faebbff..3b0330210 100644 --- a/public/rdp__event_8h_source.html +++ b/public/rdp__event_8h_source.html @@ -87,21 +87,21 @@ $(document).ready(function(){initNavTree('rdp__event_8h_source.html','');});
Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2010-2011 Vic Lee
4  * Copyright (C) 2017-2023 Antenore Gatta, Giovanni Panozzo
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  * In addition, as a special exception, the copyright holders give
22  * permission to link the code of portions of this program with the
23  * OpenSSL library under certain conditions as described in each
24  * individual source file, and distribute linked combinations
25  * including the two.
26  * You must obey the GNU General Public License in all respects
27  * for all of the code used other than OpenSSL. * If you modify
28  * file(s) with this exception, you may extend this exception to your
29  * version of the file(s), but you are not obligated to do so. * If you
30  * do not wish to do so, delete this exception statement from your
31  * version. * If you delete this exception statement from all source
32  * files in the program, then also delete it here.
33  *
34  */
35 
36 #pragma once
37 
38 #include <glib.h>
39 #include "common/remmina_plugin.h"
40 #include "rdp_plugin.h"
41 
42 G_BEGIN_DECLS
43 
44 
50 void remmina_rdp_event_update_rect(RemminaProtocolWidget *gp, gint x, gint y, gint w, gint h);
57 
58 G_END_DECLS
void remmina_rdp_event_update_rect(RemminaProtocolWidget *gp, gint x, gint y, gint w, gint h)
Definition: rdp_event.c:301
-
void remmina_rdp_event_unfocus(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1309
+
void remmina_rdp_event_unfocus(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1312
-
G_BEGIN_DECLS void remmina_rdp_event_init(RemminaProtocolWidget *gp)
Definition: rdp_event.c:909
-
void remmina_rdp_event_update_scale(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1115
-
int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1460
+
G_BEGIN_DECLS void remmina_rdp_event_init(RemminaProtocolWidget *gp)
Definition: rdp_event.c:912
+
void remmina_rdp_event_update_scale(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1118
+
int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1463
-
void remmina_rdp_event_uninit(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1041
+
void remmina_rdp_event_uninit(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1044
void remmina_rdp_mouse_jitter(RemminaProtocolWidget *gp)
Definition: rdp_event.c:561
-
void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1454
+
void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1457
gboolean remmina_rdp_event_on_unmap(RemminaProtocolWidget *gp)
Definition: rdp_event.c:74
void remmina_rdp_event_send_delayed_monitor_layout(RemminaProtocolWidget *gp)
Definition: rdp_event.c:483
gboolean remmina_rdp_event_on_map(RemminaProtocolWidget *gp)
Definition: rdp_event.c:52
-
void * remmina_rdp_event_queue_ui_sync_retptr(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1472
+
void * remmina_rdp_event_queue_ui_sync_retptr(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1475
diff --git a/public/rdp__graphics_8c_source.html b/public/rdp__graphics_8c_source.html index f9bf12a91..4380f01b4 100644 --- a/public/rdp__graphics_8c_source.html +++ b/public/rdp__graphics_8c_source.html @@ -116,7 +116,7 @@ $(document).ready(function(){initNavTree('rdp__graphics_8c_source.html','');});
static BOOL rf_Glyph_EndDraw(rdpContext *context, INT32 x, INT32 y, INT32 width, INT32 height, UINT32 bgcolor, UINT32 fgcolor)
Definition: rdp_graphics.c:363
Pixmap pixmap
Definition: rdp_plugin.h:174
-
int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1460
+
int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1463
gint scanline_pad
Definition: rdp_plugin.h:369
static BOOL rf_Glyph_BeginDraw(rdpContext *context, INT32 x, INT32 y, INT32 width, INT32 height, UINT32 bgcolor, UINT32 fgcolor, BOOL fOpRedundant)
Definition: rdp_graphics.c:335
Definition: rdp_plugin.h:156
diff --git a/public/rdp__plugin_8c.html b/public/rdp__plugin_8c.html index 90c02f893..99842642b 100644 --- a/public/rdp__plugin_8c.html +++ b/public/rdp__plugin_8c.html @@ -268,7 +268,7 @@ Variables
-

Definition at line 3033 of file rdp_plugin.c.

+

Definition at line 3035 of file rdp_plugin.c.

@@ -344,7 +344,7 @@ Variables
-

Definition at line 3053 of file rdp_plugin.c.

+

Definition at line 3055 of file rdp_plugin.c.

@@ -432,7 +432,7 @@ Variables
-

Definition at line 2571 of file rdp_plugin.c.

+

Definition at line 2573 of file rdp_plugin.c.

@@ -460,7 +460,7 @@ Variables
-

Definition at line 2523 of file rdp_plugin.c.

+

Definition at line 2525 of file rdp_plugin.c.

@@ -619,7 +619,7 @@ Variables
Todo:
we should lock FreeRDP subthread to update rfi->primary_buffer, rfi->gdi and w/h, from here to memcpy, but… how ?
-

Definition at line 2637 of file rdp_plugin.c.

+

Definition at line 2639 of file rdp_plugin.c.

@@ -741,7 +741,7 @@ Variables
-

Definition at line 2627 of file rdp_plugin.c.

+

Definition at line 2629 of file rdp_plugin.c.

@@ -905,7 +905,7 @@ Variables
-

Definition at line 2475 of file rdp_plugin.c.

+

Definition at line 2477 of file rdp_plugin.c.

@@ -1028,7 +1028,7 @@ Variables
-

Definition at line 2565 of file rdp_plugin.c.

+

Definition at line 2567 of file rdp_plugin.c.

@@ -1723,7 +1723,7 @@ Variables
Initial value:
=
N_("Options for redirection of audio output:\n"
" • [sys:<sys>,][dev:<dev>,][format:<format>,][rate:<rate>,]\n"
" [channel:<channel>] Audio output\n"
" • sys:pulse\n"
" • format:1\n"
" • sys:oss,dev:1,format:1\n"
" • sys:alsa")
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2803 of file rdp_plugin.c.

+

Definition at line 2805 of file rdp_plugin.c.

@@ -1748,7 +1748,7 @@ Variables
Initial value:
=
N_("2600 (Windows XP), 7601 (Windows Vista/7), 9600 (Windows 8 and newer)")
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2783 of file rdp_plugin.c.

+

Definition at line 2785 of file rdp_plugin.c.

@@ -1773,7 +1773,7 @@ Variables
Initial value:
=
N_("Used i.a. by terminal services in a smart card channel to distinguish client capabilities:\n"
" • < 4034: Windows XP base smart card functions\n"
" • 4034-7064: Windows Vista/7: SCardReadCache(),\n"
" SCardWriteCache(), SCardGetTransmitCount()\n"
" • >= 7065: Windows 8 and newer: SCardGetReaderIcon(),\n"
" SCardGetDeviceTypeId()")
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2786 of file rdp_plugin.c.

+

Definition at line 2788 of file rdp_plugin.c.

@@ -1798,7 +1798,7 @@ Variables
Initial value:
=
{
"99", N_("Automatic (32 bpp) (Server chooses its best format)"),
"66", N_("GFX AVC444 (32 bpp)"),
"65", N_("GFX AVC420 (32 bpp)"),
"64", N_("GFX RFX (32 bpp)"),
"63", N_("GFX RFX Progressive (32 bpp)"),
"0", N_("RemoteFX (32 bpp)"),
"32", N_("True colour (32 bpp)"),
"24", N_("True colour (24 bpp)"),
"16", N_("High colour (16 bpp)"),
"15", N_("High colour (15 bpp)"),
"8", N_("256 colours (8 bpp)"),
NULL
}
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2677 of file rdp_plugin.c.

+

Definition at line 2679 of file rdp_plugin.c.

@@ -1823,7 +1823,7 @@ Variables
Initial value:
=
N_("Redirect directory <path> as named share <name>.\n"
" • <name>,<fullpath>[;<name>,<fullpath>[;…]]\n"
" • MyHome,/home/remminer\n"
" • /home/remminer\n"
" • MyHome,/home/remminer;SomePath,/path/to/somepath\n"
"Hotplug support is enabled with:\n"
" • hotplug,*\n"
"\n")
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2841 of file rdp_plugin.c.

+

Definition at line 2843 of file rdp_plugin.c.

@@ -1871,7 +1871,7 @@ Variables
Initial value:
=
{
"http", "HTTP",
"rpc", "RPC",
"auto", "Auto",
NULL
}
-

Definition at line 2763 of file rdp_plugin.c.

+

Definition at line 2765 of file rdp_plugin.c.

@@ -1919,7 +1919,7 @@ Variables
Initial value:
=
{
"INFO", "INFO",
"FATAL", "FATAL",
"ERROR", "ERROR",
"WARN", "WARN",
"DEBUG", "DEBUG",
"TRACE", "TRACE",
"OFF", "OFF",
NULL
}
-

Definition at line 2695 of file rdp_plugin.c.

+

Definition at line 2697 of file rdp_plugin.c.

@@ -1944,7 +1944,7 @@ Variables
Initial value:
=
N_("Options for redirection of audio input:\n"
" • [sys:<sys>,][dev:<dev>,][format:<format>,][rate:<rate>,]\n"
" [channel:<channel>] Audio input (microphone)\n"
" • sys:pulse\n"
" • format:1\n"
" • sys:oss,dev:1,format:1\n"
" • sys:alsa")
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2794 of file rdp_plugin.c.

+

Definition at line 2796 of file rdp_plugin.c.

@@ -1969,7 +1969,7 @@ Variables
Initial value:
=
N_("Comma-separated list of monitor IDs and desktop orientations:\n"
" • [<id>:<orientation-in-degrees>,]\n"
" • 0,1,2,3\n"
" • 0:270,1:90\n"
"Orientations are specified in degrees, valid values are:\n"
" • 0 (landscape)\n"
" • 90 (portrait)\n"
" • 180 (landscape flipped)\n"
" • 270 (portrait flipped)\n"
"\n")
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2829 of file rdp_plugin.c.

+

Definition at line 2831 of file rdp_plugin.c.

@@ -1994,7 +1994,7 @@ Variables
Initial value:
=
{
"No", N_("No"),
"60", N_("Every 1 min"),
"180", N_("Every 3 min"),
"300", N_("Every 5 min"),
"600", N_("Every 10 min"),
NULL
}
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2753 of file rdp_plugin.c.

+

Definition at line 2755 of file rdp_plugin.c.

@@ -2019,7 +2019,7 @@ Variables
Initial value:
=
{
"none", N_("None"),
"autodetect", N_("Auto-detect"),
"modem", N_("Modem"),
"broadband-low", N_("Low performance broadband"),
"satellite", N_("Satellite"),
"broadband-high", N_("High performance broadband"),
"wan", N_("WAN"),
"lan", N_("LAN"),
NULL
}
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2719 of file rdp_plugin.c.

+

Definition at line 2721 of file rdp_plugin.c.

@@ -2044,7 +2044,7 @@ Variables
Initial value:
=
N_("Performance optimisations based on the network connection type:\n"
"Using auto-detection is advised.\n"
"If “Auto-detect” fails, choose the most appropriate option in the list.\n")
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2824 of file rdp_plugin.c.

+

Definition at line 2826 of file rdp_plugin.c.

@@ -2069,7 +2069,7 @@ Variables
Initial value:
=
{
"0", N_("Poor (fastest)"),
"1", N_("Medium"),
"2", N_("Good"),
"9", N_("Best (slowest)"),
NULL
}
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2709 of file rdp_plugin.c.

+

Definition at line 2711 of file rdp_plugin.c.

@@ -2093,7 +2093,7 @@ Variables
-

Definition at line 2979 of file rdp_plugin.c.

+

Definition at line 2981 of file rdp_plugin.c.

@@ -2132,24 +2132,24 @@ Variables
-Initial value:
=
{
"RDP",
N_("RDP - Remote Desktop Protocol"),
GETTEXT_PACKAGE,
"org.remmina.Remmina-rdp-symbolic",
"org.remmina.Remmina-rdp-ssh-symbolic",
}
static gboolean remmina_rdp_open_connection(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:2475
+Initial value:
=
{
"RDP",
N_("RDP - Remote Desktop Protocol"),
GETTEXT_PACKAGE,
"org.remmina.Remmina-rdp-symbolic",
"org.remmina.Remmina-rdp-ssh-symbolic",
}
static gboolean remmina_rdp_open_connection(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:2477
gboolean remmina_rdp_event_on_unmap(RemminaProtocolWidget *gp)
Definition: rdp_event.c:74
-
static gboolean remmina_rdp_query_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Definition: rdp_plugin.c:2565
+
static gboolean remmina_rdp_query_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Definition: rdp_plugin.c:2567
-
static const RemminaProtocolSetting remmina_rdp_advanced_settings[]
Definition: rdp_plugin.c:2898
+
static const RemminaProtocolSetting remmina_rdp_advanced_settings[]
Definition: rdp_plugin.c:2900
static void remmina_rdp_init(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:2439
-
static const RemminaProtocolFeature remmina_rdp_features[]
Definition: rdp_plugin.c:2965
-
static void remmina_rdp_keystroke(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
Definition: rdp_plugin.c:2627
-
static gboolean remmina_rdp_close_connection(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:2523
-
static char remmina_plugin_rdp_version[256]
Definition: rdp_plugin.c:2979
-
static const RemminaProtocolSetting remmina_rdp_basic_settings[]
Definition: rdp_plugin.c:2868
-
static gboolean remmina_rdp_get_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
Definition: rdp_plugin.c:2637
+
static const RemminaProtocolFeature remmina_rdp_features[]
Definition: rdp_plugin.c:2967
+
static void remmina_rdp_keystroke(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
Definition: rdp_plugin.c:2629
+
static gboolean remmina_rdp_close_connection(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:2525
+
static char remmina_plugin_rdp_version[256]
Definition: rdp_plugin.c:2981
+
static const RemminaProtocolSetting remmina_rdp_basic_settings[]
Definition: rdp_plugin.c:2870
+
static gboolean remmina_rdp_get_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
Definition: rdp_plugin.c:2639
gboolean remmina_rdp_event_on_map(RemminaProtocolWidget *gp)
Definition: rdp_event.c:52
-
static void remmina_rdp_call_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Definition: rdp_plugin.c:2571
+
static void remmina_rdp_call_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Definition: rdp_plugin.c:2573
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2982 of file rdp_plugin.c.

+

Definition at line 2984 of file rdp_plugin.c.

@@ -2173,7 +2173,7 @@ Variables
-

Definition at line 2898 of file rdp_plugin.c.

+

Definition at line 2900 of file rdp_plugin.c.

@@ -2197,21 +2197,21 @@ Variables
Initial value:
=
{
{ REMMINA_PROTOCOL_SETTING_TYPE_SERVER, "server", NULL, FALSE, NULL, NULL, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "username", N_("Username"), FALSE, NULL, NULL, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD, "password", N_("Password"), FALSE, NULL, NULL, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "domain", N_("Domain"), FALSE, NULL, NULL, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "drive", N_("Share folder"), FALSE, NULL, drive_tooltip, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "restricted-admin", N_("Restricted admin mode"), FALSE, NULL, NULL, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "pth", N_("Password hash"), FALSE, NULL, N_("Restricted admin mode password hash"), NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "left-handed", N_("Left-handed mouse support"), TRUE, NULL, N_("Swap left and right mouse buttons for left-handed mouse support"), NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disable-smooth-scrolling", N_("Disable smooth scrolling"), TRUE, NULL, NULL, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "multimon", N_("Enable multi monitor"), TRUE, NULL, NULL, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "span", N_("Span screen over multiple monitors"), TRUE, NULL, NULL, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "monitorids", N_("List monitor IDs"), FALSE, NULL, monitorids_tooltip, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_RESOLUTION, "resolution", NULL, FALSE, NULL, NULL, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "colordepth", N_("Colour depth"), FALSE, colordepth_list, NULL, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "network", N_("Network connection type"), FALSE, network_list, network_tooltip, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_KEYMAP, "keymap", NULL, FALSE, NULL, NULL, NULL, NULL },
{ REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL, NULL, NULL }
}
-
static gchar network_tooltip[]
Definition: rdp_plugin.c:2824
+
static gchar network_tooltip[]
Definition: rdp_plugin.c:2826
-
static gpointer network_list[]
Definition: rdp_plugin.c:2719
+
static gpointer network_list[]
Definition: rdp_plugin.c:2721
-
static gpointer colordepth_list[]
Definition: rdp_plugin.c:2677
-
static gchar monitorids_tooltip[]
Definition: rdp_plugin.c:2829
+
static gpointer colordepth_list[]
Definition: rdp_plugin.c:2679
+
static gchar monitorids_tooltip[]
Definition: rdp_plugin.c:2831
-
static gchar drive_tooltip[]
Definition: rdp_plugin.c:2841
+
static gchar drive_tooltip[]
Definition: rdp_plugin.c:2843
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2868 of file rdp_plugin.c.

+

Definition at line 2870 of file rdp_plugin.c.

@@ -2243,7 +2243,7 @@ Variables
Definition: types.h:50
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2965 of file rdp_plugin.c.

+

Definition at line 2967 of file rdp_plugin.c.

@@ -2270,11 +2270,11 @@ Variables
Definition: plugin.h:49
gboolean remmina_rdp_file_import_test(RemminaFilePlugin *plugin, const gchar *from_file)
Definition: rdp_file.c:41
gboolean remmina_rdp_file_export(RemminaFilePlugin *plugin, RemminaFile *remminafile, const gchar *to_file)
Definition: rdp_file.c:282
-
static char remmina_plugin_rdp_version[256]
Definition: rdp_plugin.c:2979
+
static char remmina_plugin_rdp_version[256]
Definition: rdp_plugin.c:2981
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
RemminaFile * remmina_rdp_file_import(RemminaFilePlugin *plugin, const gchar *from_file)
Definition: rdp_file.c:185
-

Definition at line 3007 of file rdp_plugin.c.

+

Definition at line 3009 of file rdp_plugin.c.

@@ -2299,10 +2299,10 @@ Variables
Initial value:
=
{
"RDPS",
N_("RDP - Preferences"),
GETTEXT_PACKAGE,
"RDP",
}
GtkWidget * remmina_rdp_settings_new(RemminaPrefPlugin *plugin)
Definition: rdp_settings.c:696
-
static char remmina_plugin_rdp_version[256]
Definition: rdp_plugin.c:2979
+
static char remmina_plugin_rdp_version[256]
Definition: rdp_plugin.c:2981
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 3022 of file rdp_plugin.c.

+

Definition at line 3024 of file rdp_plugin.c.

@@ -2327,7 +2327,7 @@ Variables
Initial value:
=
{
"", N_("Automatic negotiation"),
"nla", N_("NLA protocol security"),
"tls", N_("TLS protocol security"),
"rdp", N_("RDP protocol security"),
"ext", N_("NLA extended protocol security"),
NULL
}
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2742 of file rdp_plugin.c.

+

Definition at line 2744 of file rdp_plugin.c.

@@ -2352,7 +2352,7 @@ Variables
Initial value:
=
{
"off", N_("Off"),
"local", N_("Local"),
"remote", N_("Remote"),
NULL
}
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2733 of file rdp_plugin.c.

+

Definition at line 2735 of file rdp_plugin.c.

@@ -2377,7 +2377,7 @@ Variables
Initial value:
=
N_("Advanced setting for high latency links:\n"
"Adjusts the connection timeout. Use if your connection times out.\n"
"The highest possible value is 600000 ms (10 minutes).\n")
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2819 of file rdp_plugin.c.

+

Definition at line 2821 of file rdp_plugin.c.

@@ -2402,7 +2402,7 @@ Variables
Initial value:
=
{
"", N_("Default"),
"0", N_("0 — Windows 7 compatible"),
"1", N_("1"),
"2", N_("2"),
"3", N_("3"),
"4", N_("4"),
"5", N_("5"),
NULL
}
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2771 of file rdp_plugin.c.

+

Definition at line 2773 of file rdp_plugin.c.

@@ -2427,7 +2427,7 @@ Variables
Initial value:
=
N_("Options for redirection of USB device:\n"
" • [dbg,][id:<vid>:<pid>#…,][addr:<bus>:<addr>#…,][auto]\n"
" • auto\n"
" • id:054c:0268#4669:6e6b,addr:04:0c")
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
-

Definition at line 2813 of file rdp_plugin.c.

+

Definition at line 2815 of file rdp_plugin.c.

diff --git a/public/rdp__plugin_8c_source.html b/public/rdp__plugin_8c_source.html index d19bc9652..8d3ac1e95 100644 --- a/public/rdp__plugin_8c_source.html +++ b/public/rdp__plugin_8c_source.html @@ -86,22 +86,22 @@ $(document).ready(function(){initNavTree('rdp__plugin_8c_source.html','');});
rdp_plugin.c
-Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2010-2011 Vic Lee
4  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
5  * Copyright (C) 2016-2022 Antenore Gatta, Giovanni Panozzo
6  * Copyright (C) 2022-2023 Antenore Gatta, Giovanni Panozzo, Hiroyuki Tanaka
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  * In addition, as a special exception, the copyright holders give
24  * permission to link the code of portions of this program with the
25  * OpenSSL library under certain conditions as described in each
26  * individual source file, and distribute linked combinations
27  * including the two.
28  * You must obey the GNU General Public License in all respects
29  * for all of the code used other than OpenSSL. * If you modify
30  * file(s) with this exception, you may extend this exception to your
31  * version of the file(s), but you are not obligated to do so. * If you
32  * do not wish to do so, delete this exception statement from your
33  * version. * If you delete this exception statement from all source
34  * files in the program, then also delete it here.
35  *
36  */
37 
38 
39 #define _GNU_SOURCE
40 
41 #include "remmina/plugin.h"
42 #include "rdp_plugin.h"
43 #include "rdp_event.h"
44 #include "rdp_graphics.h"
45 #include "rdp_file.h"
46 #include "rdp_settings.h"
47 #include "rdp_cliprdr.h"
48 #include "rdp_monitor.h"
49 #include "rdp_channels.h"
50 
51 #include <errno.h>
52 #include <pthread.h>
53 #include <time.h>
54 #include <sys/time.h>
55 #ifdef GDK_WINDOWING_X11
56 #include <cairo/cairo-xlib.h>
57 #else
58 #include <cairo/cairo.h>
59 #endif
60 #include <freerdp/addin.h>
61 #include <freerdp/assistance.h>
62 #include <freerdp/settings.h>
63 #include <freerdp/freerdp.h>
64 #include <freerdp/constants.h>
65 #include <freerdp/client/cliprdr.h>
66 #include <freerdp/client/channels.h>
67 #include <freerdp/client/cmdline.h>
68 #include <freerdp/error.h>
69 #include <freerdp/event.h>
70 #include <winpr/memory.h>
71 #include <winpr/cmdline.h>
72 #include <ctype.h>
73 
74 #ifdef HAVE_CUPS
75 #include <cups/cups.h>
76 #endif
77 
78 #include <unistd.h>
79 #include <string.h>
80 
81 #ifdef GDK_WINDOWING_X11
82 #include <X11/Xlib.h>
83 #include <X11/XKBlib.h>
84 #include <gdk/gdkx.h>
85 #elif defined(GDK_WINDOWING_WAYLAND)
86 #include <gdk/gdkwayland.h>
87 #endif
88 
89 #if defined(__FreeBSD__)
90 #include <pthread_np.h>
91 #endif
92 
93 #include <freerdp/locale/keyboard.h>
94 
95 #define REMMINA_RDP_FEATURE_TOOL_REFRESH 1
96 #define REMMINA_RDP_FEATURE_SCALE 2
97 #define REMMINA_RDP_FEATURE_UNFOCUS 3
98 #define REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL 4
99 #define REMMINA_RDP_FEATURE_DYNRESUPDATE 5
100 #define REMMINA_RDP_FEATURE_MULTIMON 6
101 #define REMMINA_RDP_FEATURE_VIEWONLY 7
102 
103 #define REMMINA_CONNECTION_TYPE_NONE 0
104 
105 #ifdef WITH_FREERDP3
106  #define CLPARAM const char
107 #else
108  #define CLPARAM char
109 #endif
110 
111 
113 
114 static BOOL gfx_h264_available = FALSE;
115 // keep track of last interaction time for keep alive
116 static time_t last_time;
117 
118 /* Compatibility: these functions have been introduced with https://github.com/FreeRDP/FreeRDP/commit/8c5d96784d
119  * and are missing on older FreeRDP, so we add them here.
120  * They should be removed from here after all distributed versions of FreeRDP (libwinpr) will have
121  * CommandLineParseCommaSeparatedValuesEx() onboard.
122  *
123  * (C) Copyright goes to the FreeRDP authors.
124  */
125 static CLPARAM **remmina_rdp_CommandLineParseCommaSeparatedValuesEx(const char *name, const char *list, size_t *count)
126 {
127  TRACE_CALL(__func__);
128 #if FREERDP_CHECK_VERSION(2, 0, 0)
129  return (CLPARAM **)CommandLineParseCommaSeparatedValuesEx(name, list, count);
130 #else
131  char **p;
132  char *str;
133  size_t nArgs;
134  size_t index;
135  size_t nCommas;
136  size_t prefix, len;
137 
138  nCommas = 0;
139 
140  if (count == NULL)
141  return NULL;
142 
143  *count = 0;
144 
145  if (!list) {
146  if (name) {
147  size_t len = strlen(name);
148  p = (char **)calloc(2UL + len, sizeof(char *));
149 
150  if (p) {
151  char *dst = (char *)&p[1];
152  p[0] = dst;
153  sprintf_s(dst, len + 1, "%s", name);
154  *count = 1;
155  return p;
156  }
157  }
158 
159  return NULL;
160  }
161 
162  {
163  const char *it = list;
164 
165  while ((it = strchr(it, ',')) != NULL) {
166  it++;
167  nCommas++;
168  }
169  }
170 
171  nArgs = nCommas + 1;
172 
173  if (name)
174  nArgs++;
175 
176  prefix = (nArgs + 1UL) * sizeof(char *);
177  len = strlen(list);
178  p = (char **)calloc(len + prefix + 1, sizeof(char *));
179 
180  if (!p)
181  return NULL;
182 
183  str = &((char *)p)[prefix];
184  memcpy(str, list, len);
185 
186  if (name)
187  p[0] = (char *)name;
188 
189  for (index = name ? 1 : 0; index < nArgs; index++) {
190  char *comma = strchr(str, ',');
191  p[index] = str;
192 
193  if (comma) {
194  str = comma + 1;
195  *comma = '\0';
196  }
197  }
198 
199  *count = nArgs;
200  return p;
201 #endif
202 }
203 
204 static CLPARAM **remmina_rdp_CommandLineParseCommaSeparatedValues(const char *list, size_t *count)
205 {
206  TRACE_CALL(__func__);
207  return remmina_rdp_CommandLineParseCommaSeparatedValuesEx(NULL, list, count);
208 }
209 
210 /*
211  * End of CommandLineParseCommaSeparatedValuesEx() compatibility and copyright
212  */
214 {
215  TRACE_CALL(__func__);
216  UINT16 flags;
217  rdpInput *input;
218  rfContext *rfi = GET_PLUGIN_DATA(gp);
219  RemminaPluginRdpEvent *event;
220  DISPLAY_CONTROL_MONITOR_LAYOUT *dcml;
221  CLIPRDR_FORMAT_DATA_RESPONSE response = { 0 };
222  RemminaFile *remminafile;
223 
224  if (rfi->event_queue == NULL)
225  return true;
226 
227  input = rfi->instance->input;
228 
229  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
230 
231  while ((event = (RemminaPluginRdpEvent *)g_async_queue_try_pop(rfi->event_queue)) != NULL) {
232  time(&last_time); //update last user interaction time
233  switch (event->type) {
235  flags = event->key_event.extended ? KBD_FLAGS_EXTENDED : 0;
236  flags |= event->key_event.up ? KBD_FLAGS_RELEASE : KBD_FLAGS_DOWN;
237  input->KeyboardEvent(input, flags, event->key_event.key_code);
238  break;
239 
241  /*
242  * TS_UNICODE_KEYBOARD_EVENT RDP message, see https://msdn.microsoft.com/en-us/library/cc240585.aspx
243  */
244  flags = event->key_event.up ? KBD_FLAGS_RELEASE : KBD_FLAGS_DOWN;
245  input->UnicodeKeyboardEvent(input, flags, event->key_event.unicode_code);
246  break;
247 
249  if (event->mouse_event.extended)
250  input->ExtendedMouseEvent(input, event->mouse_event.flags,
251  event->mouse_event.x, event->mouse_event.y);
252  else
253  input->MouseEvent(input, event->mouse_event.flags,
254  event->mouse_event.x, event->mouse_event.y);
255  break;
256 
258  rfi->clipboard.context->ClientFormatList(rfi->clipboard.context, event->clipboard_formatlist.pFormatList);
259  free(event->clipboard_formatlist.pFormatList);
260  break;
261 
263  response.msgFlags = (event->clipboard_formatdataresponse.data) ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
264  response.dataLen = event->clipboard_formatdataresponse.size;
265  response.requestedFormatData = event->clipboard_formatdataresponse.data;
266  rfi->clipboard.context->ClientFormatDataResponse(rfi->clipboard.context, &response);
267  break;
268 
270  REMMINA_PLUGIN_DEBUG("Sending client FormatDataRequest to server");
271  gettimeofday(&(rfi->clipboard.clientformatdatarequest_tv), NULL);
272  rfi->clipboard.context->ClientFormatDataRequest(rfi->clipboard.context, event->clipboard_formatdatarequest.pFormatDataRequest);
273  free(event->clipboard_formatdatarequest.pFormatDataRequest);
274  break;
275 
277  if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) {
278  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseMultimon, TRUE);
279  /* TODO Add an option for this */
280  freerdp_settings_set_bool(rfi->settings, FreeRDP_ForceMultimon, TRUE);
281  freerdp_settings_set_bool(rfi->settings, FreeRDP_Fullscreen, TRUE);
282  /* got some crashes with g_malloc0, to be investigated */
283  dcml = calloc(freerdp_settings_get_uint32(rfi->settings, FreeRDP_MonitorCount), sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
284  REMMINA_PLUGIN_DEBUG("REMMINA_RDP_EVENT_TYPE_SEND_MONITOR_LAYOUT:");
285  if (!dcml)
286  break;
287 
288  const rdpMonitor *base = freerdp_settings_get_pointer(rfi->settings, FreeRDP_MonitorDefArray);
289  for (gint i = 0; i < freerdp_settings_get_uint32(rfi->settings, FreeRDP_MonitorCount); ++i) {
290  const rdpMonitor *current = &base[i];
291  REMMINA_PLUGIN_DEBUG("Sending display layout for monitor n° %d", i);
292  dcml[i].Flags = (current->is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0);
293  REMMINA_PLUGIN_DEBUG("Monitor %d is primary: %d", i, dcml[i].Flags);
294  dcml[i].Left = current->x;
295  REMMINA_PLUGIN_DEBUG("Monitor %d x: %d", i, dcml[i].Left);
296  dcml[i].Top = current->y;
297  REMMINA_PLUGIN_DEBUG("Monitor %d y: %d", i, dcml[i].Top);
298  dcml[i].Width = current->width;
299  REMMINA_PLUGIN_DEBUG("Monitor %d width: %d", i, dcml[i].Width);
300  dcml[i].Height = current->height;
301  REMMINA_PLUGIN_DEBUG("Monitor %d height: %d", i, dcml[i].Height);
302  dcml[i].PhysicalWidth = current->attributes.physicalWidth;
303  REMMINA_PLUGIN_DEBUG("Monitor %d physical width: %d", i, dcml[i].PhysicalWidth);
304  dcml[i].PhysicalHeight = current->attributes.physicalHeight;
305  REMMINA_PLUGIN_DEBUG("Monitor %d physical height: %d", i, dcml[i].PhysicalHeight);
306  if (current->attributes.orientation)
307  dcml[i].Orientation = current->attributes.orientation;
308  else
309  dcml[i].Orientation = event->monitor_layout.desktopOrientation;
310  REMMINA_PLUGIN_DEBUG("Monitor %d orientation: %d", i, dcml[i].Orientation);
311  dcml[i].DesktopScaleFactor = event->monitor_layout.desktopScaleFactor;
312  dcml[i].DeviceScaleFactor = event->monitor_layout.deviceScaleFactor;
313  }
314  rfi->dispcontext->SendMonitorLayout(rfi->dispcontext, freerdp_settings_get_uint32(rfi->settings, FreeRDP_MonitorCount), dcml);
315  g_free(dcml);
316  } else {
317  dcml = g_malloc0(sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
318  if (dcml) {
319  dcml->Flags = DISPLAY_CONTROL_MONITOR_PRIMARY;
320  dcml->Width = event->monitor_layout.width;
321  dcml->Height = event->monitor_layout.height;
322  dcml->Orientation = event->monitor_layout.desktopOrientation;
323  dcml->DesktopScaleFactor = event->monitor_layout.desktopScaleFactor;
324  dcml->DeviceScaleFactor = event->monitor_layout.deviceScaleFactor;
325  rfi->dispcontext->SendMonitorLayout(rfi->dispcontext, 1, dcml);
326  g_free(dcml); \
327  }
328  }
329  break;
331  /* Disconnect requested via GUI (i.e: tab destroy/close) */
332  freerdp_abort_connect(rfi->instance);
333  break;
334  }
335 
336  g_free(event);
337  }
338 
339  return true;
340 }
341 
343 {
344  TRACE_CALL(__func__);
345 
346  /* Opens the optional SSH tunnel if needed.
347  * Used also when reopening the same tunnel for a FreeRDP reconnect.
348  * Returns TRUE if all OK, and setups correct rfi->Settings values
349  * with connection and certificate parameters */
350 
351  gchar *hostport;
352  gchar *s;
353  gchar *host;
354  gchar *cert_host;
355  gint cert_port;
356  gint port;
357 
358  rfContext *rfi = GET_PLUGIN_DATA(gp);
359 
360  REMMINA_PLUGIN_DEBUG("Tunnel init");
361  hostport = remmina_plugin_service->protocol_plugin_start_direct_tunnel(gp, 3389, FALSE);
362  if (hostport == NULL)
363  return FALSE;
364 
365  remmina_plugin_service->get_server_port(hostport, 3389, &host, &port);
366 
367  if (host[0] == 0)
368  return FALSE;
369 
370  REMMINA_PLUGIN_DEBUG("protocol_plugin_start_direct_tunnel() returned %s", hostport);
371 
372  cert_host = host;
373  cert_port = port;
374 
375  if (!rfi->is_reconnecting) {
376  /* settings->CertificateName and settings->ServerHostname is created
377  * only on 1st connect, not on reconnections */
378 
379  freerdp_settings_set_string(rfi->settings, FreeRDP_ServerHostname, host);
380 
381  if (cert_port == 3389) {
382  freerdp_settings_set_string(rfi->settings, FreeRDP_CertificateName, cert_host);
383  } else {
384  s = g_strdup_printf("%s:%d", cert_host, cert_port);
385  freerdp_settings_set_string(rfi->settings, FreeRDP_CertificateName, s);
386  g_free(s);
387  }
388  }
389 
390  REMMINA_PLUGIN_DEBUG("Tunnel has been optionally initialized. Now connecting to %s:%d", host, port);
391 
392  if (cert_host != host) g_free(cert_host);
393  g_free(host);
394  g_free(hostport);
395 
396  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ServerPort, port);
397 
398  return TRUE;
399 }
400 
401 static BOOL rf_auto_reconnect(rfContext *rfi)
402 {
403  TRACE_CALL(__func__);
404  rdpSettings *settings = rfi->instance->settings;
406  time_t treconn;
407  gchar *cval;
408  gint maxattempts;
409 
411  RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
412 
413  rfi->is_reconnecting = TRUE;
414  rfi->stop_reconnecting_requested = FALSE;
415 
416  /* Get the value set in FreeRDP_AutoReconnectMaxRetries (20) */
417  maxattempts = freerdp_settings_get_uint32(settings, FreeRDP_AutoReconnectMaxRetries);
418  REMMINA_PLUGIN_DEBUG("maxattempts from default: %d", maxattempts);
419  /* Get the value from the global preferences if any */
420  if ((cval = remmina_plugin_service->pref_get_value("rdp_reconnect_attempts")) != NULL)
421  maxattempts = atoi(cval);
422  REMMINA_PLUGIN_DEBUG("maxattempts from general preferences: %d", maxattempts);
423  /* Get the value from the profile if any, otherwise uses the value of maxattempts */
424  maxattempts = remmina_plugin_service->file_get_int(remminafile, "rdp_reconnect_attempts", maxattempts);
425  REMMINA_PLUGIN_DEBUG("maxattempts from general plugin: %d", maxattempts);
426  /* If maxattemps is <= 0, we get the value from FreeRDP_AutoReconnectMaxRetries (20) */
427  if (maxattempts <= 0)
428  maxattempts = freerdp_settings_get_uint32(settings, FreeRDP_AutoReconnectMaxRetries);
429  freerdp_settings_set_uint32(settings, FreeRDP_AutoReconnectMaxRetries, maxattempts);
430  REMMINA_PLUGIN_DEBUG("maxattempts set to: %d", maxattempts);
431 
432  rfi->reconnect_maxattempts = maxattempts;
433  rfi->reconnect_nattempt = 0;
434 
435  /* Only auto reconnect on network disconnects. */
436  switch (freerdp_error_info(rfi->instance)) {
437  case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
438  /* Disconnected by server hitting a bug or resource limit */
439  break;
440  case ERRINFO_SUCCESS:
441  /* A network disconnect was detected */
442  break;
443  default:
444  rfi->is_reconnecting = FALSE;
445  return FALSE;
446  }
447 
448  if (!freerdp_settings_get_bool(settings, FreeRDP_AutoReconnectionEnabled)) {
449  /* No auto-reconnect - just quit */
450  rfi->is_reconnecting = FALSE;
451  return FALSE;
452  }
453 
454  /* A network disconnect was detected and we should try to reconnect */
455  REMMINA_PLUGIN_DEBUG("[%s] network disconnection detected, initiating reconnection attempt",
456  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
457 
458  ui = g_new0(RemminaPluginRdpUiObject, 1);
461 
462  /* Sleep half a second to allow:
463  * - processing of the UI event we just pushed on the queue
464  * - better network conditions
465  * Remember: We hare on a thread, so the main gui won’t lock */
466  usleep(500000);
467 
468  /* Perform an auto-reconnect. */
469  while (TRUE) {
470  /* Quit retrying if max retries has been exceeded */
471  if (rfi->reconnect_nattempt++ >= rfi->reconnect_maxattempts) {
472  REMMINA_PLUGIN_DEBUG("[%s] maximum number of reconnection attempts exceeded.",
473  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
474  break;
475  }
476 
477  if (rfi->stop_reconnecting_requested) {
478  REMMINA_PLUGIN_DEBUG("[%s] reconnect request loop interrupted by user.",
479  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
480  break;
481  }
482 
483  /* Attempt the next reconnect */
484  REMMINA_PLUGIN_DEBUG("[%s] reconnection, attempt #%d of %d",
485  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname), rfi->reconnect_nattempt, rfi->reconnect_maxattempts);
486 
487  ui = g_new0(RemminaPluginRdpUiObject, 1);
490 
491  treconn = time(NULL);
492 
493  /* Reconnect the SSH tunnel, if needed */
495  REMMINA_PLUGIN_DEBUG("[%s] unable to recreate tunnel with remmina_rdp_tunnel_init.",
496  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
497  } else {
498  if (freerdp_reconnect(rfi->instance)) {
499  /* Reconnection is successful */
500  REMMINA_PLUGIN_DEBUG("[%s] reconnected.", freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
501  rfi->is_reconnecting = FALSE;
502  return TRUE;
503  }
504  }
505 
506  /* Wait until 5 secs have elapsed from last reconnect attempt, while checking for rfi->stop_reconnecting_requested */
507  while (time(NULL) - treconn < 5) {
509  break;
510  usleep(200000); // 200ms sleep
511  }
512  }
513 
514  rfi->is_reconnecting = FALSE;
515  return FALSE;
516 }
517 
518 static BOOL rf_begin_paint(rdpContext *context)
519 {
520  TRACE_CALL(__func__);
521  rdpGdi *gdi;
522 
523  if (!context)
524  return FALSE;
525 
526  gdi = context->gdi;
527  if (!gdi || !gdi->primary || !gdi->primary->hdc || !gdi->primary->hdc->hwnd)
528  return FALSE;
529 
530  return TRUE;
531 }
532 
533 static BOOL rf_end_paint(rdpContext *context)
534 {
535  TRACE_CALL(__func__);
536  rdpGdi *gdi;
537  rfContext *rfi;
539  int i, ninvalid;
540  region *reg;
541  HGDI_RGN cinvalid;
542 
543  gdi = context->gdi;
544  rfi = (rfContext *)context;
545 
546  if (gdi == NULL || gdi->primary == NULL || gdi->primary->hdc == NULL || gdi->primary->hdc->hwnd == NULL)
547  return TRUE;
548 
549  if (gdi->primary->hdc->hwnd->invalid->null)
550  return TRUE;
551 
552  if (gdi->primary->hdc->hwnd->ninvalid < 1)
553  return TRUE;
554 
555  ninvalid = gdi->primary->hdc->hwnd->ninvalid;
556  cinvalid = gdi->primary->hdc->hwnd->cinvalid;
557  reg = (region *)g_malloc(sizeof(region) * ninvalid);
558  for (i = 0; i < ninvalid; i++) {
559  reg[i].x = cinvalid[i].x;
560  reg[i].y = cinvalid[i].y;
561  reg[i].w = cinvalid[i].w;
562  reg[i].h = cinvalid[i].h;
563  }
564 
565  ui = g_new0(RemminaPluginRdpUiObject, 1);
567  ui->reg.ninvalid = ninvalid;
568  ui->reg.ureg = reg;
569 
571 
572 
573  gdi->primary->hdc->hwnd->invalid->null = TRUE;
574  gdi->primary->hdc->hwnd->ninvalid = 0;
575 
576 
577  return TRUE;
578 }
579 
580 static BOOL rf_desktop_resize(rdpContext *context)
581 {
582  TRACE_CALL(__func__);
583  rfContext *rfi;
586  UINT32 w, h;
587 
588  rfi = (rfContext *)context;
589  gp = rfi->protocol_widget;
590 
591  w = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth);
592  h = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight);
593  remmina_plugin_service->protocol_plugin_set_width(gp, w);
594  remmina_plugin_service->protocol_plugin_set_height(gp, h);
595 
596  ui = g_new0(RemminaPluginRdpUiObject, 1);
600 
601  /* Tell libfreerdp to change its internal GDI bitmap width and heigt,
602  * this will also destroy gdi->primary_buffer, making our rfi->surface invalid */
603  gdi_resize(((rdpContext *)rfi)->gdi, w, h);
604 
605  /* Call to remmina_rdp_event_update_scale(gp) on the main UI thread,
606  * this will recreate rfi->surface from gdi->primary_buffer */
607 
608  ui = g_new0(RemminaPluginRdpUiObject, 1);
612 
613  remmina_plugin_service->protocol_plugin_desktop_resize(gp);
614 
615  return TRUE;
616 }
617 
618 static BOOL rf_play_sound(rdpContext *context, const PLAY_SOUND_UPDATE *play_sound)
619 {
620  TRACE_CALL(__func__);
621  rfContext *rfi;
623  GdkDisplay *disp;
624 
625  rfi = (rfContext *)context;
626  gp = rfi->protocol_widget;
627 
628  disp = gtk_widget_get_display(GTK_WIDGET(gp));
629  gdk_display_beep(disp);
630 
631  return TRUE;
632 }
633 
634 static BOOL rf_keyboard_set_indicators(rdpContext *context, UINT16 led_flags)
635 {
636  TRACE_CALL(__func__);
637  rfContext *rfi;
639  GdkDisplay *disp;
640 
641  rfi = (rfContext *)context;
642  gp = rfi->protocol_widget;
643  disp = gtk_widget_get_display(GTK_WIDGET(gp));
644 
645 #ifdef GDK_WINDOWING_X11
646  if (GDK_IS_X11_DISPLAY(disp)) {
647  /* TODO: We are not on the main thread. Will X.Org complain? */
648  Display *x11_display;
649  x11_display = gdk_x11_display_get_xdisplay(disp);
650  XkbLockModifiers(x11_display, XkbUseCoreKbd,
651  LockMask | Mod2Mask,
652  ((led_flags & KBD_SYNC_CAPS_LOCK) ? LockMask : 0) |
653  ((led_flags & KBD_SYNC_NUM_LOCK) ? Mod2Mask : 0)
654  );
655 
656  /* TODO: Add support to KANA_LOCK and SCROLL_LOCK */
657  }
658 #endif
659 
660  return TRUE;
661 }
662 
663 static BOOL rf_keyboard_set_ime_status(rdpContext *context, UINT16 imeId, UINT32 imeState,
664  UINT32 imeConvMode)
665 {
666  TRACE_CALL(__func__);
667  if (!context)
668  return FALSE;
669 
670  /* Unimplemented, we ignore it */
671 
672  return TRUE;
673 }
674 
675 static BOOL remmina_rdp_pre_connect(freerdp *instance)
676 {
677  TRACE_CALL(__func__);
678  rdpChannels *channels;
679  rdpSettings *settings;
680  rdpContext *context = instance->context;
681 
682  settings = instance->settings;
683  channels = context->channels;
684  freerdp_settings_set_uint32(settings, FreeRDP_OsMajorType, OSMAJORTYPE_UNIX);
685  freerdp_settings_set_uint32(settings, FreeRDP_OsMinorType, OSMINORTYPE_UNSPECIFIED);
686  freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled, TRUE);
687  freerdp_settings_set_uint32(settings, FreeRDP_OffscreenSupportLevel, 1);
688 
689  PubSub_SubscribeChannelConnected(instance->context->pubSub,
691  PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
693 
694  if (!freerdp_client_load_addins(channels, settings))
695  return FALSE;
696 
697  return true;
698 }
699 
700 static BOOL remmina_rdp_post_connect(freerdp *instance)
701 {
702  TRACE_CALL(__func__);
703  rfContext *rfi;
706  UINT32 freerdp_local_color_format;
707 
708  rfi = (rfContext *)instance->context;
709  gp = rfi->protocol_widget;
710  rfi->postconnect_error = REMMINA_POSTCONNECT_ERROR_OK;
711 
712  rfi->attempt_interactive_authentication = FALSE; // We authenticated!
713 
714  rfi->srcBpp = freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth);
715 
716  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_RemoteFxCodec) == FALSE)
717  rfi->sw_gdi = TRUE;
718 
719  rf_register_graphics(instance->context->graphics);
720 
721  REMMINA_PLUGIN_DEBUG("bpp: %d", rfi->bpp);
722  switch (rfi->bpp) {
723  case 24:
724  REMMINA_PLUGIN_DEBUG("CAIRO_FORMAT_RGB24");
725  freerdp_local_color_format = PIXEL_FORMAT_BGRX32;
726  rfi->cairo_format = CAIRO_FORMAT_RGB24;
727  break;
728  case 32:
733  REMMINA_PLUGIN_DEBUG("CAIRO_FORMAT_RGB24");
734  freerdp_local_color_format = PIXEL_FORMAT_BGRA32;
735  rfi->cairo_format = CAIRO_FORMAT_RGB24;
736  break;
737  default:
738  REMMINA_PLUGIN_DEBUG("CAIRO_FORMAT_RGB16_565");
739  freerdp_local_color_format = PIXEL_FORMAT_RGB16;
740  rfi->cairo_format = CAIRO_FORMAT_RGB16_565;
741  break;
742  }
743 
744  if (!gdi_init(instance, freerdp_local_color_format)) {
745  rfi->postconnect_error = REMMINA_POSTCONNECT_ERROR_GDI_INIT;
746  return FALSE;
747  }
748 
749  if (instance->context->codecs->h264 == NULL && freerdp_settings_get_bool(rfi->settings, FreeRDP_GfxH264)) {
750  gdi_free(instance);
751  rfi->postconnect_error = REMMINA_POSTCONNECT_ERROR_NO_H264;
752  return FALSE;
753  }
754 
755  // pointer_cache_register_callbacks(instance->update);
756 
757  instance->update->BeginPaint = rf_begin_paint;
758  instance->update->EndPaint = rf_end_paint;
759  instance->update->DesktopResize = rf_desktop_resize;
760 
761  instance->update->PlaySound = rf_play_sound;
762  instance->update->SetKeyboardIndicators = rf_keyboard_set_indicators;
763  instance->update->SetKeyboardImeStatus = rf_keyboard_set_ime_status;
764 
766  rfi->connected = true;
767 
768  ui = g_new0(RemminaPluginRdpUiObject, 1);
771 
772  return TRUE;
773 }
774 
775 static BOOL remmina_rdp_authenticate(freerdp *instance, char **username, char **password, char **domain)
776 {
777  TRACE_CALL(__func__);
778  gchar *s_username, *s_password, *s_domain;
779  gint ret;
780  rfContext *rfi;
782  gboolean save;
783  gboolean disablepasswordstoring;
784  RemminaFile *remminafile;
785 
786  rfi = (rfContext *)instance->context;
787  gp = rfi->protocol_widget;
788  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
789  disablepasswordstoring = remmina_plugin_service->file_get_int(remminafile, "disablepasswordstoring", FALSE);
790 
791  ret = remmina_plugin_service->protocol_plugin_init_auth(gp,
793  _("Enter RDP authentication credentials"),
794  remmina_plugin_service->file_get_string(remminafile, "username"),
795  remmina_plugin_service->file_get_string(remminafile, "password"),
796  remmina_plugin_service->file_get_string(remminafile, "domain"),
797  NULL);
798  if (ret == GTK_RESPONSE_OK) {
799  s_username = remmina_plugin_service->protocol_plugin_init_get_username(gp);
800  if (s_username) freerdp_settings_set_string(rfi->settings, FreeRDP_Username, s_username);
801 
802  s_password = remmina_plugin_service->protocol_plugin_init_get_password(gp);
803  if (s_password) freerdp_settings_set_string(rfi->settings, FreeRDP_Password, s_password);
804 
805  s_domain = remmina_plugin_service->protocol_plugin_init_get_domain(gp);
806  if (s_domain) freerdp_settings_set_string(rfi->settings, FreeRDP_Domain, s_domain);
807 
808  remmina_plugin_service->file_set_string(remminafile, "username", s_username);
809  remmina_plugin_service->file_set_string(remminafile, "domain", s_domain);
810 
811  save = remmina_plugin_service->protocol_plugin_init_get_savepassword(gp);
812  if (save) {
813  // User has requested to save credentials. We put the password
814  // into remminafile->settings. It will be saved later, on successful connection, by
815  // rcw.c
816  remmina_plugin_service->file_set_string(remminafile, "password", s_password);
817  } else {
818  remmina_plugin_service->file_set_string(remminafile, "password", NULL);
819  }
820 
821 
822  if (s_username) g_free(s_username);
823  if (s_password) g_free(s_password);
824  if (s_domain) g_free(s_domain);
825 
826  return TRUE;
827  } else {
828  return FALSE;
829  }
830 
831  return TRUE;
832 }
833 
834 static BOOL remmina_rdp_gw_authenticate(freerdp *instance, char **username, char **password, char **domain)
835 {
836  TRACE_CALL(__func__);
837  gchar *s_username, *s_password, *s_domain;
838  gint ret;
839  rfContext *rfi;
841  gboolean save;
842  gboolean disablepasswordstoring;
843  gboolean basecredforgw;
844  RemminaFile *remminafile;
845 
846  rfi = (rfContext *)instance->context;
847  gp = rfi->protocol_widget;
848  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
849 
850  if (!remmina_plugin_service->file_get_string(remminafile, "gateway_server"))
851  return false;
852  disablepasswordstoring = remmina_plugin_service->file_get_int(remminafile, "disablepasswordstoring", FALSE);
853  basecredforgw = remmina_plugin_service->file_get_int(remminafile, "base-cred-for-gw", FALSE);
854 
855  if (basecredforgw) {
856  ret = remmina_plugin_service->protocol_plugin_init_auth(gp,
858  _("Enter RDP authentication credentials"),
859  remmina_plugin_service->file_get_string(remminafile, "username"),
860  remmina_plugin_service->file_get_string(remminafile, "password"),
861  remmina_plugin_service->file_get_string(remminafile, "domain"),
862  NULL);
863  } else {
864  ret = remmina_plugin_service->protocol_plugin_init_auth(gp,
866  _("Enter RDP gateway authentication credentials"),
867  remmina_plugin_service->file_get_string(remminafile, "gateway_username"),
868  remmina_plugin_service->file_get_string(remminafile, "gateway_password"),
869  remmina_plugin_service->file_get_string(remminafile, "gateway_domain"),
870  NULL);
871  }
872 
873 
874  if (ret == GTK_RESPONSE_OK) {
875  s_username = remmina_plugin_service->protocol_plugin_init_get_username(gp);
876  if (s_username) freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayUsername, s_username);
877 
878  s_password = remmina_plugin_service->protocol_plugin_init_get_password(gp);
879  if (s_password) freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayPassword, s_password);
880 
881  s_domain = remmina_plugin_service->protocol_plugin_init_get_domain(gp);
882  if (s_domain) freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayDomain, s_domain);
883 
884  save = remmina_plugin_service->protocol_plugin_init_get_savepassword(gp);
885 
886  if (basecredforgw) {
887  remmina_plugin_service->file_set_string(remminafile, "username", s_username);
888  remmina_plugin_service->file_set_string(remminafile, "domain", s_domain);
889  if (save)
890  remmina_plugin_service->file_set_string(remminafile, "password", s_password);
891  else
892  remmina_plugin_service->file_set_string(remminafile, "password", NULL);
893  } else {
894  remmina_plugin_service->file_set_string(remminafile, "gateway_username", s_username);
895  remmina_plugin_service->file_set_string(remminafile, "gateway_domain", s_domain);
896  if (save)
897  remmina_plugin_service->file_set_string(remminafile, "gateway_password", s_password);
898  else
899  remmina_plugin_service->file_set_string(remminafile, "gateway_password", NULL);
900  }
901 
902  if (s_username) g_free(s_username);
903  if (s_password) g_free(s_password);
904  if (s_domain) g_free(s_domain);
905 
906  return true;
907  } else {
908  return false;
909  }
910 
911  return true;
912 }
913 
914 static DWORD remmina_rdp_verify_certificate_ex(freerdp *instance, const char *host, UINT16 port,
915  const char *common_name, const char *subject,
916  const char *issuer, const char *fingerprint, DWORD flags)
917 {
918  TRACE_CALL(__func__);
919  gint status;
920  rfContext *rfi;
922 
923  rfi = (rfContext *)instance->context;
924  gp = rfi->protocol_widget;
925 
926  status = remmina_plugin_service->protocol_plugin_init_certificate(gp, subject, issuer, fingerprint);
927 
928  if (status == GTK_RESPONSE_OK)
929  return 1;
930 
931  return 0;
932 }
933 
934 static DWORD
935 remmina_rdp_verify_certificate(freerdp *instance, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, BOOL host_mismatch) __attribute__ ((unused));
936 static DWORD
937 remmina_rdp_verify_certificate(freerdp *instance, const char *common_name, const char *subject,
938  const char *issuer, const char *fingerprint, BOOL host_mismatch)
939 {
940  TRACE_CALL(__func__);
941  gint status;
942  rfContext *rfi;
944 
945  rfi = (rfContext *)instance->context;
946  gp = rfi->protocol_widget;
947 
948  status = remmina_plugin_service->protocol_plugin_init_certificate(gp, subject, issuer, fingerprint);
949 
950  if (status == GTK_RESPONSE_OK)
951  return 1;
952 
953  return 0;
954 }
955 
956 static DWORD remmina_rdp_verify_changed_certificate_ex(freerdp *instance, const char *host, UINT16 port,
957  const char *common_name, const char *subject,
958  const char *issuer, const char *fingerprint,
959  const char *old_subject, const char *old_issuer,
960  const char *old_fingerprint, DWORD flags)
961 {
962  TRACE_CALL(__func__);
963  gint status;
964  rfContext *rfi;
966 
967  rfi = (rfContext *)instance->context;
968  gp = rfi->protocol_widget;
969 
970  status = remmina_plugin_service->protocol_plugin_changed_certificate(gp, subject, issuer, fingerprint, old_fingerprint);
971 
972  if (status == GTK_RESPONSE_OK)
973  return 1;
974 
975  return 0;
976 }
977 
978 static void remmina_rdp_post_disconnect(freerdp *instance)
979 {
980  TRACE_CALL(__func__);
981 
982  if (!instance || !instance->context)
983  return;
984 
985  PubSub_UnsubscribeChannelConnected(instance->context->pubSub,
987  PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub,
989 
990  /* The remaining cleanup will be continued on main thread by complete_cleanup_on_main_thread() */
991 }
992 
994 {
995  TRACE_CALL(__func__);
996  DWORD status;
997  gchar buf[100];
998  rfContext *rfi = GET_PLUGIN_DATA(gp);
999  RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
1000  time_t cur_time, time_diff;
1001 
1002  int jitter_time = remmina_plugin_service->file_get_int(remminafile, "rdp_mouse_jitter", 0);
1003  time(&last_time);
1004  while (!freerdp_shall_disconnect(rfi->instance)) {
1005  //move mouse if we've been idle and option is selected
1006  time(&cur_time);
1007  time_diff = cur_time - last_time;
1008  if (jitter_time > 0 && time_diff > jitter_time){
1009  last_time = cur_time;
1011  }
1012 
1013  HANDLE handles[64]={0};
1014  DWORD nCount = freerdp_get_event_handles(rfi->instance->context, &handles[0], 64);
1015  if (rfi->event_handle)
1016  handles[nCount++] = rfi->event_handle;
1017 
1018  handles[nCount++] = rfi->instance->context->abortEvent;
1019 
1020  if (nCount == 0) {
1021  fprintf(stderr, "freerdp_get_event_handles failed\n");
1022  break;
1023  }
1024 
1025  status = WaitForMultipleObjects(nCount, handles, FALSE, 100);
1026 
1027  if (status == WAIT_FAILED) {
1028  fprintf(stderr, "WaitForMultipleObjects failed with %lu\n", (unsigned long)status);
1029  break;
1030  }
1031 
1032  if (rfi->event_handle && WaitForSingleObject(rfi->event_handle, 0) == WAIT_OBJECT_0) {
1033  if (!rf_process_event_queue(gp)) {
1034  fprintf(stderr, "Could not process local keyboard/mouse event queue\n");
1035  break;
1036  }
1037  if (read(rfi->event_pipe[0], buf, sizeof(buf))) {
1038  }
1039  }
1040 
1041  /* Check if a processed event called freerdp_abort_connect() and exit if true */
1042  if (WaitForSingleObject(rfi->instance->context->abortEvent, 0) == WAIT_OBJECT_0)
1043  /* Session disconnected by local user action */
1044  break;
1045 
1046  if (!freerdp_check_event_handles(rfi->instance->context)) {
1047  if (rf_auto_reconnect(rfi)) {
1048  /* Reset the possible reason/error which made us doing many reconnection reattempts and continue */
1049  remmina_plugin_service->protocol_plugin_set_error(gp, NULL);
1050  continue;
1051  }
1052  if (freerdp_get_last_error(rfi->instance->context) == FREERDP_ERROR_SUCCESS)
1053  fprintf(stderr, "Could not check FreeRDP file descriptor\n");
1054  break;
1055  }
1056  }
1057  const gchar *host = freerdp_settings_get_string (rfi->settings, FreeRDP_ServerHostname);
1058  // TRANSLATORS: the placeholder may be either an IP/FQDN or a server hostname
1059  REMMINA_PLUGIN_AUDIT(_("Disconnected from %s via RDP"), host);
1060  freerdp_disconnect(rfi->instance);
1061  REMMINA_PLUGIN_DEBUG("RDP client disconnected");
1062 }
1063 
1064 static int remmina_rdp_load_static_channel_addin(rdpChannels *channels, rdpSettings *settings, char *name, void *data)
1065 {
1066  TRACE_CALL(__func__);
1067  PVIRTUALCHANNELENTRY entry = NULL;
1068  PVIRTUALCHANNELENTRYEX entryEx = NULL;
1069 
1070  entryEx = (PVIRTUALCHANNELENTRYEX)(void *)freerdp_load_channel_addin_entry(
1071  name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC | FREERDP_ADDIN_CHANNEL_ENTRYEX);
1072 
1073  if (!entryEx)
1074  entry = freerdp_load_channel_addin_entry(name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC);
1075 
1076  if (entryEx) {
1077  if (freerdp_channels_client_load_ex(channels, settings, entryEx, data) == 0) {
1078  fprintf(stderr, "loading channel %s\n", name);
1079  return TRUE;
1080  }
1081  } else if (entry) {
1082  if (freerdp_channels_client_load(channels, settings, entry, data) == 0) {
1083  fprintf(stderr, "loading channel %s\n", name);
1084  return TRUE;
1085  }
1086  }
1087 
1088  return FALSE;
1089 }
1090 
1091 static gchar *remmina_rdp_find_prdriver(char *smap, char *prn)
1092 {
1093  char c, *p, *dr;
1094  int matching;
1095  size_t sz;
1096 
1097  enum { S_WAITPR,
1098  S_INPRINTER,
1099  S_WAITCOLON,
1100  S_WAITDRIVER,
1101  S_INDRIVER,
1102  S_WAITSEMICOLON } state = S_WAITPR;
1103 
1104  matching = 0;
1105  while ((c = *smap++) != 0) {
1106  switch (state) {
1107  case S_WAITPR:
1108  if (c != '\"') return NULL;
1109  state = S_INPRINTER;
1110  p = prn;
1111  matching = 1;
1112  break;
1113  case S_INPRINTER:
1114  if (matching && c == *p && *p != 0) {
1115  p++;
1116  } else if (c == '\"') {
1117  if (*p != 0)
1118  matching = 0;
1119  state = S_WAITCOLON;
1120  } else {
1121  matching = 0;
1122  }
1123  break;
1124  case S_WAITCOLON:
1125  if (c != ':')
1126  return NULL;
1127  state = S_WAITDRIVER;
1128  break;
1129  case S_WAITDRIVER:
1130  if (c != '\"')
1131  return NULL;
1132  state = S_INDRIVER;
1133  dr = smap;
1134  break;
1135  case S_INDRIVER:
1136  if (c == '\"') {
1137  if (matching)
1138  goto found;
1139  else
1140  state = S_WAITSEMICOLON;
1141  }
1142  break;
1143  case S_WAITSEMICOLON:
1144  if (c != ';')
1145  return NULL;
1146  state = S_WAITPR;
1147  break;
1148  }
1149  }
1150  return NULL;
1151 
1152 found:
1153  sz = smap - dr;
1154  p = (char *)malloc(sz);
1155  memcpy(p, dr, sz);
1156  p[sz - 1] = 0;
1157  return p;
1158 }
1159 
1160 #ifdef HAVE_CUPS
1161 
1166 static int remmina_rdp_set_printers(void *user_data, unsigned flags, cups_dest_t *dest)
1167 {
1168  rfContext *rfi = (rfContext *)user_data;
1170 
1185  RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
1186  const gchar *s = remmina_plugin_service->file_get_string(remminafile, "printer_overrides");
1187 
1188  RDPDR_PRINTER *printer;
1189  printer = (RDPDR_PRINTER *)calloc(1, sizeof(RDPDR_PRINTER));
1190 
1191 #ifdef WITH_FREERDP3
1192  RDPDR_DEVICE *pdev;
1193  pdev = &(printer->device);
1194 #else
1195  RDPDR_PRINTER *pdev;
1196  pdev = printer;
1197 #endif
1198 
1199  pdev->Type = RDPDR_DTYP_PRINT;
1200  REMMINA_PLUGIN_DEBUG("Printer Type: %d", pdev->Type);
1201 
1202  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectPrinters, TRUE);
1203  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
1204 
1205  REMMINA_PLUGIN_DEBUG("Destination: %s", dest->name);
1206  if (!(pdev->Name = _strdup(dest->name))) {
1207  free(printer);
1208  return 1;
1209  }
1210 
1211  REMMINA_PLUGIN_DEBUG("Printer Name: %s", pdev->Name);
1212 
1213  if (s) {
1214  gchar *d = remmina_rdp_find_prdriver(strdup(s), pdev->Name);
1215  if (d) {
1216  printer->DriverName = strdup(d);
1217  REMMINA_PLUGIN_DEBUG("Printer DriverName set to: %s", printer->DriverName);
1218  g_free(d);
1219  } else {
1225  free(pdev->Name);
1226  free(printer);
1227  return 1;
1228  }
1229  } else {
1230  /* We set to a default driver*/
1231  printer->DriverName = _strdup("MS Publisher Imagesetter");
1232  }
1233 
1234  REMMINA_PLUGIN_DEBUG("Printer Driver: %s", printer->DriverName);
1235  if (!freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)printer)) {
1236  free(printer->DriverName);
1237  free(pdev->Name);
1238  free(printer);
1239  return 1;
1240  }
1241 
1242  return 1;
1243 }
1244 #endif /* HAVE_CUPS */
1245 
1246 /* Send Ctrl+Alt+Del keystrokes to the plugin drawing_area widget */
1248 {
1249  TRACE_CALL(__func__);
1250  guint keys[] = { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_Delete };
1251  rfContext *rfi = GET_PLUGIN_DATA(gp);
1252 
1253  remmina_plugin_service->protocol_plugin_send_keys_signals(rfi->drawing_area,
1254  keys, G_N_ELEMENTS(keys), GDK_KEY_PRESS | GDK_KEY_RELEASE);
1255 }
1256 
1257 static gboolean remmina_rdp_set_connection_type(rdpSettings *settings, guint32 type)
1258 {
1259  freerdp_settings_set_uint32(settings, FreeRDP_ConnectionType, type);
1260 
1261  if (type == CONNECTION_TYPE_MODEM) {
1262  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, TRUE);
1263  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, FALSE);
1264  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, FALSE);
1265  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE);
1266  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE);
1267  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, TRUE);
1268  } else if (type == CONNECTION_TYPE_BROADBAND_LOW) {
1269  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, TRUE);
1270  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, FALSE);
1271  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, FALSE);
1272  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE);
1273  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE);
1274  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
1275  } else if (type == CONNECTION_TYPE_SATELLITE) {
1276  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, TRUE);
1277  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, FALSE);
1278  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
1279  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE);
1280  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE);
1281  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
1282  } else if (type == CONNECTION_TYPE_BROADBAND_HIGH) {
1283  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, TRUE);
1284  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, FALSE);
1285  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
1286  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE);
1287  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE);
1288  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
1289  } else if (type == CONNECTION_TYPE_WAN) {
1290  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, FALSE);
1291  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, TRUE);
1292  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
1293  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, FALSE);
1294  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, FALSE);
1295  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
1296  } else if (type == CONNECTION_TYPE_LAN) {
1297  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, FALSE);
1298  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, TRUE);
1299  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
1300  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, FALSE);
1301  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, FALSE);
1302  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
1303  } else if (type == CONNECTION_TYPE_AUTODETECT) {
1304  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, FALSE);
1305  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, TRUE);
1306  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
1307  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, FALSE);
1308  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, FALSE);
1309  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
1310  freerdp_settings_set_bool(settings, FreeRDP_NetworkAutoDetect, TRUE);
1311 
1312  /* Automatically activate GFX and RFX codec support */
1313 #ifdef WITH_GFX_H264
1314  freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444, gfx_h264_available);
1315  freerdp_settings_set_bool(settings, FreeRDP_GfxH264, gfx_h264_available);
1316 #endif
1317  freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE);
1318  freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, TRUE);
1319  } else if (type == REMMINA_CONNECTION_TYPE_NONE) {
1320  return FALSE;
1321  } else {
1322  return FALSE;
1323  }
1324 
1325  return TRUE;
1326 }
1327 
1328 #ifdef GDK_WINDOWING_X11
1329 #if FREERDP_CHECK_VERSION(2, 3, 0)
1330 static gchar *remmina_get_rdp_kbd_remap(const gchar *keymap)
1331 {
1332  TRACE_CALL(__func__);
1333  guint *table;
1334  gchar keys[20];
1335  gchar *rdp_kbd_remap = NULL;
1336  gint i;
1337  Display *display;
1338 
1339  table = remmina_plugin_service->pref_keymap_get_table(keymap);
1340  if (!table)
1341  return rdp_kbd_remap;
1342  rdp_kbd_remap = g_malloc0(512);
1343  display = XOpenDisplay(0);
1344  for (i = 0; table[i] > 0; i += 2) {
1345  g_snprintf(keys, sizeof(keys), "0x%02x=0x%02x", freerdp_keyboard_get_rdp_scancode_from_x11_keycode(XKeysymToKeycode(display, table[i])),
1346  freerdp_keyboard_get_rdp_scancode_from_x11_keycode(XKeysymToKeycode(display, table[i + 1])));
1347  if (i > 0)
1348  g_strlcat(rdp_kbd_remap, ",", 512);
1349  g_strlcat(rdp_kbd_remap, keys, 512);
1350  }
1351  XCloseDisplay(display);
1352 
1353  return rdp_kbd_remap;
1354 }
1355 #endif
1356 #endif
1357 
1359 {
1360  TRACE_CALL(__func__);
1361  const gchar *s;
1362  gchar *sm;
1363  gchar *value;
1364  const gchar *cs;
1365  RemminaFile *remminafile;
1366  rfContext *rfi = GET_PLUGIN_DATA(gp);
1367  rdpChannels *channels;
1368  gchar *gateway_host;
1369  gint gateway_port;
1370  gchar *datapath = NULL;
1371  gboolean status = TRUE;
1372 #ifdef GDK_WINDOWING_X11
1373  gchar *rdp_kbd_remap;
1374 #endif
1375  gint i;
1376 
1377  gint desktopOrientation, desktopScaleFactor, deviceScaleFactor;
1378 
1379  channels = rfi->instance->context->channels;
1380 
1381  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
1382 
1383  datapath = g_build_path("/",
1384  remmina_plugin_service->file_get_user_datadir(),
1385  "RDP",
1386  NULL);
1387  REMMINA_PLUGIN_DEBUG("RDP data path is %s", datapath);
1388 
1389  if ((datapath != NULL) && (datapath[0] != '\0'))
1390  if (access(datapath, W_OK) == 0)
1391  freerdp_settings_set_string(rfi->settings, FreeRDP_ConfigPath, datapath);
1392  g_free(datapath);
1393 
1394  if (remmina_plugin_service->file_get_int(remminafile, "assistance_mode", 0)){
1395  rdpAssistanceFile* file = freerdp_assistance_file_new();
1396  if (!file){
1397  REMMINA_PLUGIN_DEBUG("Could not allocate assistance file structure");
1398  return FALSE;
1399  }
1400 
1401  if (remmina_plugin_service->file_get_string(remminafile, "assistance_file") == NULL ||
1402  remmina_plugin_service->file_get_string(remminafile, "assistance_pass") == NULL ){
1403 
1404  REMMINA_PLUGIN_DEBUG("Assistance file and password are not set while assistance mode is on");
1405  return FALSE;
1406  }
1407 
1408  status = freerdp_assistance_parse_file(file,
1409  remmina_plugin_service->file_get_string(remminafile, "assistance_file"),
1410  remmina_plugin_service->file_get_string(remminafile, "assistance_pass"));
1411 
1412  if (status < 0){
1413  REMMINA_PLUGIN_DEBUG("Could not parse assistance file");
1414  return FALSE;
1415  }
1416 
1417 
1418  if (!freerdp_assistance_populate_settings_from_assistance_file(file, rfi->settings)){
1419  REMMINA_PLUGIN_DEBUG("Could not populate settings from assistance file");
1420  return FALSE;
1421  }
1422  }
1423 
1424 
1425 #if defined(PROXY_TYPE_IGNORE)
1426  if (!remmina_plugin_service->file_get_int(remminafile, "useproxyenv", FALSE) ? TRUE : FALSE) {
1427  REMMINA_PLUGIN_DEBUG("Not using system proxy settings");
1428  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ProxyType, PROXY_TYPE_IGNORE);
1429  }
1430 #endif
1431 
1432  if (!remmina_rdp_tunnel_init(gp))
1433  return FALSE;
1434 
1435  freerdp_settings_set_bool(rfi->settings, FreeRDP_AutoReconnectionEnabled, (remmina_plugin_service->file_get_int(remminafile, "disableautoreconnect", FALSE) ? FALSE : TRUE));
1436  /* Disable RDP auto reconnection when SSH tunnel is enabled */
1437  if (remmina_plugin_service->file_get_int(remminafile, "ssh_tunnel_enabled", FALSE))
1438  freerdp_settings_set_bool(rfi->settings, FreeRDP_AutoReconnectionEnabled, FALSE);
1439 
1440  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, remmina_plugin_service->file_get_int(remminafile, "colordepth", 99));
1441 
1442  freerdp_settings_set_bool(rfi->settings, FreeRDP_SoftwareGdi, TRUE);
1443  REMMINA_PLUGIN_DEBUG("gfx_h264_available: %d", gfx_h264_available);
1444 
1445  /* Avoid using H.264 modes if they are not available on libfreerdp */
1446  if (!gfx_h264_available && (freerdp_settings_get_bool(rfi->settings, FreeRDP_ColorDepth) == 65 || freerdp_settings_get_bool(rfi->settings, FreeRDP_ColorDepth == 66)))
1447  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 64); // Fallback to GFX RFX
1448 
1449  if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 0) {
1450  /* RFX (Win7)*/
1451  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteFxCodec, TRUE);
1452  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, FALSE);
1453  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
1454  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 63) {
1455  /* /gfx (RFX Progressive) (Win8) */
1456  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
1457  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
1458  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, FALSE);
1459  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, FALSE);
1460  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 64) {
1461  /* /gfx:rfx (Win8) */
1462  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
1463  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteFxCodec, TRUE);
1464  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
1465  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, FALSE);
1466  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, FALSE);
1467  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 65) {
1468  /* /gfx:avc420 (Win8.1) */
1469  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
1470  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
1471  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, gfx_h264_available);
1472  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, FALSE);
1473  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 66) {
1474  /* /gfx:avc444 (Win10) */
1475  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
1476  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
1477  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, gfx_h264_available);
1478  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, gfx_h264_available);
1479  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 99) {
1480  /* Automatic (Let the server choose its best format) */
1481  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
1482  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteFxCodec, TRUE);
1483  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
1484  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, gfx_h264_available);
1485  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, gfx_h264_available);
1486  }
1487 
1488  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_RemoteFxCodec) ||
1489  freerdp_settings_get_bool(rfi->settings, FreeRDP_NSCodec) ||
1490  freerdp_settings_get_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline)) {
1491  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathOutput, TRUE);
1492  freerdp_settings_set_bool(rfi->settings, FreeRDP_FrameMarkerCommandEnabled, TRUE);
1493  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
1494  rfi->bpp = 32;
1495  }
1496 
1497  gint w = remmina_plugin_service->get_profile_remote_width(gp);
1498  gint h = remmina_plugin_service->get_profile_remote_height(gp);
1499  /* multiple of 4 */
1500  w = (w + 3) & ~0x3;
1501  h = (h + 3) & ~0x3;
1502  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopWidth, w);
1503  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopHeight, h);
1504  REMMINA_PLUGIN_DEBUG("Resolution set by the user: %dx%d", w, h);
1505 
1506  /* Workaround for FreeRDP issue #5417: in GFX AVC modes we can't go under
1507  * AVC_MIN_DESKTOP_WIDTH x AVC_MIN_DESKTOP_HEIGHT */
1508  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline) &&
1509  freerdp_settings_get_bool(rfi->settings, FreeRDP_GfxH264)) {
1510  if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth) <
1511  AVC_MIN_DESKTOP_WIDTH)
1512  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopWidth,
1513  AVC_MIN_DESKTOP_WIDTH);
1514  if (freerdp_settings_get_uint32(rfi->settings,
1515  FreeRDP_DesktopHeight) <
1516  AVC_MIN_DESKTOP_HEIGHT)
1517  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopHeight,
1518  AVC_MIN_DESKTOP_HEIGHT);
1519  }
1520 
1521  /* Workaround for FreeRDP issue #5119. This will make our horizontal resolution
1522  * an even value, but it will add a vertical black 1 pixel line on the
1523  * right of the desktop */
1524  if ((freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth) & 1) != 0) {
1525  UINT32 tmp = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth);
1526  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopWidth, tmp - 1);
1527  }
1528 
1529  remmina_plugin_service->protocol_plugin_set_width(gp, freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth));
1530  remmina_plugin_service->protocol_plugin_set_height(gp, freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight));
1531 
1532  w = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth);
1533  h = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight);
1534  REMMINA_PLUGIN_DEBUG("Resolution set after workarounds: %dx%d", w, h);
1535 
1536 
1537  if (remmina_plugin_service->file_get_string(remminafile, "username"))
1538  freerdp_settings_set_string(rfi->settings, FreeRDP_Username, remmina_plugin_service->file_get_string(remminafile, "username"));
1539 
1540  if (remmina_plugin_service->file_get_string(remminafile, "domain"))
1541  freerdp_settings_set_string(rfi->settings, FreeRDP_Domain, remmina_plugin_service->file_get_string(remminafile, "domain"));
1542 
1543  s = remmina_plugin_service->file_get_string(remminafile, "password");
1544  if (s) freerdp_settings_set_string(rfi->settings, FreeRDP_Password, s);
1545 
1546  freerdp_settings_set_bool(rfi->settings, FreeRDP_AutoLogonEnabled, TRUE);
1547 
1552  gchar *proxy_type = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_type"));
1553  gchar *proxy_username = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_username"));
1554  gchar *proxy_password = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_password"));
1555  gchar *proxy_hostname = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_hostname"));
1556  gint proxy_port = remmina_plugin_service->file_get_int(remminafile, "proxy_port", 80);
1557  REMMINA_PLUGIN_DEBUG("proxy_type: %s", proxy_type);
1558  REMMINA_PLUGIN_DEBUG("proxy_username: %s", proxy_username);
1559  REMMINA_PLUGIN_DEBUG("proxy_password: %s", proxy_password);
1560  REMMINA_PLUGIN_DEBUG("proxy_hostname: %s", proxy_hostname);
1561  REMMINA_PLUGIN_DEBUG("proxy_port: %d", proxy_port);
1562  if (proxy_type && proxy_hostname) {
1563  if (g_strcmp0(proxy_type, "no_proxy") == 0)
1564  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ProxyType, PROXY_TYPE_IGNORE);
1565  else if (g_strcmp0(proxy_type, "http") == 0)
1566  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ProxyType, PROXY_TYPE_HTTP);
1567  else if (g_strcmp0(proxy_type, "socks5") == 0)
1568  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ProxyType, PROXY_TYPE_SOCKS);
1569  else
1570  g_warning("Invalid proxy protocol, at the moment only no_proxy, HTTP and SOCKS5 are supported");
1571  REMMINA_PLUGIN_DEBUG("ProxyType set to: %" PRIu32, freerdp_settings_get_uint32(rfi->settings, FreeRDP_ProxyType));
1572  freerdp_settings_set_string(rfi->settings, FreeRDP_ProxyHostname, proxy_hostname);
1573  if (proxy_username)
1574  freerdp_settings_set_string(rfi->settings, FreeRDP_ProxyUsername, proxy_username);
1575  if (proxy_password)
1576  freerdp_settings_set_string(rfi->settings, FreeRDP_ProxyPassword, proxy_password);
1577  if (proxy_port)
1578  freerdp_settings_set_uint16(rfi->settings, FreeRDP_ProxyPort, proxy_port);
1579  }
1580  g_free(proxy_hostname);
1581  g_free(proxy_username);
1582  g_free(proxy_password);
1583 
1584  if (remmina_plugin_service->file_get_int(remminafile, "base-cred-for-gw", FALSE)) {
1585  // Reset gateway credentials
1586  remmina_plugin_service->file_set_string(remminafile, "gateway_username", NULL);
1587  remmina_plugin_service->file_set_string(remminafile, "gateway_domain", NULL);
1588  remmina_plugin_service->file_set_string(remminafile, "gateway_password", NULL);
1589  }
1590 
1591  /* Remote Desktop Gateway server address */
1592  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayEnabled, FALSE);
1593  s = remmina_plugin_service->file_get_string(remminafile, "gateway_server");
1594  if (s) {
1595  cs = remmina_plugin_service->file_get_string(remminafile, "gwtransp");
1596 #if FREERDP_CHECK_VERSION(2, 3, 1)
1597  if (remmina_plugin_service->file_get_int(remminafile, "websockets", FALSE))
1598  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpUseWebsockets, TRUE);
1599  else
1600  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpUseWebsockets, FALSE);
1601 #endif
1602  if (g_strcmp0(cs, "http") == 0) {
1603  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayRpcTransport, FALSE);
1604  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpTransport, TRUE);
1605  } else if (g_strcmp0(cs, "rpc") == 0) {
1606  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayRpcTransport, TRUE);
1607  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpTransport, FALSE);
1608  } else if (g_strcmp0(cs, "auto") == 0) {
1609  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayRpcTransport, TRUE);
1610  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpTransport, TRUE);
1611  }
1612  remmina_plugin_service->get_server_port(s, 443, &gateway_host, &gateway_port);
1613  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayHostname, gateway_host);
1614  freerdp_settings_set_uint32(rfi->settings, FreeRDP_GatewayPort, gateway_port);
1615  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayEnabled, TRUE);
1616  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, TRUE);
1617  }
1618  /* Remote Desktop Gateway domain */
1619  if (remmina_plugin_service->file_get_string(remminafile, "gateway_domain")) {
1620  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayDomain, remmina_plugin_service->file_get_string(remminafile, "gateway_domain"));
1621  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, FALSE);
1622  }
1623  /* Remote Desktop Gateway username */
1624  if (remmina_plugin_service->file_get_string(remminafile, "gateway_username")) {
1625  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayUsername, remmina_plugin_service->file_get_string(remminafile, "gateway_username"));
1626  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, FALSE);
1627  }
1628  /* Remote Desktop Gateway password */
1629  s = remmina_plugin_service->file_get_string(remminafile, "gateway_password");
1630  if (s) {
1631  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayPassword, s);
1632  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, FALSE);
1633  }
1634  /* If no different credentials were provided for the Remote Desktop Gateway
1635  * use the same authentication credentials for the host */
1636  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_GatewayEnabled) && freerdp_settings_get_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials)) {
1637  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayDomain, freerdp_settings_get_string(rfi->settings, FreeRDP_Domain));
1638  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayUsername, freerdp_settings_get_string(rfi->settings, FreeRDP_Username));
1639  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayPassword, freerdp_settings_get_string(rfi->settings, FreeRDP_Password));
1640  }
1641  /* Remote Desktop Gateway usage */
1642  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_GatewayEnabled))
1643  freerdp_set_gateway_usage_method(rfi->settings,
1644  remmina_plugin_service->file_get_int(remminafile, "gateway_usage", FALSE) ? TSC_PROXY_MODE_DETECT : TSC_PROXY_MODE_DIRECT);
1645 
1646  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayAccessToken,
1647  remmina_plugin_service->file_get_string(remminafile, "gatewayaccesstoken"));
1648 
1649  freerdp_settings_set_uint32(rfi->settings, FreeRDP_AuthenticationLevel, remmina_plugin_service->file_get_int(
1650  remminafile, "authentication level", freerdp_settings_get_uint32(rfi->settings, FreeRDP_AuthenticationLevel)));
1651 
1652  /* Certificate ignore */
1653  freerdp_settings_set_bool(rfi->settings, FreeRDP_IgnoreCertificate, remmina_plugin_service->file_get_int(remminafile, "cert_ignore", 0));
1654  freerdp_settings_set_bool(rfi->settings, FreeRDP_OldLicenseBehaviour, remmina_plugin_service->file_get_int(remminafile, "old-license", 0));
1655  freerdp_settings_set_bool(rfi->settings, FreeRDP_AllowUnanouncedOrdersFromServer, remmina_plugin_service->file_get_int(remminafile, "relax-order-checks", 0));
1656  freerdp_settings_set_uint32(rfi->settings, FreeRDP_GlyphSupportLevel, (remmina_plugin_service->file_get_int(remminafile, "glyph-cache", 0) ? GLYPH_SUPPORT_FULL : GLYPH_SUPPORT_NONE));
1657 
1658  if ((cs = remmina_plugin_service->file_get_string(remminafile, "clientname")))
1659  freerdp_settings_set_string(rfi->settings, FreeRDP_ClientHostname, cs);
1660  else
1661  freerdp_settings_set_string(rfi->settings, FreeRDP_ClientHostname, g_get_host_name());
1662 
1663  /* Client Build number is optional, if not specified defaults to 0, allow for comments to appear after number */
1664  if ((cs = remmina_plugin_service->file_get_string(remminafile, "clientbuild"))) {
1665  if (*cs) {
1666  UINT32 val = strtoul(cs, NULL, 0);
1667  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ClientBuild, val);
1668  }
1669  }
1670 
1671 
1672  if (remmina_plugin_service->file_get_string(remminafile, "loadbalanceinfo")) {
1673  char *tmp = strdup(remmina_plugin_service->file_get_string(remminafile, "loadbalanceinfo"));
1674  rfi->settings->LoadBalanceInfo = (BYTE *)tmp;
1675 
1676  freerdp_settings_set_uint32(rfi->settings, FreeRDP_LoadBalanceInfoLength, strlen(tmp));
1677  }
1678 
1679  if (remmina_plugin_service->file_get_string(remminafile, "exec"))
1680  freerdp_settings_set_string(rfi->settings, FreeRDP_AlternateShell, remmina_plugin_service->file_get_string(remminafile, "exec"));
1681 
1682  if (remmina_plugin_service->file_get_string(remminafile, "execpath"))
1683  freerdp_settings_set_string(rfi->settings, FreeRDP_ShellWorkingDirectory, remmina_plugin_service->file_get_string(remminafile, "execpath"));
1684 
1685  sm = g_strdup_printf("rdp_quality_%i", remmina_plugin_service->file_get_int(remminafile, "quality", DEFAULT_QUALITY_0));
1686  value = remmina_plugin_service->pref_get_value(sm);
1687  g_free(sm);
1688 
1689  if (value && value[0]) {
1690  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, strtoul(value, NULL, 16));
1691  } else {
1692  switch (remmina_plugin_service->file_get_int(remminafile, "quality", DEFAULT_QUALITY_0)) {
1693  case 9:
1694  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, DEFAULT_QUALITY_9);
1695  break;
1696 
1697  case 2:
1698  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, DEFAULT_QUALITY_2);
1699  break;
1700 
1701  case 1:
1702  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, DEFAULT_QUALITY_1);
1703  break;
1704 
1705  case 0:
1706  default:
1707  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, DEFAULT_QUALITY_0);
1708  break;
1709  }
1710  }
1711  g_free(value);
1712 
1713  if ((cs = remmina_plugin_service->file_get_string(remminafile, "network"))) {
1714  guint32 type = 0;
1715 
1716  if (g_strcmp0(cs, "modem") == 0)
1717  type = CONNECTION_TYPE_MODEM;
1718  else if (g_strcmp0(cs, "broadband") == 0)
1719  type = CONNECTION_TYPE_BROADBAND_HIGH;
1720  else if (g_strcmp0(cs, "broadband-low") == 0)
1721  type = CONNECTION_TYPE_BROADBAND_LOW;
1722  else if (g_strcmp0(cs, "broadband-high") == 0)
1723  type = CONNECTION_TYPE_BROADBAND_HIGH;
1724  else if (g_strcmp0(cs, "wan") == 0)
1725  type = CONNECTION_TYPE_WAN;
1726  else if (g_strcmp0(cs, "lan") == 0)
1727  type = CONNECTION_TYPE_LAN;
1728  else if ((g_strcmp0(cs, "autodetect") == 0))
1729  type = CONNECTION_TYPE_AUTODETECT;
1730  else if ((g_strcmp0(cs, "none") == 0))
1731  type = REMMINA_CONNECTION_TYPE_NONE;
1732  else
1733  type = REMMINA_CONNECTION_TYPE_NONE;
1734 
1735  if (!remmina_rdp_set_connection_type(rfi->settings, type))
1736  REMMINA_PLUGIN_DEBUG("Network settings not set");
1737  }
1738 
1739  /* PerformanceFlags bitmask need also to be splitted into BOOL variables
1740  * like freerdp_settings_set_bool(rfi->settings, FreeRDP_DisableWallpaper, freerdp_settings_set_bool(rfi->settings, FreeRDP_AllowFontSmoothing…
1741  * or freerdp_get_param_bool() function will return the wrong value
1742  */
1743  freerdp_performance_flags_split(rfi->settings);
1744 
1745 #ifdef GDK_WINDOWING_X11
1746 #if FREERDP_CHECK_VERSION(2, 3, 0)
1747  rdp_kbd_remap = remmina_get_rdp_kbd_remap(remmina_plugin_service->file_get_string(remminafile, "keymap"));
1748  if (rdp_kbd_remap != NULL) {
1749  freerdp_settings_set_string(rfi->settings, FreeRDP_KeyboardRemappingList, rdp_kbd_remap);
1750  REMMINA_PLUGIN_DEBUG("rdp_keyboard_remapping_list: %s", rfi->settings->KeyboardRemappingList);
1751  g_free(rdp_kbd_remap);
1752  }
1753  else {
1754  freerdp_settings_set_string(rfi->settings, FreeRDP_KeyboardRemappingList, remmina_plugin_service->pref_get_value("rdp_kbd_remap"));
1755  REMMINA_PLUGIN_DEBUG("rdp_keyboard_remapping_list: %s", rfi->settings->KeyboardRemappingList);
1756  }
1757 #endif
1758 #endif
1759 
1760  freerdp_settings_set_uint32(rfi->settings, FreeRDP_KeyboardLayout, remmina_rdp_settings_get_keyboard_layout());
1761 
1762  if (remmina_plugin_service->file_get_int(remminafile, "console", FALSE))
1763  freerdp_settings_set_bool(rfi->settings, FreeRDP_ConsoleSession, TRUE);
1764 
1765  if (remmina_plugin_service->file_get_int(remminafile, "restricted-admin", FALSE)) {
1766  freerdp_settings_set_bool(rfi->settings, FreeRDP_ConsoleSession, TRUE);
1767  freerdp_settings_set_bool(rfi->settings, FreeRDP_RestrictedAdminModeRequired, TRUE);
1768  }
1769 
1770  if (remmina_plugin_service->file_get_string(remminafile, "pth")) {
1771  freerdp_settings_set_bool(rfi->settings, FreeRDP_ConsoleSession, TRUE);
1772  freerdp_settings_set_bool(rfi->settings, FreeRDP_RestrictedAdminModeRequired, TRUE);
1773  freerdp_settings_set_string(rfi->settings, FreeRDP_PasswordHash, remmina_plugin_service->file_get_string(remminafile, "pth"));
1774  remmina_plugin_service->file_set_int(remminafile, "restricted-admin", TRUE);
1775  }
1776 
1777  cs = remmina_plugin_service->file_get_string(remminafile, "security");
1778  if (g_strcmp0(cs, "rdp") == 0) {
1779  freerdp_settings_set_bool(rfi->settings, FreeRDP_RdpSecurity, TRUE);
1780  freerdp_settings_set_bool(rfi->settings, FreeRDP_TlsSecurity, FALSE);
1781  freerdp_settings_set_bool(rfi->settings, FreeRDP_NlaSecurity, FALSE);
1782  freerdp_settings_set_bool(rfi->settings, FreeRDP_ExtSecurity, FALSE);
1783  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseRdpSecurityLayer, TRUE);
1784  } else if (g_strcmp0(cs, "tls") == 0) {
1785  freerdp_settings_set_bool(rfi->settings, FreeRDP_RdpSecurity, FALSE);
1786  freerdp_settings_set_bool(rfi->settings, FreeRDP_TlsSecurity, TRUE);
1787  freerdp_settings_set_bool(rfi->settings, FreeRDP_NlaSecurity, FALSE);
1788  freerdp_settings_set_bool(rfi->settings, FreeRDP_ExtSecurity, FALSE);
1789  } else if (g_strcmp0(cs, "nla") == 0) {
1790  freerdp_settings_set_bool(rfi->settings, FreeRDP_RdpSecurity, FALSE);
1791  freerdp_settings_set_bool(rfi->settings, FreeRDP_TlsSecurity, FALSE);
1792  freerdp_settings_set_bool(rfi->settings, FreeRDP_NlaSecurity, TRUE);
1793  freerdp_settings_set_bool(rfi->settings, FreeRDP_ExtSecurity, FALSE);
1794  } else if (g_strcmp0(cs, "ext") == 0) {
1795  freerdp_settings_set_bool(rfi->settings, FreeRDP_RdpSecurity, FALSE);
1796  freerdp_settings_set_bool(rfi->settings, FreeRDP_TlsSecurity, FALSE);
1797  freerdp_settings_set_bool(rfi->settings, FreeRDP_NlaSecurity, FALSE);
1798  freerdp_settings_set_bool(rfi->settings, FreeRDP_ExtSecurity, TRUE);
1799  } else {
1800  /* This is "-nego" switch of xfreerdp */
1801  freerdp_settings_set_bool(rfi->settings, FreeRDP_NegotiateSecurityLayer, TRUE);
1802  }
1803 
1804  cs = remmina_plugin_service->file_get_string(remminafile, "tls-seclevel");
1805  if (cs && g_strcmp0(cs,"")!=0) {
1806  i = atoi(cs);
1807  freerdp_settings_set_uint32(rfi->settings, FreeRDP_TlsSecLevel, i);
1808  }
1809 
1810  freerdp_settings_set_bool(rfi->settings, FreeRDP_CompressionEnabled, TRUE);
1811  if (remmina_plugin_service->file_get_int(remminafile, "disable_fastpath", FALSE)) {
1812  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathInput, FALSE);
1813  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathOutput, FALSE);
1814  } else {
1815  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathInput, TRUE);
1816  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathOutput, TRUE);
1817  }
1818 
1819  /* Orientation and scaling settings */
1820  remmina_rdp_settings_get_orientation_scale_prefs(&desktopOrientation, &desktopScaleFactor, &deviceScaleFactor);
1821 
1822  freerdp_settings_set_uint16(rfi->settings, FreeRDP_DesktopOrientation, desktopOrientation);
1823  if (desktopScaleFactor != 0 && deviceScaleFactor != 0) {
1824  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopScaleFactor, desktopScaleFactor);
1825  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DeviceScaleFactor, deviceScaleFactor);
1826  }
1827 
1828  /* Try to enable "Display Control Virtual Channel Extension", needed to
1829  * dynamically resize remote desktop. This will automatically open
1830  * the "disp" dynamic channel, if available */
1831  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportDisplayControl, TRUE);
1832 
1833  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_SupportDisplayControl)) {
1834  CLPARAM *d[1];
1835  int dcount;
1836 
1837  dcount = 1;
1838  d[0] = "disp";
1839  freerdp_client_add_dynamic_channel(rfi->settings, dcount, d);
1840  }
1841 
1842  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline)) {
1843  CLPARAM *d[1];
1844 
1845  int dcount;
1846 
1847  dcount = 1;
1848  d[0] = "rdpgfx";
1849  freerdp_client_add_dynamic_channel(rfi->settings, dcount, d);
1850  }
1851 
1852  /* Sound settings */
1853  cs = remmina_plugin_service->file_get_string(remminafile, "sound");
1854  if (g_strcmp0(cs, "remote") == 0) {
1855  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteConsoleAudio, TRUE);
1856  } else if (g_str_has_prefix(cs, "local")) {
1857  freerdp_settings_set_bool(rfi->settings, FreeRDP_AudioPlayback, TRUE);
1858  freerdp_settings_set_bool(rfi->settings, FreeRDP_AudioCapture, TRUE);
1859  } else {
1860  /* Disable sound */
1861  freerdp_settings_set_bool(rfi->settings, FreeRDP_AudioPlayback, FALSE);
1862  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteConsoleAudio, FALSE);
1863  }
1864 
1865  cs = remmina_plugin_service->file_get_string(remminafile, "microphone");
1866  if (cs != NULL && cs[0] != '\0') {
1867  if (g_strcmp0(cs, "0") == 0) {
1868  REMMINA_PLUGIN_DEBUG("“microphone” was set to 0, setting to \"\"");
1869  remmina_plugin_service->file_set_string(remminafile, "microphone", "");
1870  } else {
1871  freerdp_settings_set_bool(rfi->settings, FreeRDP_AudioCapture, TRUE);
1872  REMMINA_PLUGIN_DEBUG("“microphone” set to “%s”", cs);
1873  CLPARAM **p;
1874  size_t count;
1875 
1876  p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("audin", g_strdup(cs), &count);
1877 
1878  freerdp_client_add_dynamic_channel(rfi->settings, count, p);
1879  g_free(p);
1880  }
1881  }
1882 
1883  cs = remmina_plugin_service->file_get_string(remminafile, "audio-output");
1884  if (cs != NULL && cs[0] != '\0') {
1885  REMMINA_PLUGIN_DEBUG("audio output set to %s", cs);
1886  CLPARAM **p;
1887  size_t count;
1888 
1889  p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("rdpsnd", g_strdup(cs), &count);
1890  status = freerdp_client_add_static_channel(rfi->settings, count, p);
1891  if (status)
1892  status = freerdp_client_add_dynamic_channel(rfi->settings, count, p);
1893  g_free(p);
1894  }
1895 
1896 
1897  cs = remmina_plugin_service->file_get_string(remminafile, "freerdp_log_level");
1898  if (cs != NULL && cs[0] != '\0')
1899  REMMINA_PLUGIN_DEBUG("Log level set to to %s", cs);
1900  else
1901  cs = g_strdup("INFO");
1902  wLog *root = WLog_GetRoot();
1903  WLog_SetStringLogLevel(root, cs);
1904 
1905  cs = remmina_plugin_service->file_get_string(remminafile, "freerdp_log_filters");
1906  if (cs != NULL && cs[0] != '\0') {
1907  REMMINA_PLUGIN_DEBUG("Log filters set to to %s", cs);
1908  WLog_AddStringLogFilters(cs);
1909  } else {
1910  WLog_AddStringLogFilters(NULL);
1911  }
1912 
1913 
1914  cs = remmina_plugin_service->file_get_string(remminafile, "usb");
1915  if (cs != NULL && cs[0] != '\0') {
1916  CLPARAM **p;
1917  size_t count;
1918  p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("urbdrc", g_strdup(cs), &count);
1919  freerdp_client_add_dynamic_channel(rfi->settings, count, p);
1920  g_free(p);
1921  }
1922 
1923  cs = remmina_plugin_service->file_get_string(remminafile, "vc");
1924  if (cs != NULL && cs[0] != '\0') {
1925  CLPARAM **p;
1926  size_t count;
1927  p = remmina_rdp_CommandLineParseCommaSeparatedValues(g_strdup(cs), &count);
1928  freerdp_client_add_static_channel(rfi->settings, count, p);
1929  g_free(p);
1930  }
1931 
1932  cs = remmina_plugin_service->file_get_string(remminafile, "dvc");
1933  if (cs != NULL && cs[0] != '\0') {
1934  CLPARAM **p;
1935  size_t count;
1936  p = remmina_rdp_CommandLineParseCommaSeparatedValues(g_strdup(cs), &count);
1937  freerdp_client_add_dynamic_channel(rfi->settings, count, p);
1938  g_free(p);
1939  }
1940 
1941  cs = remmina_plugin_service->file_get_string(remminafile, "rdp2tcp");
1942  if (cs != NULL && cs[0] != '\0') {
1943  g_free(rfi->settings->RDP2TCPArgs);
1944  rfi->settings->RDP2TCPArgs = g_strdup(cs);
1945  REMMINA_PLUGIN_DEBUG("rdp2tcp set to %s", rfi->settings->RDP2TCPArgs);
1946  remmina_rdp_load_static_channel_addin(channels, rfi->settings, "rdp2tcp", rfi->settings->RDP2TCPArgs);
1947  }
1948 
1949  int vermaj, vermin, verrev;
1950  freerdp_get_version(&vermaj, &vermin, &verrev);
1951 
1952 #if FREERDP_CHECK_VERSION(2, 1, 0)
1953  cs = remmina_plugin_service->file_get_string(remminafile, "timeout");
1954  if (cs != NULL && cs[0] != '\0') {
1955  const gchar *endptr = NULL;
1956  guint64 val = g_ascii_strtoull(cs, (gchar **)&endptr, 10);
1957  if (val > 600000 || val <= 0)
1958  val = 600000;
1959  freerdp_settings_set_uint32(rfi->settings, FreeRDP_TcpAckTimeout, (UINT32)val);
1960  }
1961 #endif
1962 
1963  if (remmina_plugin_service->file_get_int(remminafile, "preferipv6", FALSE) ? TRUE : FALSE)
1964  freerdp_settings_set_bool(rfi->settings, FreeRDP_PreferIPv6OverIPv4, TRUE);
1965 
1966  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectClipboard, remmina_plugin_service->file_get_int(remminafile, "disableclipboard", FALSE) ? FALSE : TRUE);
1967 
1968  cs = remmina_plugin_service->file_get_string(remminafile, "sharefolder");
1969  if (cs != NULL && cs[0] != '\0') {
1970  gchar *ccs = g_strdup(cs);
1971  REMMINA_PLUGIN_DEBUG("[Deprecated->migrating] - Old sharefolder %s to \"drive \"", ccs);
1972  if (!remmina_plugin_service->file_get_string(remminafile, "drive")) {
1973  remmina_plugin_service->file_set_string(remminafile, "drive", g_strdup(ccs));
1974  remmina_plugin_service->file_set_string(remminafile, "sharefolder", NULL);
1975  REMMINA_PLUGIN_DEBUG("[Deprecated->migrated] - drive set to %s", g_strdup(ccs));
1976  }
1977  g_free(ccs);
1978  //CLPARAM **p;
1979  //size_t count;
1980  //p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("drive", g_strdup(cs), &count);
1981  //status = freerdp_client_add_device_channel(rfi->settings, count, p);
1982  //g_free(p);
1983  }
1984  cs = remmina_plugin_service->file_get_string(remminafile, "drive");
1985  if (cs != NULL && cs[0] != '\0') {
1986  REMMINA_PLUGIN_DEBUG("Redirect directory set to %s", cs);
1987  CLPARAM **p;
1988  size_t count;
1989 
1990  gchar **folders = g_strsplit(cs, ";", -1);
1991  for (i = 0; folders[i] != NULL; i++) {
1992  REMMINA_PLUGIN_DEBUG("Parsing folder %s", folders[i]);
1993  p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("drive", g_strdup(folders[i]), &count);
1994  status = freerdp_client_add_device_channel(rfi->settings, count, p);
1995  g_free(p);
1996  }
1997  g_strfreev(folders);
1998  }
1999 
2000  if (remmina_plugin_service->file_get_int(remminafile, "shareprinter", FALSE)) {
2001 #ifdef HAVE_CUPS
2002  REMMINA_PLUGIN_DEBUG("Sharing printers");
2003  const gchar *po = remmina_plugin_service->file_get_string(remminafile, "printer_overrides");
2004  if (po && po[0] != 0) {
2005  /* Fallback to remmina code to override print drivers */
2006  if (cupsEnumDests(CUPS_DEST_FLAGS_NONE, 1000, NULL, 0, 0, remmina_rdp_set_printers, rfi))
2007  REMMINA_PLUGIN_DEBUG("All printers have been shared");
2008  else
2009  REMMINA_PLUGIN_DEBUG("Cannot share printers, are there any available?");
2010  } else {
2011  /* Use libfreerdp code to map all printers */
2012  CLPARAM *d[1];
2013  int dcount;
2014  dcount = 1;
2015  d[0] = "printer";
2016  freerdp_client_add_device_channel(rfi->settings, dcount, d);
2017  }
2018 #endif /* HAVE_CUPS */
2019  }
2020 
2021  if (remmina_plugin_service->file_get_int(remminafile, "span", FALSE)) {
2022  freerdp_settings_set_bool(rfi->settings, FreeRDP_SpanMonitors, TRUE);
2023  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseMultimon, TRUE);
2024  freerdp_settings_set_bool(rfi->settings, FreeRDP_Fullscreen, TRUE);
2025  remmina_plugin_service->file_set_int(remminafile, "multimon", 1);
2026  }
2027 
2028  if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) {
2029  guint32 maxwidth = 0;
2030  guint32 maxheight = 0;
2031  gchar *monitorids;
2032  guint32 i;
2033  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseMultimon, TRUE);
2034  /* TODO Add an option for this */
2035  freerdp_settings_set_bool(rfi->settings, FreeRDP_ForceMultimon, TRUE);
2036  freerdp_settings_set_bool(rfi->settings, FreeRDP_Fullscreen, TRUE);
2037 
2038  gchar *monitorids_string = g_strdup(remmina_plugin_service->file_get_string(remminafile, "monitorids"));
2039  /* Otherwise we get all the attached monitors
2040  * monitorids may contains desktop orientation values.
2041  * But before we check if there are orientation attributes
2042  */
2043  if (monitorids_string != NULL && monitorids_string[0] != '\0') {
2044  if (g_strstr_len(monitorids_string, -1, ",") != NULL) {
2045  if (g_strstr_len(monitorids_string, -1, ":") != NULL) {
2046  rdpMonitor *base = (rdpMonitor *)freerdp_settings_get_pointer(rfi->settings, FreeRDP_MonitorDefArray);
2047  /* We have an ID and an orientation degree */
2048  gchar **temp_items;
2049  gchar **rot_items;
2050  temp_items = g_strsplit(monitorids_string, ",", -1);
2051  for (i = 0; i < g_strv_length(temp_items); i++) {
2052  rot_items = g_strsplit(temp_items[i], ":", -1);
2053  rdpMonitor *current = &base[atoi(rot_items[0])];
2054  if (i == 0)
2055  monitorids = g_strdup(rot_items[0]);
2056  else
2057  monitorids = g_strdup_printf("%s,%s", monitorids, rot_items[0]);
2058  current->attributes.orientation = atoi(rot_items[1]);
2059  REMMINA_PLUGIN_DEBUG("Monitor n %d orientation: %d", i, current->attributes.orientation);
2060  }
2061  } else {
2062  monitorids = g_strdup(monitorids_string);
2063  }
2064  } else {
2065  monitorids = g_strdup(monitorids_string);
2066  }
2067  } else {
2068  monitorids = g_strdup(monitorids_string);
2069  }
2070  remmina_rdp_monitor_get(rfi, &monitorids, &maxwidth, &maxheight);
2071  if (monitorids != NULL && monitorids[0] != '\0') {
2072  UINT32 *base = (UINT32 *)freerdp_settings_get_pointer(rfi->settings, FreeRDP_MonitorIds);
2073  gchar **items;
2074  items = g_strsplit(monitorids, ",", -1);
2075  freerdp_settings_set_uint32(rfi->settings, FreeRDP_NumMonitorIds, g_strv_length(items));
2076  REMMINA_PLUGIN_DEBUG("NumMonitorIds: %d", freerdp_settings_get_uint32(rfi->settings, FreeRDP_NumMonitorIds));
2077  for (i = 0; i < g_strv_length(items); i++) {
2078  UINT32 *current = &base[i];
2079  *current = atoi(items[i]);
2080  REMMINA_PLUGIN_DEBUG("Added monitor with ID %" PRIu32, *current);
2081  }
2082  g_free(monitorids);
2083  g_strfreev(items);
2084  }
2085  if (maxwidth && maxheight) {
2086  REMMINA_PLUGIN_DEBUG("Setting DesktopWidth and DesktopHeight to: %dx%d", maxwidth, maxheight);
2087  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopWidth, maxwidth);
2088  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopHeight, maxheight);
2089  REMMINA_PLUGIN_DEBUG("DesktopWidth and DesktopHeight set to: %dx%d", freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth), freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight));
2090  } else {
2091  REMMINA_PLUGIN_DEBUG("Cannot set Desktop Size, we are using the previously set values: %dx%d", freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth), freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight));
2092  }
2093  remmina_plugin_service->protocol_plugin_set_width(gp, freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth));
2094  remmina_plugin_service->protocol_plugin_set_height(gp, freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight));
2095  }
2096 
2097  const gchar *sn = remmina_plugin_service->file_get_string(remminafile, "smartcardname");
2098  if (remmina_plugin_service->file_get_int(remminafile, "sharesmartcard", FALSE) ||
2099  (sn != NULL && sn[0] != '\0')) {
2100  RDPDR_SMARTCARD *smartcard;
2101  smartcard = (RDPDR_SMARTCARD *)calloc(1, sizeof(RDPDR_SMARTCARD));
2102 
2103 #ifdef WITH_FREERDP3
2104  RDPDR_DEVICE *sdev;
2105  sdev = &(smartcard->device);
2106 #else
2107  RDPDR_SMARTCARD *sdev;
2108  sdev = smartcard;
2109 #endif
2110 
2111  sdev->Type = RDPDR_DTYP_SMARTCARD;
2112 
2113  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
2114 
2115  if (sn != NULL && sn[0] != '\0')
2116  sdev->Name = _strdup(sn);
2117 
2118  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectSmartCards, TRUE);
2119 
2120  freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)smartcard);
2121  }
2122 
2123  if (remmina_plugin_service->file_get_int(remminafile, "passwordispin", FALSE))
2124  /* Option works only combined with Username and Domain, because FreeRDP
2125  * doesn’t know anything about info on smart card */
2126  freerdp_settings_set_bool(rfi->settings, FreeRDP_PasswordIsSmartcardPin, TRUE);
2127 
2128  /* /serial[:<name>[,<path>[,<driver>[,permissive]]]] */
2129  if (remmina_plugin_service->file_get_int(remminafile, "shareserial", FALSE)) {
2130  RDPDR_SERIAL *serial;
2131  serial = (RDPDR_SERIAL *)calloc(1, sizeof(RDPDR_SERIAL));
2132 
2133 #ifdef WITH_FREERDP3
2134  RDPDR_DEVICE *sdev;
2135  sdev = &(serial->device);
2136 #else
2137  RDPDR_SERIAL *sdev;
2138  sdev = serial;
2139 #endif
2140 
2141  sdev->Type = RDPDR_DTYP_SERIAL;
2142 
2143  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
2144 
2145  const gchar *sn = remmina_plugin_service->file_get_string(remminafile, "serialname");
2146  if (sn != NULL && sn[0] != '\0')
2147  sdev->Name = _strdup(sn);
2148 
2149  const gchar *sd = remmina_plugin_service->file_get_string(remminafile, "serialdriver");
2150  if (sd != NULL && sd[0] != '\0')
2151  serial->Driver = _strdup(sd);
2152 
2153  const gchar *sp = remmina_plugin_service->file_get_string(remminafile, "serialpath");
2154  if (sp != NULL && sp[0] != '\0')
2155  serial->Path = _strdup(sp);
2156 
2157  if (remmina_plugin_service->file_get_int(remminafile, "serialpermissive", FALSE))
2158  serial->Permissive = _strdup("permissive");
2159 
2160  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectSerialPorts, TRUE);
2161 
2162  freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)serial);
2163  }
2164 
2165  if (remmina_plugin_service->file_get_int(remminafile, "shareparallel", FALSE)) {
2166  RDPDR_PARALLEL *parallel;
2167  parallel = (RDPDR_PARALLEL *)calloc(1, sizeof(RDPDR_PARALLEL));
2168 
2169 #ifdef WITH_FREERDP3
2170  RDPDR_DEVICE *pdev;
2171  pdev = &(parallel->device);
2172 #else
2173  RDPDR_PARALLEL *pdev;
2174  pdev = parallel;
2175 #endif
2176 
2177  pdev->Type = RDPDR_DTYP_PARALLEL;
2178 
2179  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
2180 
2181  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectParallelPorts, TRUE);
2182 
2183  const gchar *pn = remmina_plugin_service->file_get_string(remminafile, "parallelname");
2184  if (pn != NULL && pn[0] != '\0')
2185  pdev->Name = _strdup(pn);
2186  const gchar *dp = remmina_plugin_service->file_get_string(remminafile, "parallelpath");
2187  if (dp != NULL && dp[0] != '\0')
2188  parallel->Path = _strdup(dp);
2189 
2190  freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)parallel);
2191  }
2192 
2196  if (remmina_plugin_service->file_get_int(remminafile, "multitransport", FALSE)) {
2197  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
2198  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportMultitransport, TRUE);
2199  freerdp_settings_set_uint32(rfi->settings, FreeRDP_MultitransportFlags,
2200  (TRANSPORT_TYPE_UDP_FECR | TRANSPORT_TYPE_UDP_FECL | TRANSPORT_TYPE_UDP_PREFERRED));
2201  } else {
2202  freerdp_settings_set_uint32(rfi->settings, FreeRDP_MultitransportFlags, 0);
2203  }
2204 
2205  /* If needed, force interactive authentication by deleting all authentication fields,
2206  * forcing libfreerdp to call our callbacks for authentication.
2207  * This usually happens from a second attempt of connection, never on the 1st one. */
2209  freerdp_settings_set_string(rfi->settings, FreeRDP_Username, NULL);
2210  freerdp_settings_set_string(rfi->settings, FreeRDP_Password, NULL);
2211  freerdp_settings_set_string(rfi->settings, FreeRDP_Domain, NULL);
2212 
2213  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayDomain, NULL);
2214  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayUsername, NULL);
2215  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayPassword, NULL);
2216 
2217  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, FALSE);
2218  }
2219 
2220  gboolean orphaned;
2221 
2222  if (!freerdp_connect(rfi->instance)) {
2223  orphaned = (GET_PLUGIN_DATA(rfi->protocol_widget) == NULL);
2224  if (!orphaned) {
2225  UINT32 e;
2226 
2227  e = freerdp_get_last_error(rfi->instance->context);
2228 
2229  switch (e) {
2230  case FREERDP_ERROR_AUTHENTICATION_FAILED:
2231  case STATUS_LOGON_FAILURE: // wrong return code from FreeRDP introduced at the end of July 2016? (fixed with b86c0ba)
2232 #ifdef FREERDP_ERROR_CONNECT_LOGON_FAILURE
2233  case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
2234 #endif
2235  /* Logon failure, will retry with interactive authentication */
2237  break;
2238  case STATUS_ACCOUNT_LOCKED_OUT:
2239 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT
2240  case FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT:
2241 #endif
2242  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nAccount locked out."),
2243  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2244  break;
2245  case STATUS_ACCOUNT_EXPIRED:
2246 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED
2247  case FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED:
2248 #endif
2249  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nAccount expired."),
2250  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2251  break;
2252  case STATUS_PASSWORD_EXPIRED:
2253 #ifdef FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED
2254  case FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED:
2255 #endif
2256  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nPassword expired."),
2257  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2258  break;
2259  case STATUS_ACCOUNT_DISABLED:
2260 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED
2261  case FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED:
2262 #endif
2263  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nAccount disabled."),
2264  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2265  break;
2266 #ifdef FREERDP_ERROR_SERVER_INSUFFICIENT_PRIVILEGES
2267  /* https://msdn.microsoft.com/en-us/library/ee392247.aspx */
2268  case FREERDP_ERROR_SERVER_INSUFFICIENT_PRIVILEGES:
2269  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nInsufficient user privileges."),
2270  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2271  break;
2272 #endif
2273  case STATUS_ACCOUNT_RESTRICTION:
2274 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION
2275  case FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION:
2276 #endif
2277  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nAccount restricted."),
2278  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2279  break;
2280 
2281  case STATUS_PASSWORD_MUST_CHANGE:
2282 #ifdef FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE
2283  case FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE:
2284 #endif
2285  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nChange user password before connecting."),
2286  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2287  break;
2288 
2289  case FREERDP_ERROR_CONNECT_FAILED:
2290  remmina_plugin_service->protocol_plugin_set_error(gp, _("Lost connection to the RDP server “%s”."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2291  break;
2292  case FREERDP_ERROR_DNS_NAME_NOT_FOUND:
2293  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not find the address for the RDP server “%s”."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2294  break;
2295  case FREERDP_ERROR_TLS_CONNECT_FAILED:
2296  remmina_plugin_service->protocol_plugin_set_error(gp,
2297  _("Could not connect to the RDP server “%s” via TLS. See the DEBUG traces from a terminal for more information."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2298  break;
2299  case FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED:
2300  // TRANSLATORS: the placeholder may be either an IP/FQDN or a server hostname
2301  remmina_plugin_service->protocol_plugin_set_error(gp, _("Unable to establish a connection to the RDP server “%s”. Check “Security protocol negotiation”."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2302  break;
2303 #ifdef FREERDP_ERROR_POST_CONNECT_FAILED
2304  case FREERDP_ERROR_POST_CONNECT_FAILED:
2305  /* remmina_rdp_post_connect() returned FALSE to libfreerdp. We saved the error on rfi->postconnect_error */
2306  switch (rfi->postconnect_error) {
2307  case REMMINA_POSTCONNECT_ERROR_OK:
2308  /* We should never come here */
2309  remmina_plugin_service->protocol_plugin_set_error(gp, _("Cannot connect to the RDP server “%s”."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2310  break;
2311  case REMMINA_POSTCONNECT_ERROR_GDI_INIT:
2312  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not start libfreerdp-gdi."));
2313  break;
2314  case REMMINA_POSTCONNECT_ERROR_NO_H264:
2315  remmina_plugin_service->protocol_plugin_set_error(gp, _("You requested a H.264 GFX mode for the server “%s”, but your libfreerdp does not support H.264. Please use a non-AVC colour depth setting."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2316  break;
2317  }
2318  break;
2319 #endif
2320 #ifdef FREERDP_ERROR_SERVER_DENIED_CONNECTION
2321  case FREERDP_ERROR_SERVER_DENIED_CONNECTION:
2322  remmina_plugin_service->protocol_plugin_set_error(gp, _("The “%s” server refused the connection."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2323  break;
2324 #endif
2325  case 0x800759DB:
2326  // E_PROXY_NAP_ACCESSDENIED https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tsgu/84cd92e4-592c-4219-95d8-18021ac654b0
2327  remmina_plugin_service->protocol_plugin_set_error(gp, _("The Remote Desktop Gateway “%s” denied the user “%s\\%s” access due to policy."),
2328  freerdp_settings_get_string(rfi->settings, FreeRDP_GatewayHostname), freerdp_settings_get_string(rfi->settings, FreeRDP_GatewayDomain), freerdp_settings_get_string(rfi->settings, FreeRDP_GatewayUsername));
2329  break;
2330 
2331  case FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS:
2332  rfi->user_cancelled = TRUE;
2333  break;
2334 
2335  default:
2336  g_printf("libfreerdp returned code is %08X\n", e);
2337  remmina_plugin_service->protocol_plugin_set_error(gp, _("Cannot connect to the “%s” RDP server."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2338  break;
2339  }
2340  }
2341 
2342  return FALSE;
2343  }
2344 
2345  if (GET_PLUGIN_DATA(rfi->protocol_widget) == NULL) orphaned = true; else orphaned = false;
2346  if (!orphaned && freerdp_get_last_error(rfi->instance->context) == FREERDP_ERROR_SUCCESS && !rfi->user_cancelled)
2348 
2349  return TRUE;
2350 }
2351 
2352 static void rfi_uninit(rfContext *rfi)
2353 {
2354  freerdp *instance;
2355 
2356  instance = rfi->instance;
2357 
2358  if (rfi->remmina_plugin_thread) {
2359  rfi->thread_cancelled = TRUE; // Avoid all rf_queue function to run
2360  pthread_cancel(rfi->remmina_plugin_thread);
2361  if (rfi->remmina_plugin_thread)
2362  pthread_join(rfi->remmina_plugin_thread, NULL);
2363  }
2364 
2365  if (instance) {
2366  if (rfi->connected) {
2367  freerdp_abort_connect(instance);
2368  rfi->connected = false;
2369  }
2370  }
2371 
2372  if (instance) {
2373  RDP_CLIENT_ENTRY_POINTS *pEntryPoints = instance->pClientEntryPoints;
2374  if (pEntryPoints)
2375  IFCALL(pEntryPoints->GlobalUninit);
2376  free(instance->pClientEntryPoints);
2377  freerdp_context_free(instance); /* context is rfContext* rfi */
2378  freerdp_free(instance); /* This implicitly frees instance->context and rfi is no longer valid */
2379  }
2380 }
2381 
2382 static gboolean complete_cleanup_on_main_thread(gpointer data)
2383 {
2384  TRACE_CALL(__func__);
2385 
2386  gboolean orphaned;
2387  rfContext *rfi = (rfContext *)data;
2389 
2391 
2392  gdi_free(rfi->instance);
2393 
2394  gp = rfi->protocol_widget;
2395  if (GET_PLUGIN_DATA(gp) == NULL) orphaned = true; else orphaned = false;
2396 
2398  if (!orphaned) remmina_rdp_event_uninit(gp);
2399 
2400  if (!orphaned) g_object_steal_data(G_OBJECT(gp), "plugin-data");
2401 
2402  rfi_uninit(rfi);
2403 
2404  /* Notify the RemminaProtocolWidget that we closed our connection, and the GUI interface
2405  * can be removed */
2406  if (!orphaned)
2407  remmina_plugin_service->protocol_plugin_signal_connection_closed(gp);
2408 
2409  return G_SOURCE_REMOVE;
2410 }
2411 
2412 static gpointer remmina_rdp_main_thread(gpointer data)
2413 {
2414  TRACE_CALL(__func__);
2416  rfContext *rfi;
2417 
2418  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
2419  CANCEL_ASYNC
2420 
2421  gp = (RemminaProtocolWidget *)data;
2422 
2423  rfi = GET_PLUGIN_DATA(gp);
2424 
2426  do
2427  remmina_rdp_main(gp);
2428  while (!remmina_plugin_service->protocol_plugin_has_error(gp) && rfi->attempt_interactive_authentication == TRUE && !rfi->user_cancelled);
2429 
2430  rfi->remmina_plugin_thread = 0;
2431 
2432  /* cleanup */
2433  g_idle_add(complete_cleanup_on_main_thread, (gpointer)rfi);
2434 
2435 
2436  return NULL;
2437 }
2438 
2440 {
2441  TRACE_CALL(__func__);
2442  freerdp *instance;
2443  rfContext *rfi;
2444 
2445  instance = freerdp_new();
2446  instance->PreConnect = remmina_rdp_pre_connect;
2447  instance->PostConnect = remmina_rdp_post_connect;
2448  instance->PostDisconnect = remmina_rdp_post_disconnect;
2449  instance->Authenticate = remmina_rdp_authenticate;
2450  instance->GatewayAuthenticate = remmina_rdp_gw_authenticate;
2451  //instance->VerifyCertificate = remmina_rdp_verify_certificate;
2452  instance->VerifyCertificateEx = remmina_rdp_verify_certificate_ex;
2453  //instance->VerifyChangedCertificate = remmina_rdp_verify_changed_certificate;
2454  instance->VerifyChangedCertificateEx = remmina_rdp_verify_changed_certificate_ex;
2455 
2456  instance->ContextSize = sizeof(rfContext);
2457  freerdp_context_new(instance);
2458  rfi = (rfContext *)instance->context;
2459 
2460  g_object_set_data_full(G_OBJECT(gp), "plugin-data", rfi, free);
2461 
2462  rfi->protocol_widget = gp;
2463  rfi->instance = instance;
2464  rfi->settings = instance->settings;
2465  rfi->connected = false;
2466  rfi->is_reconnecting = false;
2467  rfi->stop_reconnecting_requested = false;
2468  rfi->user_cancelled = FALSE;
2469 
2470  freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0);
2471 
2473 }
2474 
2476 {
2477  TRACE_CALL(__func__);
2478  rfContext *rfi = GET_PLUGIN_DATA(gp);
2479  RemminaFile *remminafile;
2480  const gchar *profile_name, *p;
2481  gchar thname[16], c;
2482  gint nthname = 0;
2483 
2484  rfi->scale = remmina_plugin_service->remmina_protocol_widget_get_current_scale_mode(gp);
2485 
2486  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
2487 
2488 
2489  if (pthread_create(&rfi->remmina_plugin_thread, NULL, remmina_rdp_main_thread, gp)) {
2490  remmina_plugin_service->protocol_plugin_set_error(gp, "%s",
2491  "Could not start pthread.");
2492 
2493  rfi->remmina_plugin_thread = 0;
2494 
2495  return FALSE;
2496  }
2497 
2498  /* Generate a thread name to be used with pthread_setname_np() for debugging */
2499  profile_name = remmina_plugin_service->file_get_string(remminafile, "name");
2500  p = profile_name;
2501  strcpy(thname, "RemmRDP:");
2502  if (p) {
2503  nthname = strlen(thname);
2504  while ((c = *p) != 0 && nthname < sizeof(thname) - 1) {
2505  if (isalnum(c))
2506  thname[nthname++] = c;
2507  p++;
2508  }
2509  } else {
2510  strcat(thname, "<NONAM>");
2511  nthname = strlen(thname);
2512  }
2513  thname[nthname] = 0;
2514 #if defined(__linux__)
2515  pthread_setname_np(rfi->remmina_plugin_thread, thname);
2516 #elif defined(__FreeBSD__)
2517  pthread_set_name_np(rfi->remmina_plugin_thread, thname);
2518 #endif
2519 
2520  return TRUE;
2521 }
2522 
2524 {
2525  TRACE_CALL(__func__);
2526 
2527  REMMINA_PLUGIN_DEBUG("Requesting to close the connection");
2528  RemminaPluginRdpEvent rdp_event = { 0 };
2529  rfContext *rfi = GET_PLUGIN_DATA(gp);
2530 
2531  if (!remmina_plugin_service->is_main_thread())
2532  g_warning("WARNING: %s called on a subthread, which may not work or crash Remmina.", __func__);
2533 
2534  if (rfi && !rfi->connected) {
2535  /* libfreerdp is attempting to connect, we cannot interrupt our main thread
2536  * in the connect phase.
2537  * So we remove "plugin-data" from gp, so our rfi remains "orphan"
2538  */
2540  g_object_steal_data(G_OBJECT(gp), "plugin-data");
2541  remmina_plugin_service->protocol_plugin_signal_connection_closed(gp);
2542  return FALSE;
2543  }
2544 
2545 
2546  if (rfi && rfi->clipboard.srv_clip_data_wait == SCDW_BUSY_WAIT) {
2547  REMMINA_PLUGIN_DEBUG("[RDP] requesting clipboard transfer to abort");
2548  /* Allow clipboard transfer from server to terminate */
2549  rfi->clipboard.srv_clip_data_wait = SCDW_ABORTING;
2550  usleep(100000);
2551  }
2552 
2553  if (rfi->is_reconnecting) {
2554  /* Special case: window closed when attempting to reconnect */
2555  rfi->stop_reconnecting_requested = TRUE;
2556  return FALSE;
2557  }
2558 
2559  rdp_event.type = REMMINA_RDP_EVENT_DISCONNECT;
2560  remmina_rdp_event_event_push(gp, &rdp_event);
2561 
2562  return FALSE;
2563 }
2564 
2566 {
2567  TRACE_CALL(__func__);
2568  return TRUE;
2569 }
2570 
2572 {
2573  TRACE_CALL(__func__);
2574  rfContext *rfi = GET_PLUGIN_DATA(gp);
2575 
2576  switch (feature->id) {
2577  case REMMINA_RDP_FEATURE_UNFOCUS:
2579  break;
2580 
2581  case REMMINA_RDP_FEATURE_SCALE:
2582  if (rfi) {
2583  rfi->scale = remmina_plugin_service->remmina_protocol_widget_get_current_scale_mode(gp);
2585  } else {
2586  REMMINA_PLUGIN_DEBUG("Remmina RDP plugin warning: Null value for rfi by REMMINA_RDP_FEATURE_SCALE");
2587  }
2588  break;
2589 
2590  case REMMINA_RDP_FEATURE_MULTIMON:
2591  if (rfi) {
2592  RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
2593  if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) {
2594  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseMultimon, TRUE);
2595  /* TODO Add an option for this */
2596  freerdp_settings_set_bool(rfi->settings, FreeRDP_ForceMultimon, TRUE);
2597  freerdp_settings_set_bool(rfi->settings, FreeRDP_Fullscreen, TRUE);
2599  }
2600  } else {
2601  REMMINA_PLUGIN_DEBUG("Remmina RDP plugin warning: Null value for rfi by REMMINA_RDP_FEATURE_MULTIMON");
2602  }
2603  break;
2604 
2605  case REMMINA_RDP_FEATURE_DYNRESUPDATE:
2606  break;
2607 
2608  case REMMINA_RDP_FEATURE_TOOL_REFRESH:
2609  if (rfi)
2610  gtk_widget_queue_draw_area(rfi->drawing_area, 0, 0,
2611  remmina_plugin_service->protocol_plugin_get_width(gp),
2612  remmina_plugin_service->protocol_plugin_get_height(gp));
2613  else
2614  REMMINA_PLUGIN_DEBUG("Remmina RDP plugin warning: Null value for rfi by REMMINA_RDP_FEATURE_TOOL_REFRESH");
2615  break;
2616 
2617  case REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL:
2619  break;
2620 
2621  default:
2622  break;
2623  }
2624 }
2625 
2626 /* Send a keystroke to the plugin window */
2627 static void remmina_rdp_keystroke(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
2628 {
2629  TRACE_CALL(__func__);
2630  rfContext *rfi = GET_PLUGIN_DATA(gp);
2631 
2632  remmina_plugin_service->protocol_plugin_send_keys_signals(rfi->drawing_area,
2633  keystrokes, keylen, GDK_KEY_PRESS | GDK_KEY_RELEASE);
2634  return;
2635 }
2636 
2638 {
2639  rfContext *rfi = GET_PLUGIN_DATA(gp);
2640  rdpGdi *gdi;
2641  size_t szmem;
2642 
2643  UINT32 bytesPerPixel;
2644  UINT32 bitsPerPixel;
2645 
2646  if (!rfi)
2647  return FALSE;
2648 
2649  gdi = ((rdpContext *)rfi)->gdi;
2650 
2651  bytesPerPixel = GetBytesPerPixel(gdi->hdc->format);
2652  bitsPerPixel = GetBitsPerPixel(gdi->hdc->format);
2653 
2657  szmem = gdi->width * gdi->height * bytesPerPixel;
2658 
2659  REMMINA_PLUGIN_DEBUG("allocating %zu bytes for a full screenshot", szmem);
2660  rpsd->buffer = malloc(szmem);
2661  if (!rpsd->buffer) {
2662  REMMINA_PLUGIN_DEBUG("could not set aside %zu bytes for a full screenshot", szmem);
2663  return FALSE;
2664  }
2665  rpsd->width = gdi->width;
2666  rpsd->height = gdi->height;
2667  rpsd->bitsPerPixel = bitsPerPixel;
2668  rpsd->bytesPerPixel = bytesPerPixel;
2669 
2670  memcpy(rpsd->buffer, gdi->primary_buffer, szmem);
2671 
2672  /* Returning TRUE instruct also the caller to deallocate rpsd->buffer */
2673  return TRUE;
2674 }
2675 
2676 /* Array of key/value pairs for colour depths */
2677 static gpointer colordepth_list[] =
2678 {
2679  /* 1st one is the default in a new install */
2680  "99", N_("Automatic (32 bpp) (Server chooses its best format)"),
2681  "66", N_("GFX AVC444 (32 bpp)"),
2682  "65", N_("GFX AVC420 (32 bpp)"),
2683  "64", N_("GFX RFX (32 bpp)"),
2684  "63", N_("GFX RFX Progressive (32 bpp)"),
2685  "0", N_("RemoteFX (32 bpp)"),
2686  "32", N_("True colour (32 bpp)"),
2687  "24", N_("True colour (24 bpp)"),
2688  "16", N_("High colour (16 bpp)"),
2689  "15", N_("High colour (15 bpp)"),
2690  "8", N_("256 colours (8 bpp)"),
2691  NULL
2692 };
2693 
2694 /* Array of key/value pairs for the FreeRDP logging level */
2695 static gpointer log_level[] =
2696 {
2697  "INFO", "INFO",
2698  "FATAL", "FATAL",
2699  "ERROR", "ERROR",
2700  "WARN", "WARN",
2701  "DEBUG", "DEBUG",
2702  "TRACE", "TRACE",
2703  "OFF", "OFF",
2704  NULL
2705 };
2706 
2707 
2708 /* Array of key/value pairs for quality selection */
2709 static gpointer quality_list[] =
2710 {
2711  "0", N_("Poor (fastest)"),
2712  "1", N_("Medium"),
2713  "2", N_("Good"),
2714  "9", N_("Best (slowest)"),
2715  NULL
2716 };
2717 
2718 /* Array of key/value pairs for quality selection */
2719 static gpointer network_list[] =
2720 {
2721  "none", N_("None"),
2722  "autodetect", N_("Auto-detect"),
2723  "modem", N_("Modem"),
2724  "broadband-low", N_("Low performance broadband"),
2725  "satellite", N_("Satellite"),
2726  "broadband-high", N_("High performance broadband"),
2727  "wan", N_("WAN"),
2728  "lan", N_("LAN"),
2729  NULL
2730 };
2731 
2732 /* Array of key/value pairs for sound options */
2733 static gpointer sound_list[] =
2734 {
2735  "off", N_("Off"),
2736  "local", N_("Local"),
2737  "remote", N_("Remote"),
2738  NULL
2739 };
2740 
2741 /* Array of key/value pairs for security */
2742 static gpointer security_list[] =
2743 {
2744  "", N_("Automatic negotiation"),
2745  "nla", N_("NLA protocol security"),
2746  "tls", N_("TLS protocol security"),
2747  "rdp", N_("RDP protocol security"),
2748  "ext", N_("NLA extended protocol security"),
2749  NULL
2750 };
2751 
2752 /* Array of key/value pairs for mouse movement */
2753 static gpointer mouse_jitter_list[] =
2754 {
2755  "No", N_("No"),
2756  "60", N_("Every 1 min"),
2757  "180", N_("Every 3 min"),
2758  "300", N_("Every 5 min"),
2759  "600", N_("Every 10 min"),
2760  NULL
2761 };
2762 
2763 static gpointer gwtransp_list[] =
2764 {
2765  "http", "HTTP",
2766  "rpc", "RPC",
2767  "auto", "Auto",
2768  NULL
2769 };
2770 
2771 static gpointer tls_seclevel[] =
2772 {
2773  "", N_("Default"),
2774  "0", N_("0 — Windows 7 compatible"),
2775  "1", N_("1"),
2776  "2", N_("2"),
2777  "3", N_("3"),
2778  "4", N_("4"),
2779  "5", N_("5"),
2780  NULL
2781 };
2782 
2783 static gchar clientbuild_list[] =
2784  N_("2600 (Windows XP), 7601 (Windows Vista/7), 9600 (Windows 8 and newer)");
2785 
2786 static gchar clientbuild_tooltip[] =
2787  N_("Used i.a. by terminal services in a smart card channel to distinguish client capabilities:\n"
2788  " • < 4034: Windows XP base smart card functions\n"
2789  " • 4034-7064: Windows Vista/7: SCardReadCache(),\n"
2790  " SCardWriteCache(), SCardGetTransmitCount()\n"
2791  " • >= 7065: Windows 8 and newer: SCardGetReaderIcon(),\n"
2792  " SCardGetDeviceTypeId()");
2793 
2794 static gchar microphone_tooltip[] =
2795  N_("Options for redirection of audio input:\n"
2796  " • [sys:<sys>,][dev:<dev>,][format:<format>,][rate:<rate>,]\n"
2797  " [channel:<channel>] Audio input (microphone)\n"
2798  " • sys:pulse\n"
2799  " • format:1\n"
2800  " • sys:oss,dev:1,format:1\n"
2801  " • sys:alsa");
2802 
2803 static gchar audio_tooltip[] =
2804  N_("Options for redirection of audio output:\n"
2805  " • [sys:<sys>,][dev:<dev>,][format:<format>,][rate:<rate>,]\n"
2806  " [channel:<channel>] Audio output\n"
2807  " • sys:pulse\n"
2808  " • format:1\n"
2809  " • sys:oss,dev:1,format:1\n"
2810  " • sys:alsa");
2811 
2812 
2813 static gchar usb_tooltip[] =
2814  N_("Options for redirection of USB device:\n"
2815  " • [dbg,][id:<vid>:<pid>#…,][addr:<bus>:<addr>#…,][auto]\n"
2816  " • auto\n"
2817  " • id:054c:0268#4669:6e6b,addr:04:0c");
2818 
2819 static gchar timeout_tooltip[] =
2820  N_("Advanced setting for high latency links:\n"
2821  "Adjusts the connection timeout. Use if your connection times out.\n"
2822  "The highest possible value is 600000 ms (10 minutes).\n");
2823 
2824 static gchar network_tooltip[] =
2825  N_("Performance optimisations based on the network connection type:\n"
2826  "Using auto-detection is advised.\n"
2827  "If “Auto-detect” fails, choose the most appropriate option in the list.\n");
2828 
2829 static gchar monitorids_tooltip[] =
2830  N_("Comma-separated list of monitor IDs and desktop orientations:\n"
2831  " • [<id>:<orientation-in-degrees>,]\n"
2832  " • 0,1,2,3\n"
2833  " • 0:270,1:90\n"
2834  "Orientations are specified in degrees, valid values are:\n"
2835  " • 0 (landscape)\n"
2836  " • 90 (portrait)\n"
2837  " • 180 (landscape flipped)\n"
2838  " • 270 (portrait flipped)\n"
2839  "\n");
2840 
2841 static gchar drive_tooltip[] =
2842  N_("Redirect directory <path> as named share <name>.\n"
2843  " • <name>,<fullpath>[;<name>,<fullpath>[;…]]\n"
2844  " • MyHome,/home/remminer\n"
2845  " • /home/remminer\n"
2846  " • MyHome,/home/remminer;SomePath,/path/to/somepath\n"
2847  "Hotplug support is enabled with:\n"
2848  " • hotplug,*\n"
2849  "\n");
2850 
2851 /* Array of RemminaProtocolSetting for basic settings.
2852  * Each item is composed by:
2853  * a) RemminaProtocolSettingType for setting type
2854  * b) Setting name
2855  * c) Setting description
2856  * d) Compact disposition
2857  * e) Values for REMMINA_PROTOCOL_SETTING_TYPE_SELECT or REMMINA_PROTOCOL_SETTING_TYPE_COMBO
2858  * f) Setting tooltip
2859  * g) Validation data pointer, will be passed to the validation callback method.
2860  * h) Validation callback method (Can be NULL. Every entry will be valid then.)
2861  * use following prototype:
2862  * gboolean mysetting_validator_method(gpointer key, gpointer value,
2863  * gpointer validator_data);
2864  * gpointer key is a gchar* containing the setting's name,
2865  * gpointer value contains the value which should be validated,
2866  * gpointer validator_data contains your passed data.
2867  */
2869 {
2870  { REMMINA_PROTOCOL_SETTING_TYPE_SERVER, "server", NULL, FALSE, NULL, NULL, NULL, NULL },
2871  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "username", N_("Username"), FALSE, NULL, NULL, NULL, NULL },
2872  { REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD, "password", N_("Password"), FALSE, NULL, NULL, NULL, NULL },
2873  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "domain", N_("Domain"), FALSE, NULL, NULL, NULL, NULL },
2874  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "drive", N_("Share folder"), FALSE, NULL, drive_tooltip, NULL, NULL },
2875  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "restricted-admin", N_("Restricted admin mode"), FALSE, NULL, NULL, NULL, NULL },
2876  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "pth", N_("Password hash"), FALSE, NULL, N_("Restricted admin mode password hash"), NULL, NULL },
2877  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "left-handed", N_("Left-handed mouse support"), TRUE, NULL, N_("Swap left and right mouse buttons for left-handed mouse support"), NULL, NULL },
2878  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disable-smooth-scrolling", N_("Disable smooth scrolling"), TRUE, NULL, NULL, NULL, NULL },
2879  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "multimon", N_("Enable multi monitor"), TRUE, NULL, NULL, NULL, NULL },
2880  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "span", N_("Span screen over multiple monitors"), TRUE, NULL, NULL, NULL, NULL },
2881  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "monitorids", N_("List monitor IDs"), FALSE, NULL, monitorids_tooltip, NULL, NULL },
2882  { REMMINA_PROTOCOL_SETTING_TYPE_RESOLUTION, "resolution", NULL, FALSE, NULL, NULL, NULL, NULL },
2883  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "colordepth", N_("Colour depth"), FALSE, colordepth_list, NULL, NULL, NULL },
2884  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "network", N_("Network connection type"), FALSE, network_list, network_tooltip, NULL, NULL },
2885  { REMMINA_PROTOCOL_SETTING_TYPE_KEYMAP, "keymap", NULL, FALSE, NULL, NULL, NULL, NULL },
2886  { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL, NULL, NULL }
2887 };
2888 
2889 /* Array of RemminaProtocolSetting for advanced settings.
2890  * Each item is composed by:
2891  * a) RemminaProtocolSettingType for setting type
2892  * b) Setting name
2893  * c) Setting description
2894  * d) Compact disposition
2895  * e) Values for REMMINA_PROTOCOL_SETTING_TYPE_SELECT or REMMINA_PROTOCOL_SETTING_TYPE_COMBO
2896  * f) Setting Tooltip
2897  */
2899 {
2900  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "quality", N_("Quality"), FALSE, quality_list, NULL },
2901  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "security", N_("Security protocol negotiation"), FALSE, security_list, NULL },
2902  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "gwtransp", N_("Gateway transport type"), FALSE, gwtransp_list, NULL },
2903  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "tls-seclevel", N_("TLS Security Level"), FALSE, tls_seclevel, NULL },
2904  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "freerdp_log_level", N_("FreeRDP log level"), FALSE, log_level, NULL },
2905  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "freerdp_log_filters", N_("FreeRDP log filters"), FALSE, NULL, N_("tag:level[,tag:level[,…]]") },
2906  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "sound", N_("Audio output mode"), FALSE, sound_list, NULL },
2907  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "audio-output", N_("Redirect local audio output"), TRUE, NULL, audio_tooltip },
2908  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "microphone", N_("Redirect local microphone"), TRUE, NULL, microphone_tooltip },
2909  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "timeout", N_("Connection timeout in ms"), TRUE, NULL, timeout_tooltip },
2910  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "gateway_server", N_("Remote Desktop Gateway server"), FALSE, NULL, NULL },
2911  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "gateway_username", N_("Remote Desktop Gateway username"), FALSE, NULL, NULL },
2912  { REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD, "gateway_password", N_("Remote Desktop Gateway password"), FALSE, NULL, NULL },
2913  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "gateway_domain", N_("Remote Desktop Gateway domain"), FALSE, NULL, NULL },
2914  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "clientname", N_("Client name"), FALSE, NULL, NULL },
2915  { REMMINA_PROTOCOL_SETTING_TYPE_COMBO, "clientbuild", N_("Client build"), FALSE, clientbuild_list, clientbuild_tooltip },
2916  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "exec", N_("Start-up program"), FALSE, NULL, NULL },
2917  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "execpath", N_("Start-up path"), FALSE, NULL, NULL },
2918  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "loadbalanceinfo", N_("Load balance info"), FALSE, NULL, NULL },
2919  // TRANSLATORS: Do not use typographic quotation marks, these must stay as "double quote", also know as “Typewriter ("programmer's") quote, ambidextrous.”
2920  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "printer_overrides", N_("Override printer drivers"), FALSE, NULL, N_("\"Samsung_CLX-3300_Series\":\"Samsung CLX-3300 Series PS\";\"Canon MF410\":\"Canon MF410 Series UFR II\"") },
2921  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "usb", N_("USB device redirection"), TRUE, NULL, usb_tooltip },
2922  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "serialname", N_("Local serial name"), FALSE, NULL, N_("COM1, COM2, etc.") },
2923  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "serialdriver", N_("Local serial driver"), FALSE, NULL, N_("Serial") },
2924  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "serialpath", N_("Local serial path"), FALSE, NULL, N_("/dev/ttyS0, /dev/ttyS1, etc.") },
2925  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "parallelname", N_("Local parallel name"), FALSE, NULL, NULL },
2926  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "parallelpath", N_("Local parallel device"), FALSE, NULL, NULL },
2927  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "smartcardname", N_("Name of smart card"), FALSE, NULL, NULL },
2928  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "dvc", N_("Dynamic virtual channel"), FALSE, NULL, N_("<channel>[,<options>]") },
2929  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "vc", N_("Static virtual channel"), FALSE, NULL, N_("<channel>[,<options>]") },
2930  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "rdp2tcp", N_("TCP redirection"), FALSE, NULL, N_("/PATH/TO/rdp2tcp") },
2931  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "rdp_reconnect_attempts", N_("Reconnect attempts number"), FALSE, NULL, N_("The maximum number of reconnect attempts upon an RDP disconnect (default: 20)") },
2932  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "rdp_mouse_jitter", N_("Move mouse when connection is idle"), FALSE, mouse_jitter_list, NULL },
2933 
2934  { REMMINA_PROTOCOL_SETTING_TYPE_ASSISTANCE, "assistance_mode", N_("Attempt to connect in assistance mode"), TRUE, NULL },
2935  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "preferipv6", N_("Prefer IPv6 AAAA record over IPv4 A record"), TRUE, NULL, NULL },
2936  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "shareprinter", N_("Share printers"), TRUE, NULL, NULL },
2937  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "shareserial", N_("Share serial ports"), TRUE, NULL, NULL },
2938  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "serialpermissive", N_("(SELinux) permissive mode for serial ports"), TRUE, NULL, NULL },
2939  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "shareparallel", N_("Share parallel ports"), TRUE, NULL, NULL },
2940  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "sharesmartcard", N_("Share a smart card"), TRUE, NULL, NULL },
2941  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disableclipboard", N_("Turn off clipboard sync"), TRUE, NULL, NULL },
2942  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "cert_ignore", N_("Ignore certificate"), TRUE, NULL, NULL },
2943  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "old-license", N_("Use the old license workflow"), TRUE, NULL, N_("It disables CAL and hwId is set to 0") },
2944  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disablepasswordstoring", N_("Forget passwords after use"), TRUE, NULL, NULL },
2945  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "console", N_("Attach to console (2003/2003 R2)"), TRUE, NULL, NULL },
2946  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disable_fastpath", N_("Turn off fast-path"), TRUE, NULL, NULL },
2947  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "gateway_usage", N_("Server detection using Remote Desktop Gateway"), TRUE, NULL, NULL },
2948 #if defined(PROXY_TYPE_IGNORE)
2949  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "useproxyenv", N_("Use system proxy settings"), TRUE, NULL, NULL },
2950 #endif
2951  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disableautoreconnect", N_("Turn off automatic reconnection"), TRUE, NULL, NULL },
2952  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "relax-order-checks", N_("Relax order checks"), TRUE, NULL, NULL },
2953  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "glyph-cache", N_("Glyph cache"), TRUE, NULL, NULL },
2954  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "multitransport", N_("Enable multitransport protocol (UDP)"), TRUE, NULL, N_("Using the UDP protocol may improve performance") },
2955  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "base-cred-for-gw", N_("Use base credentials for gateway too"), TRUE, NULL, NULL },
2956 #if FREERDP_CHECK_VERSION(2, 3, 1)
2957  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "websockets", N_("Enable Gateway websockets support"), TRUE, NULL, NULL },
2958 #endif
2959  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "no-suppress", N_("Update framebuffer even when not visible"), TRUE, NULL },
2960  { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL }
2961 };
2962 
2963 /* Array for available features.
2964  * The last element of the array must be REMMINA_PROTOCOL_FEATURE_TYPE_END. */
2966 {
2967  { REMMINA_PROTOCOL_FEATURE_TYPE_PREF, REMMINA_RDP_FEATURE_VIEWONLY, GINT_TO_POINTER(REMMINA_PROTOCOL_FEATURE_PREF_CHECK), "viewonly",
2968  N_("View only") },
2969  { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, REMMINA_RDP_FEATURE_TOOL_REFRESH, N_("Refresh"), NULL, NULL },
2970  { REMMINA_PROTOCOL_FEATURE_TYPE_SCALE, REMMINA_RDP_FEATURE_SCALE, NULL, NULL, NULL },
2971  { REMMINA_PROTOCOL_FEATURE_TYPE_DYNRESUPDATE, REMMINA_RDP_FEATURE_DYNRESUPDATE, NULL, NULL, NULL },
2972  { REMMINA_PROTOCOL_FEATURE_TYPE_MULTIMON, REMMINA_RDP_FEATURE_MULTIMON, NULL, NULL, NULL },
2973  { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL, N_("Send Ctrl+Alt+Delete"), NULL, NULL },
2974  { REMMINA_PROTOCOL_FEATURE_TYPE_UNFOCUS, REMMINA_RDP_FEATURE_UNFOCUS, NULL, NULL, NULL },
2975  { REMMINA_PROTOCOL_FEATURE_TYPE_END, 0, NULL, NULL, NULL }
2976 };
2977 
2978 /* This will be filled with version info string */
2980 
2981 /* Protocol plugin definition and features */
2983 {
2985  "RDP", // Name
2986  N_("RDP - Remote Desktop Protocol"), // Description
2987  GETTEXT_PACKAGE, // Translation domain
2988  remmina_plugin_rdp_version, // Version number
2989  "org.remmina.Remmina-rdp-symbolic", // Icon for normal connection
2990  "org.remmina.Remmina-rdp-ssh-symbolic", // Icon for SSH connection
2991  remmina_rdp_basic_settings, // Array for basic settings
2992  remmina_rdp_advanced_settings, // Array for advanced settings
2993  REMMINA_PROTOCOL_SSH_SETTING_TUNNEL, // SSH settings type
2994  remmina_rdp_features, // Array for available features
2995  remmina_rdp_init, // Plugin initialization
2996  remmina_rdp_open_connection, // Plugin open connection
2997  remmina_rdp_close_connection, // Plugin close connection
2998  remmina_rdp_query_feature, // Query for available features
2999  remmina_rdp_call_feature, // Call a feature
3000  remmina_rdp_keystroke, // Send a keystroke
3001  remmina_rdp_get_screenshot, // Screenshot
3002  remmina_rdp_event_on_map, // RCW map event
3003  remmina_rdp_event_on_unmap // RCW unmap event
3004 };
3005 
3006 /* File plugin definition and features */
3008 {
3009  REMMINA_PLUGIN_TYPE_FILE, // Type
3010  "RDPF", // Name
3011  N_("RDP - RDP File Handler"), // Description
3012  GETTEXT_PACKAGE, // Translation domain
3013  remmina_plugin_rdp_version, // Version number
3014  remmina_rdp_file_import_test, // Test import function
3015  remmina_rdp_file_import, // Import function
3016  remmina_rdp_file_export_test, // Test export function
3017  remmina_rdp_file_export, // Export function
3018  NULL
3019 };
3020 
3021 /* Preferences plugin definition and features */
3023 {
3024  REMMINA_PLUGIN_TYPE_PREF, // Type
3025  "RDPS", // Name
3026  N_("RDP - Preferences"), // Description
3027  GETTEXT_PACKAGE, // Translation domain
3028  remmina_plugin_rdp_version, // Version number
3029  "RDP", // Label
3030  remmina_rdp_settings_new // Preferences body function
3031 };
3032 
3033 static char *buildconfig_strstr(const char *bc, const char *option)
3034 {
3035  TRACE_CALL(__func__);
3036 
3037  char *p, *n;
3038 
3039  p = strcasestr(bc, option);
3040  if (p == NULL)
3041  return NULL;
3042 
3043  if (p > bc && *(p - 1) > ' ')
3044  return NULL;
3045 
3046  n = p + strlen(option);
3047  if (*n > ' ')
3048  return NULL;
3049 
3050  return p;
3051 }
3052 
3053 G_MODULE_EXPORT gboolean remmina_plugin_entry(RemminaPluginService *service)
3054 {
3055  int vermaj, vermin, verrev;
3056 
3057  TRACE_CALL(__func__);
3058  remmina_plugin_service = service;
3059 
3060  /* Check that we are linked to the correct version of libfreerdp */
3061 
3062  freerdp_get_version(&vermaj, &vermin, &verrev);
3063  if (vermaj < FREERDP_REQUIRED_MAJOR ||
3064  (vermaj == FREERDP_REQUIRED_MAJOR && (vermin < FREERDP_REQUIRED_MINOR ||
3065  (vermin == FREERDP_REQUIRED_MINOR && verrev < FREERDP_REQUIRED_REVISION)))) {
3066  g_printf("Upgrade your FreeRDP library version from %d.%d.%d to at least libfreerdp %d.%d.%d "
3067  "to run the RDP plugin.\n",
3068  vermaj, vermin, verrev,
3069  FREERDP_REQUIRED_MAJOR, FREERDP_REQUIRED_MINOR, FREERDP_REQUIRED_REVISION);
3070  return FALSE;
3071  }
3072 
3073  bindtextdomain(GETTEXT_PACKAGE, REMMINA_RUNTIME_LOCALEDIR);
3074  bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
3075 
3076  if (!service->register_plugin((RemminaPlugin *)&remmina_rdp))
3077  return FALSE;
3078 
3079  remmina_rdpf.export_hints = _("Export connection in Windows .rdp file format");
3080 
3081  if (!service->register_plugin((RemminaPlugin *)&remmina_rdpf))
3082  return FALSE;
3083 
3084  if (!service->register_plugin((RemminaPlugin *)&remmina_rdps))
3085  return FALSE;
3086 
3087  if (buildconfig_strstr(freerdp_get_build_config(), "WITH_GFX_H264=ON")) {
3088  gfx_h264_available = TRUE;
3089  REMMINA_PLUGIN_DEBUG("gfx_h264_available: %d", gfx_h264_available);
3090  } else {
3091  gfx_h264_available = FALSE;
3092  REMMINA_PLUGIN_DEBUG("gfx_h264_available: %d", gfx_h264_available);
3093  /* Remove values 65 and 66 from colordepth_list array by shifting it */
3094  gpointer *src, *dst;
3095  dst = src = colordepth_list;
3096  while (*src) {
3097  if (strcmp(*src, "66") != 0 && strcmp(*src, "65") != 0) {
3098  if (dst != src) {
3099  *dst = *src;
3100  *(dst + 1) = *(src + 1);
3101  }
3102  dst += 2;
3103  }
3104  src += 2;
3105  }
3106  *dst = NULL;
3107  }
3108 
3110  "RDP plugin: %s (Git %s), Compiled with libfreerdp %s (%s), Running with libfreerdp %s (rev %s), H.264 %s",
3111  VERSION, REMMINA_GIT_REVISION,
3112 #ifdef WITH_FREERDP3
3113  FREERDP_VERSION_FULL, FREERDP_GIT_REVISION,
3114 #else
3115  FREERDP_VERSION_FULL, GIT_REVISION,
3116 #endif
3117  freerdp_get_version_string(),
3118  freerdp_get_build_revision(),
3119  gfx_h264_available ? "Yes" : "No"
3120  );
3121 
3123 
3124  return TRUE;
3125 }
CliprdrClientContext * context
Definition: rdp_plugin.h:135
+Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2010-2011 Vic Lee
4  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
5  * Copyright (C) 2016-2022 Antenore Gatta, Giovanni Panozzo
6  * Copyright (C) 2022-2023 Antenore Gatta, Giovanni Panozzo, Hiroyuki Tanaka
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  * In addition, as a special exception, the copyright holders give
24  * permission to link the code of portions of this program with the
25  * OpenSSL library under certain conditions as described in each
26  * individual source file, and distribute linked combinations
27  * including the two.
28  * You must obey the GNU General Public License in all respects
29  * for all of the code used other than OpenSSL. * If you modify
30  * file(s) with this exception, you may extend this exception to your
31  * version of the file(s), but you are not obligated to do so. * If you
32  * do not wish to do so, delete this exception statement from your
33  * version. * If you delete this exception statement from all source
34  * files in the program, then also delete it here.
35  *
36  */
37 
38 
39 #define _GNU_SOURCE
40 
41 #include "remmina/plugin.h"
42 #include "rdp_plugin.h"
43 #include "rdp_event.h"
44 #include "rdp_graphics.h"
45 #include "rdp_file.h"
46 #include "rdp_settings.h"
47 #include "rdp_cliprdr.h"
48 #include "rdp_monitor.h"
49 #include "rdp_channels.h"
50 
51 #include <errno.h>
52 #include <pthread.h>
53 #include <time.h>
54 #include <sys/time.h>
55 #ifdef GDK_WINDOWING_X11
56 #include <cairo/cairo-xlib.h>
57 #else
58 #include <cairo/cairo.h>
59 #endif
60 #include <freerdp/addin.h>
61 #include <freerdp/assistance.h>
62 #include <freerdp/settings.h>
63 #include <freerdp/freerdp.h>
64 #include <freerdp/constants.h>
65 #include <freerdp/client/cliprdr.h>
66 #include <freerdp/client/channels.h>
67 #include <freerdp/client/cmdline.h>
68 #include <freerdp/error.h>
69 #include <freerdp/event.h>
70 #include <winpr/memory.h>
71 #include <winpr/cmdline.h>
72 #include <ctype.h>
73 
74 #ifdef HAVE_CUPS
75 #include <cups/cups.h>
76 #endif
77 
78 #include <unistd.h>
79 #include <string.h>
80 
81 #ifdef GDK_WINDOWING_X11
82 #include <X11/Xlib.h>
83 #include <X11/XKBlib.h>
84 #include <gdk/gdkx.h>
85 #elif defined(GDK_WINDOWING_WAYLAND)
86 #include <gdk/gdkwayland.h>
87 #endif
88 
89 #if defined(__FreeBSD__)
90 #include <pthread_np.h>
91 #endif
92 
93 #include <freerdp/locale/keyboard.h>
94 
95 #define REMMINA_RDP_FEATURE_TOOL_REFRESH 1
96 #define REMMINA_RDP_FEATURE_SCALE 2
97 #define REMMINA_RDP_FEATURE_UNFOCUS 3
98 #define REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL 4
99 #define REMMINA_RDP_FEATURE_DYNRESUPDATE 5
100 #define REMMINA_RDP_FEATURE_MULTIMON 6
101 #define REMMINA_RDP_FEATURE_VIEWONLY 7
102 
103 #define REMMINA_CONNECTION_TYPE_NONE 0
104 
105 #ifdef WITH_FREERDP3
106  #define CLPARAM const char
107 #else
108  #define CLPARAM char
109 #endif
110 
111 
113 
114 static BOOL gfx_h264_available = FALSE;
115 // keep track of last interaction time for keep alive
116 static time_t last_time;
117 
118 /* Compatibility: these functions have been introduced with https://github.com/FreeRDP/FreeRDP/commit/8c5d96784d
119  * and are missing on older FreeRDP, so we add them here.
120  * They should be removed from here after all distributed versions of FreeRDP (libwinpr) will have
121  * CommandLineParseCommaSeparatedValuesEx() onboard.
122  *
123  * (C) Copyright goes to the FreeRDP authors.
124  */
125 static CLPARAM **remmina_rdp_CommandLineParseCommaSeparatedValuesEx(const char *name, const char *list, size_t *count)
126 {
127  TRACE_CALL(__func__);
128 #if FREERDP_CHECK_VERSION(2, 0, 0)
129  return (CLPARAM **)CommandLineParseCommaSeparatedValuesEx(name, list, count);
130 #else
131  char **p;
132  char *str;
133  size_t nArgs;
134  size_t index;
135  size_t nCommas;
136  size_t prefix, len;
137 
138  nCommas = 0;
139 
140  if (count == NULL)
141  return NULL;
142 
143  *count = 0;
144 
145  if (!list) {
146  if (name) {
147  size_t len = strlen(name);
148  p = (char **)calloc(2UL + len, sizeof(char *));
149 
150  if (p) {
151  char *dst = (char *)&p[1];
152  p[0] = dst;
153  sprintf_s(dst, len + 1, "%s", name);
154  *count = 1;
155  return p;
156  }
157  }
158 
159  return NULL;
160  }
161 
162  {
163  const char *it = list;
164 
165  while ((it = strchr(it, ',')) != NULL) {
166  it++;
167  nCommas++;
168  }
169  }
170 
171  nArgs = nCommas + 1;
172 
173  if (name)
174  nArgs++;
175 
176  prefix = (nArgs + 1UL) * sizeof(char *);
177  len = strlen(list);
178  p = (char **)calloc(len + prefix + 1, sizeof(char *));
179 
180  if (!p)
181  return NULL;
182 
183  str = &((char *)p)[prefix];
184  memcpy(str, list, len);
185 
186  if (name)
187  p[0] = (char *)name;
188 
189  for (index = name ? 1 : 0; index < nArgs; index++) {
190  char *comma = strchr(str, ',');
191  p[index] = str;
192 
193  if (comma) {
194  str = comma + 1;
195  *comma = '\0';
196  }
197  }
198 
199  *count = nArgs;
200  return p;
201 #endif
202 }
203 
204 static CLPARAM **remmina_rdp_CommandLineParseCommaSeparatedValues(const char *list, size_t *count)
205 {
206  TRACE_CALL(__func__);
207  return remmina_rdp_CommandLineParseCommaSeparatedValuesEx(NULL, list, count);
208 }
209 
210 /*
211  * End of CommandLineParseCommaSeparatedValuesEx() compatibility and copyright
212  */
214 {
215  TRACE_CALL(__func__);
216  UINT16 flags;
217  rdpInput *input;
218  rfContext *rfi = GET_PLUGIN_DATA(gp);
219  RemminaPluginRdpEvent *event;
220  DISPLAY_CONTROL_MONITOR_LAYOUT *dcml;
221  CLIPRDR_FORMAT_DATA_RESPONSE response = { 0 };
222  RemminaFile *remminafile;
223 
224  if (rfi->event_queue == NULL)
225  return true;
226 
227  input = rfi->instance->input;
228 
229  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
230 
231  while ((event = (RemminaPluginRdpEvent *)g_async_queue_try_pop(rfi->event_queue)) != NULL) {
232  time(&last_time); //update last user interaction time
233  switch (event->type) {
235  flags = event->key_event.extended ? KBD_FLAGS_EXTENDED : 0;
236  flags |= event->key_event.up ? KBD_FLAGS_RELEASE : KBD_FLAGS_DOWN;
237  input->KeyboardEvent(input, flags, event->key_event.key_code);
238  break;
239 
241  /*
242  * TS_UNICODE_KEYBOARD_EVENT RDP message, see https://msdn.microsoft.com/en-us/library/cc240585.aspx
243  */
244  flags = event->key_event.up ? KBD_FLAGS_RELEASE : KBD_FLAGS_DOWN;
245  input->UnicodeKeyboardEvent(input, flags, event->key_event.unicode_code);
246  break;
247 
249  if (event->mouse_event.extended)
250  input->ExtendedMouseEvent(input, event->mouse_event.flags,
251  event->mouse_event.x, event->mouse_event.y);
252  else
253  input->MouseEvent(input, event->mouse_event.flags,
254  event->mouse_event.x, event->mouse_event.y);
255  break;
256 
258  rfi->clipboard.context->ClientFormatList(rfi->clipboard.context, event->clipboard_formatlist.pFormatList);
259  free(event->clipboard_formatlist.pFormatList);
260  break;
261 
263  response.msgFlags = (event->clipboard_formatdataresponse.data) ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
264  response.dataLen = event->clipboard_formatdataresponse.size;
265  response.requestedFormatData = event->clipboard_formatdataresponse.data;
266  rfi->clipboard.context->ClientFormatDataResponse(rfi->clipboard.context, &response);
267  break;
268 
270  REMMINA_PLUGIN_DEBUG("Sending client FormatDataRequest to server");
271  gettimeofday(&(rfi->clipboard.clientformatdatarequest_tv), NULL);
272  rfi->clipboard.context->ClientFormatDataRequest(rfi->clipboard.context, event->clipboard_formatdatarequest.pFormatDataRequest);
273  free(event->clipboard_formatdatarequest.pFormatDataRequest);
274  break;
275 
277  if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) {
278  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseMultimon, TRUE);
279  /* TODO Add an option for this */
280  freerdp_settings_set_bool(rfi->settings, FreeRDP_ForceMultimon, TRUE);
281  freerdp_settings_set_bool(rfi->settings, FreeRDP_Fullscreen, TRUE);
282  /* got some crashes with g_malloc0, to be investigated */
283  dcml = calloc(freerdp_settings_get_uint32(rfi->settings, FreeRDP_MonitorCount), sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
284  REMMINA_PLUGIN_DEBUG("REMMINA_RDP_EVENT_TYPE_SEND_MONITOR_LAYOUT:");
285  if (!dcml)
286  break;
287 
288  const rdpMonitor *base = freerdp_settings_get_pointer(rfi->settings, FreeRDP_MonitorDefArray);
289  for (gint i = 0; i < freerdp_settings_get_uint32(rfi->settings, FreeRDP_MonitorCount); ++i) {
290  const rdpMonitor *current = &base[i];
291  REMMINA_PLUGIN_DEBUG("Sending display layout for monitor n° %d", i);
292  dcml[i].Flags = (current->is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0);
293  REMMINA_PLUGIN_DEBUG("Monitor %d is primary: %d", i, dcml[i].Flags);
294  dcml[i].Left = current->x;
295  REMMINA_PLUGIN_DEBUG("Monitor %d x: %d", i, dcml[i].Left);
296  dcml[i].Top = current->y;
297  REMMINA_PLUGIN_DEBUG("Monitor %d y: %d", i, dcml[i].Top);
298  dcml[i].Width = current->width;
299  REMMINA_PLUGIN_DEBUG("Monitor %d width: %d", i, dcml[i].Width);
300  dcml[i].Height = current->height;
301  REMMINA_PLUGIN_DEBUG("Monitor %d height: %d", i, dcml[i].Height);
302  dcml[i].PhysicalWidth = current->attributes.physicalWidth;
303  REMMINA_PLUGIN_DEBUG("Monitor %d physical width: %d", i, dcml[i].PhysicalWidth);
304  dcml[i].PhysicalHeight = current->attributes.physicalHeight;
305  REMMINA_PLUGIN_DEBUG("Monitor %d physical height: %d", i, dcml[i].PhysicalHeight);
306  if (current->attributes.orientation)
307  dcml[i].Orientation = current->attributes.orientation;
308  else
309  dcml[i].Orientation = event->monitor_layout.desktopOrientation;
310  REMMINA_PLUGIN_DEBUG("Monitor %d orientation: %d", i, dcml[i].Orientation);
311  dcml[i].DesktopScaleFactor = event->monitor_layout.desktopScaleFactor;
312  dcml[i].DeviceScaleFactor = event->monitor_layout.deviceScaleFactor;
313  }
314  rfi->dispcontext->SendMonitorLayout(rfi->dispcontext, freerdp_settings_get_uint32(rfi->settings, FreeRDP_MonitorCount), dcml);
315  g_free(dcml);
316  } else {
317  dcml = g_malloc0(sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
318  if (dcml) {
319  dcml->Flags = DISPLAY_CONTROL_MONITOR_PRIMARY;
320  dcml->Width = event->monitor_layout.width;
321  dcml->Height = event->monitor_layout.height;
322  dcml->Orientation = event->monitor_layout.desktopOrientation;
323  dcml->DesktopScaleFactor = event->monitor_layout.desktopScaleFactor;
324  dcml->DeviceScaleFactor = event->monitor_layout.deviceScaleFactor;
325  rfi->dispcontext->SendMonitorLayout(rfi->dispcontext, 1, dcml);
326  g_free(dcml); \
327  }
328  }
329  break;
331  /* Disconnect requested via GUI (i.e: tab destroy/close) */
332  freerdp_abort_connect(rfi->instance);
333  break;
334  }
335 
336  g_free(event);
337  }
338 
339  return true;
340 }
341 
343 {
344  TRACE_CALL(__func__);
345 
346  /* Opens the optional SSH tunnel if needed.
347  * Used also when reopening the same tunnel for a FreeRDP reconnect.
348  * Returns TRUE if all OK, and setups correct rfi->Settings values
349  * with connection and certificate parameters */
350 
351  gchar *hostport;
352  gchar *s;
353  gchar *host;
354  gchar *cert_host;
355  gint cert_port;
356  gint port;
357 
358  rfContext *rfi = GET_PLUGIN_DATA(gp);
359 
360  REMMINA_PLUGIN_DEBUG("Tunnel init");
361  hostport = remmina_plugin_service->protocol_plugin_start_direct_tunnel(gp, 3389, FALSE);
362  if (hostport == NULL)
363  return FALSE;
364 
365  remmina_plugin_service->get_server_port(hostport, 3389, &host, &port);
366 
367  if (host[0] == 0)
368  return FALSE;
369 
370  REMMINA_PLUGIN_DEBUG("protocol_plugin_start_direct_tunnel() returned %s", hostport);
371 
372  cert_host = host;
373  cert_port = port;
374 
375  if (!rfi->is_reconnecting) {
376  /* settings->CertificateName and settings->ServerHostname is created
377  * only on 1st connect, not on reconnections */
378 
379  freerdp_settings_set_string(rfi->settings, FreeRDP_ServerHostname, host);
380 
381  if (cert_port == 3389) {
382  freerdp_settings_set_string(rfi->settings, FreeRDP_CertificateName, cert_host);
383  } else {
384  s = g_strdup_printf("%s:%d", cert_host, cert_port);
385  freerdp_settings_set_string(rfi->settings, FreeRDP_CertificateName, s);
386  g_free(s);
387  }
388  }
389 
390  REMMINA_PLUGIN_DEBUG("Tunnel has been optionally initialized. Now connecting to %s:%d", host, port);
391 
392  if (cert_host != host) g_free(cert_host);
393  g_free(host);
394  g_free(hostport);
395 
396  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ServerPort, port);
397 
398  return TRUE;
399 }
400 
401 static BOOL rf_auto_reconnect(rfContext *rfi)
402 {
403  TRACE_CALL(__func__);
404  rdpSettings *settings = rfi->instance->settings;
406  time_t treconn;
407  gchar *cval;
408  gint maxattempts;
409 
411  RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
412 
413  rfi->is_reconnecting = TRUE;
414  rfi->stop_reconnecting_requested = FALSE;
415 
416  /* Get the value set in FreeRDP_AutoReconnectMaxRetries (20) */
417  maxattempts = freerdp_settings_get_uint32(settings, FreeRDP_AutoReconnectMaxRetries);
418  REMMINA_PLUGIN_DEBUG("maxattempts from default: %d", maxattempts);
419  /* Get the value from the global preferences if any */
420  if ((cval = remmina_plugin_service->pref_get_value("rdp_reconnect_attempts")) != NULL)
421  maxattempts = atoi(cval);
422  REMMINA_PLUGIN_DEBUG("maxattempts from general preferences: %d", maxattempts);
423  /* Get the value from the profile if any, otherwise uses the value of maxattempts */
424  maxattempts = remmina_plugin_service->file_get_int(remminafile, "rdp_reconnect_attempts", maxattempts);
425  REMMINA_PLUGIN_DEBUG("maxattempts from general plugin: %d", maxattempts);
426  /* If maxattemps is <= 0, we get the value from FreeRDP_AutoReconnectMaxRetries (20) */
427  if (maxattempts <= 0)
428  maxattempts = freerdp_settings_get_uint32(settings, FreeRDP_AutoReconnectMaxRetries);
429  freerdp_settings_set_uint32(settings, FreeRDP_AutoReconnectMaxRetries, maxattempts);
430  REMMINA_PLUGIN_DEBUG("maxattempts set to: %d", maxattempts);
431 
432  rfi->reconnect_maxattempts = maxattempts;
433  rfi->reconnect_nattempt = 0;
434 
435  /* Only auto reconnect on network disconnects. */
436  switch (freerdp_error_info(rfi->instance)) {
437  case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
438  /* Disconnected by server hitting a bug or resource limit */
439  break;
440  case ERRINFO_SUCCESS:
441  /* A network disconnect was detected */
442  break;
443  default:
444  rfi->is_reconnecting = FALSE;
445  return FALSE;
446  }
447 
448  if (!freerdp_settings_get_bool(settings, FreeRDP_AutoReconnectionEnabled)) {
449  /* No auto-reconnect - just quit */
450  rfi->is_reconnecting = FALSE;
451  return FALSE;
452  }
453 
454  /* A network disconnect was detected and we should try to reconnect */
455  REMMINA_PLUGIN_DEBUG("[%s] network disconnection detected, initiating reconnection attempt",
456  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
457 
458  ui = g_new0(RemminaPluginRdpUiObject, 1);
461 
462  /* Sleep half a second to allow:
463  * - processing of the UI event we just pushed on the queue
464  * - better network conditions
465  * Remember: We hare on a thread, so the main gui won’t lock */
466  usleep(500000);
467 
468  /* Perform an auto-reconnect. */
469  while (TRUE) {
470  /* Quit retrying if max retries has been exceeded */
471  if (rfi->reconnect_nattempt++ >= rfi->reconnect_maxattempts) {
472  REMMINA_PLUGIN_DEBUG("[%s] maximum number of reconnection attempts exceeded.",
473  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
474  break;
475  }
476 
477  if (rfi->stop_reconnecting_requested) {
478  REMMINA_PLUGIN_DEBUG("[%s] reconnect request loop interrupted by user.",
479  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
480  break;
481  }
482 
483  /* Attempt the next reconnect */
484  REMMINA_PLUGIN_DEBUG("[%s] reconnection, attempt #%d of %d",
485  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname), rfi->reconnect_nattempt, rfi->reconnect_maxattempts);
486 
487  ui = g_new0(RemminaPluginRdpUiObject, 1);
490 
491  treconn = time(NULL);
492 
493  /* Reconnect the SSH tunnel, if needed */
495  REMMINA_PLUGIN_DEBUG("[%s] unable to recreate tunnel with remmina_rdp_tunnel_init.",
496  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
497  } else {
498  if (freerdp_reconnect(rfi->instance)) {
499  /* Reconnection is successful */
500  REMMINA_PLUGIN_DEBUG("[%s] reconnected.", freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
501  rfi->is_reconnecting = FALSE;
502  return TRUE;
503  }
504  }
505 
506  /* Wait until 5 secs have elapsed from last reconnect attempt, while checking for rfi->stop_reconnecting_requested */
507  while (time(NULL) - treconn < 5) {
509  break;
510  usleep(200000); // 200ms sleep
511  }
512  }
513 
514  rfi->is_reconnecting = FALSE;
515  return FALSE;
516 }
517 
518 static BOOL rf_begin_paint(rdpContext *context)
519 {
520  TRACE_CALL(__func__);
521  rdpGdi *gdi;
522 
523  if (!context)
524  return FALSE;
525 
526  gdi = context->gdi;
527  if (!gdi || !gdi->primary || !gdi->primary->hdc || !gdi->primary->hdc->hwnd)
528  return FALSE;
529 
530  return TRUE;
531 }
532 
533 static BOOL rf_end_paint(rdpContext *context)
534 {
535  TRACE_CALL(__func__);
536  rdpGdi *gdi;
537  rfContext *rfi;
539  int i, ninvalid;
540  region *reg;
541  HGDI_RGN cinvalid;
542 
543  gdi = context->gdi;
544  rfi = (rfContext *)context;
545 
546  if (gdi == NULL || gdi->primary == NULL || gdi->primary->hdc == NULL || gdi->primary->hdc->hwnd == NULL)
547  return TRUE;
548 
549  if (gdi->primary->hdc->hwnd->invalid->null)
550  return TRUE;
551 
552  if (gdi->primary->hdc->hwnd->ninvalid < 1)
553  return TRUE;
554 
555  ninvalid = gdi->primary->hdc->hwnd->ninvalid;
556  cinvalid = gdi->primary->hdc->hwnd->cinvalid;
557  reg = (region *)g_malloc(sizeof(region) * ninvalid);
558  for (i = 0; i < ninvalid; i++) {
559  reg[i].x = cinvalid[i].x;
560  reg[i].y = cinvalid[i].y;
561  reg[i].w = cinvalid[i].w;
562  reg[i].h = cinvalid[i].h;
563  }
564 
565  ui = g_new0(RemminaPluginRdpUiObject, 1);
567  ui->reg.ninvalid = ninvalid;
568  ui->reg.ureg = reg;
569 
571 
572 
573  gdi->primary->hdc->hwnd->invalid->null = TRUE;
574  gdi->primary->hdc->hwnd->ninvalid = 0;
575 
576 
577  return TRUE;
578 }
579 
580 static BOOL rf_desktop_resize(rdpContext *context)
581 {
582  TRACE_CALL(__func__);
583  rfContext *rfi;
586  UINT32 w, h;
587 
588  rfi = (rfContext *)context;
589  gp = rfi->protocol_widget;
590 
591  w = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth);
592  h = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight);
593  remmina_plugin_service->protocol_plugin_set_width(gp, w);
594  remmina_plugin_service->protocol_plugin_set_height(gp, h);
595 
596  ui = g_new0(RemminaPluginRdpUiObject, 1);
600 
601  /* Tell libfreerdp to change its internal GDI bitmap width and heigt,
602  * this will also destroy gdi->primary_buffer, making our rfi->surface invalid */
603  gdi_resize(((rdpContext *)rfi)->gdi, w, h);
604 
605  /* Call to remmina_rdp_event_update_scale(gp) on the main UI thread,
606  * this will recreate rfi->surface from gdi->primary_buffer */
607 
608  ui = g_new0(RemminaPluginRdpUiObject, 1);
612 
613  remmina_plugin_service->protocol_plugin_desktop_resize(gp);
614 
615  return TRUE;
616 }
617 
618 static BOOL rf_play_sound(rdpContext *context, const PLAY_SOUND_UPDATE *play_sound)
619 {
620  TRACE_CALL(__func__);
621  rfContext *rfi;
623  GdkDisplay *disp;
624 
625  rfi = (rfContext *)context;
626  gp = rfi->protocol_widget;
627 
628  disp = gtk_widget_get_display(GTK_WIDGET(gp));
629  gdk_display_beep(disp);
630 
631  return TRUE;
632 }
633 
634 static BOOL rf_keyboard_set_indicators(rdpContext *context, UINT16 led_flags)
635 {
636  TRACE_CALL(__func__);
637  rfContext *rfi;
639  GdkDisplay *disp;
640 
641  rfi = (rfContext *)context;
642  gp = rfi->protocol_widget;
643  disp = gtk_widget_get_display(GTK_WIDGET(gp));
644 
645 #ifdef GDK_WINDOWING_X11
646  if (GDK_IS_X11_DISPLAY(disp)) {
647  /* TODO: We are not on the main thread. Will X.Org complain? */
648  Display *x11_display;
649  x11_display = gdk_x11_display_get_xdisplay(disp);
650  XkbLockModifiers(x11_display, XkbUseCoreKbd,
651  LockMask | Mod2Mask,
652  ((led_flags & KBD_SYNC_CAPS_LOCK) ? LockMask : 0) |
653  ((led_flags & KBD_SYNC_NUM_LOCK) ? Mod2Mask : 0)
654  );
655 
656  /* TODO: Add support to KANA_LOCK and SCROLL_LOCK */
657  }
658 #endif
659 
660  return TRUE;
661 }
662 
663 static BOOL rf_keyboard_set_ime_status(rdpContext *context, UINT16 imeId, UINT32 imeState,
664  UINT32 imeConvMode)
665 {
666  TRACE_CALL(__func__);
667  if (!context)
668  return FALSE;
669 
670  /* Unimplemented, we ignore it */
671 
672  return TRUE;
673 }
674 
675 static BOOL remmina_rdp_pre_connect(freerdp *instance)
676 {
677  TRACE_CALL(__func__);
678  rdpChannels *channels;
679  rdpSettings *settings;
680  rdpContext *context = instance->context;
681 
682  settings = instance->settings;
683  channels = context->channels;
684  freerdp_settings_set_uint32(settings, FreeRDP_OsMajorType, OSMAJORTYPE_UNIX);
685  freerdp_settings_set_uint32(settings, FreeRDP_OsMinorType, OSMINORTYPE_UNSPECIFIED);
686  freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled, TRUE);
687  freerdp_settings_set_uint32(settings, FreeRDP_OffscreenSupportLevel, 1);
688 
689  PubSub_SubscribeChannelConnected(instance->context->pubSub,
691  PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
693 
694  if (!freerdp_client_load_addins(channels, settings))
695  return FALSE;
696 
697  return true;
698 }
699 
700 static BOOL remmina_rdp_post_connect(freerdp *instance)
701 {
702  TRACE_CALL(__func__);
703  rfContext *rfi;
706  UINT32 freerdp_local_color_format;
707 
708  rfi = (rfContext *)instance->context;
709  gp = rfi->protocol_widget;
710  rfi->postconnect_error = REMMINA_POSTCONNECT_ERROR_OK;
711 
712  rfi->attempt_interactive_authentication = FALSE; // We authenticated!
713 
714  rfi->srcBpp = freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth);
715 
716  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_RemoteFxCodec) == FALSE)
717  rfi->sw_gdi = TRUE;
718 
719  rf_register_graphics(instance->context->graphics);
720 
721  REMMINA_PLUGIN_DEBUG("bpp: %d", rfi->bpp);
722  switch (rfi->bpp) {
723  case 24:
724  REMMINA_PLUGIN_DEBUG("CAIRO_FORMAT_RGB24");
725  freerdp_local_color_format = PIXEL_FORMAT_BGRX32;
726  rfi->cairo_format = CAIRO_FORMAT_RGB24;
727  break;
728  case 32:
733  REMMINA_PLUGIN_DEBUG("CAIRO_FORMAT_RGB24");
734  freerdp_local_color_format = PIXEL_FORMAT_BGRA32;
735  rfi->cairo_format = CAIRO_FORMAT_RGB24;
736  break;
737  default:
738  REMMINA_PLUGIN_DEBUG("CAIRO_FORMAT_RGB16_565");
739  freerdp_local_color_format = PIXEL_FORMAT_RGB16;
740  rfi->cairo_format = CAIRO_FORMAT_RGB16_565;
741  break;
742  }
743 
744  if (!gdi_init(instance, freerdp_local_color_format)) {
745  rfi->postconnect_error = REMMINA_POSTCONNECT_ERROR_GDI_INIT;
746  return FALSE;
747  }
748 
749  if (instance->context->codecs->h264 == NULL && freerdp_settings_get_bool(rfi->settings, FreeRDP_GfxH264)) {
750  gdi_free(instance);
751  rfi->postconnect_error = REMMINA_POSTCONNECT_ERROR_NO_H264;
752  return FALSE;
753  }
754 
755  // pointer_cache_register_callbacks(instance->update);
756 
757  instance->update->BeginPaint = rf_begin_paint;
758  instance->update->EndPaint = rf_end_paint;
759  instance->update->DesktopResize = rf_desktop_resize;
760 
761  instance->update->PlaySound = rf_play_sound;
762  instance->update->SetKeyboardIndicators = rf_keyboard_set_indicators;
763  instance->update->SetKeyboardImeStatus = rf_keyboard_set_ime_status;
764 
766  rfi->connected = true;
767 
768  ui = g_new0(RemminaPluginRdpUiObject, 1);
771 
772  return TRUE;
773 }
774 
775 static BOOL remmina_rdp_authenticate(freerdp *instance, char **username, char **password, char **domain)
776 {
777  TRACE_CALL(__func__);
778  gchar *s_username, *s_password, *s_domain;
779  gint ret;
780  rfContext *rfi;
782  gboolean save;
783  gboolean disablepasswordstoring;
784  RemminaFile *remminafile;
785 
786  rfi = (rfContext *)instance->context;
787  gp = rfi->protocol_widget;
788  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
789  disablepasswordstoring = remmina_plugin_service->file_get_int(remminafile, "disablepasswordstoring", FALSE);
790 
791  ret = remmina_plugin_service->protocol_plugin_init_auth(gp,
793  _("Enter RDP authentication credentials"),
794  remmina_plugin_service->file_get_string(remminafile, "username"),
795  remmina_plugin_service->file_get_string(remminafile, "password"),
796  remmina_plugin_service->file_get_string(remminafile, "domain"),
797  NULL);
798  if (ret == GTK_RESPONSE_OK) {
799  s_username = remmina_plugin_service->protocol_plugin_init_get_username(gp);
800  if (s_username) freerdp_settings_set_string(rfi->settings, FreeRDP_Username, s_username);
801 
802  s_password = remmina_plugin_service->protocol_plugin_init_get_password(gp);
803  if (s_password) freerdp_settings_set_string(rfi->settings, FreeRDP_Password, s_password);
804 
805  s_domain = remmina_plugin_service->protocol_plugin_init_get_domain(gp);
806  if (s_domain) freerdp_settings_set_string(rfi->settings, FreeRDP_Domain, s_domain);
807 
808  remmina_plugin_service->file_set_string(remminafile, "username", s_username);
809  remmina_plugin_service->file_set_string(remminafile, "domain", s_domain);
810 
811  save = remmina_plugin_service->protocol_plugin_init_get_savepassword(gp);
812  if (save) {
813  // User has requested to save credentials. We put the password
814  // into remminafile->settings. It will be saved later, on successful connection, by
815  // rcw.c
816  remmina_plugin_service->file_set_string(remminafile, "password", s_password);
817  } else {
818  remmina_plugin_service->file_set_string(remminafile, "password", NULL);
819  }
820 
821 
822  if (s_username) g_free(s_username);
823  if (s_password) g_free(s_password);
824  if (s_domain) g_free(s_domain);
825 
826  return TRUE;
827  } else {
828  return FALSE;
829  }
830 
831  return TRUE;
832 }
833 
834 static BOOL remmina_rdp_gw_authenticate(freerdp *instance, char **username, char **password, char **domain)
835 {
836  TRACE_CALL(__func__);
837  gchar *s_username, *s_password, *s_domain;
838  gint ret;
839  rfContext *rfi;
841  gboolean save;
842  gboolean disablepasswordstoring;
843  gboolean basecredforgw;
844  RemminaFile *remminafile;
845 
846  rfi = (rfContext *)instance->context;
847  gp = rfi->protocol_widget;
848  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
849 
850  if (!remmina_plugin_service->file_get_string(remminafile, "gateway_server"))
851  return false;
852  disablepasswordstoring = remmina_plugin_service->file_get_int(remminafile, "disablepasswordstoring", FALSE);
853  basecredforgw = remmina_plugin_service->file_get_int(remminafile, "base-cred-for-gw", FALSE);
854 
855  if (basecredforgw) {
856  ret = remmina_plugin_service->protocol_plugin_init_auth(gp,
858  _("Enter RDP authentication credentials"),
859  remmina_plugin_service->file_get_string(remminafile, "username"),
860  remmina_plugin_service->file_get_string(remminafile, "password"),
861  remmina_plugin_service->file_get_string(remminafile, "domain"),
862  NULL);
863  } else {
864  ret = remmina_plugin_service->protocol_plugin_init_auth(gp,
866  _("Enter RDP gateway authentication credentials"),
867  remmina_plugin_service->file_get_string(remminafile, "gateway_username"),
868  remmina_plugin_service->file_get_string(remminafile, "gateway_password"),
869  remmina_plugin_service->file_get_string(remminafile, "gateway_domain"),
870  NULL);
871  }
872 
873 
874  if (ret == GTK_RESPONSE_OK) {
875  s_username = remmina_plugin_service->protocol_plugin_init_get_username(gp);
876  if (s_username) freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayUsername, s_username);
877 
878  s_password = remmina_plugin_service->protocol_plugin_init_get_password(gp);
879  if (s_password) freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayPassword, s_password);
880 
881  s_domain = remmina_plugin_service->protocol_plugin_init_get_domain(gp);
882  if (s_domain) freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayDomain, s_domain);
883 
884  save = remmina_plugin_service->protocol_plugin_init_get_savepassword(gp);
885 
886  if (basecredforgw) {
887  remmina_plugin_service->file_set_string(remminafile, "username", s_username);
888  remmina_plugin_service->file_set_string(remminafile, "domain", s_domain);
889  if (save)
890  remmina_plugin_service->file_set_string(remminafile, "password", s_password);
891  else
892  remmina_plugin_service->file_set_string(remminafile, "password", NULL);
893  } else {
894  remmina_plugin_service->file_set_string(remminafile, "gateway_username", s_username);
895  remmina_plugin_service->file_set_string(remminafile, "gateway_domain", s_domain);
896  if (save)
897  remmina_plugin_service->file_set_string(remminafile, "gateway_password", s_password);
898  else
899  remmina_plugin_service->file_set_string(remminafile, "gateway_password", NULL);
900  }
901 
902  if (s_username) g_free(s_username);
903  if (s_password) g_free(s_password);
904  if (s_domain) g_free(s_domain);
905 
906  return true;
907  } else {
908  return false;
909  }
910 
911  return true;
912 }
913 
914 static DWORD remmina_rdp_verify_certificate_ex(freerdp *instance, const char *host, UINT16 port,
915  const char *common_name, const char *subject,
916  const char *issuer, const char *fingerprint, DWORD flags)
917 {
918  TRACE_CALL(__func__);
919  gint status;
920  rfContext *rfi;
922 
923  rfi = (rfContext *)instance->context;
924  gp = rfi->protocol_widget;
925 
926  status = remmina_plugin_service->protocol_plugin_init_certificate(gp, subject, issuer, fingerprint);
927 
928  if (status == GTK_RESPONSE_OK)
929  return 1;
930 
931  return 0;
932 }
933 
934 static DWORD
935 remmina_rdp_verify_certificate(freerdp *instance, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, BOOL host_mismatch) __attribute__ ((unused));
936 static DWORD
937 remmina_rdp_verify_certificate(freerdp *instance, const char *common_name, const char *subject,
938  const char *issuer, const char *fingerprint, BOOL host_mismatch)
939 {
940  TRACE_CALL(__func__);
941  gint status;
942  rfContext *rfi;
944 
945  rfi = (rfContext *)instance->context;
946  gp = rfi->protocol_widget;
947 
948  status = remmina_plugin_service->protocol_plugin_init_certificate(gp, subject, issuer, fingerprint);
949 
950  if (status == GTK_RESPONSE_OK)
951  return 1;
952 
953  return 0;
954 }
955 
956 static DWORD remmina_rdp_verify_changed_certificate_ex(freerdp *instance, const char *host, UINT16 port,
957  const char *common_name, const char *subject,
958  const char *issuer, const char *fingerprint,
959  const char *old_subject, const char *old_issuer,
960  const char *old_fingerprint, DWORD flags)
961 {
962  TRACE_CALL(__func__);
963  gint status;
964  rfContext *rfi;
966 
967  rfi = (rfContext *)instance->context;
968  gp = rfi->protocol_widget;
969 
970  status = remmina_plugin_service->protocol_plugin_changed_certificate(gp, subject, issuer, fingerprint, old_fingerprint);
971 
972  if (status == GTK_RESPONSE_OK)
973  return 1;
974 
975  return 0;
976 }
977 
978 static void remmina_rdp_post_disconnect(freerdp *instance)
979 {
980  TRACE_CALL(__func__);
981 
982  if (!instance || !instance->context)
983  return;
984 
985  PubSub_UnsubscribeChannelConnected(instance->context->pubSub,
987  PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub,
989 
990  /* The remaining cleanup will be continued on main thread by complete_cleanup_on_main_thread() */
991 }
992 
994 {
995  TRACE_CALL(__func__);
996  DWORD status;
997  gchar buf[100];
998  rfContext *rfi = GET_PLUGIN_DATA(gp);
999  RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
1000  time_t cur_time, time_diff;
1001 
1002  int jitter_time = remmina_plugin_service->file_get_int(remminafile, "rdp_mouse_jitter", 0);
1003  time(&last_time);
1004  while (!freerdp_shall_disconnect(rfi->instance)) {
1005  //move mouse if we've been idle and option is selected
1006  time(&cur_time);
1007  time_diff = cur_time - last_time;
1008  if (jitter_time > 0 && time_diff > jitter_time){
1009  last_time = cur_time;
1011  }
1012 
1013  HANDLE handles[64]={0};
1014  DWORD nCount = freerdp_get_event_handles(rfi->instance->context, &handles[0], 64);
1015  if (rfi->event_handle)
1016  handles[nCount++] = rfi->event_handle;
1017 
1018  handles[nCount++] = rfi->instance->context->abortEvent;
1019 
1020  if (nCount == 0) {
1021  fprintf(stderr, "freerdp_get_event_handles failed\n");
1022  break;
1023  }
1024 
1025  status = WaitForMultipleObjects(nCount, handles, FALSE, 100);
1026 
1027  if (status == WAIT_FAILED) {
1028  fprintf(stderr, "WaitForMultipleObjects failed with %lu\n", (unsigned long)status);
1029  break;
1030  }
1031 
1032  if (rfi->event_handle && WaitForSingleObject(rfi->event_handle, 0) == WAIT_OBJECT_0) {
1033  if (!rf_process_event_queue(gp)) {
1034  fprintf(stderr, "Could not process local keyboard/mouse event queue\n");
1035  break;
1036  }
1037  if (read(rfi->event_pipe[0], buf, sizeof(buf))) {
1038  }
1039  }
1040 
1041  /* Check if a processed event called freerdp_abort_connect() and exit if true */
1042  if (WaitForSingleObject(rfi->instance->context->abortEvent, 0) == WAIT_OBJECT_0)
1043  /* Session disconnected by local user action */
1044  break;
1045 
1046  if (!freerdp_check_event_handles(rfi->instance->context)) {
1047  if (rf_auto_reconnect(rfi)) {
1048  /* Reset the possible reason/error which made us doing many reconnection reattempts and continue */
1049  remmina_plugin_service->protocol_plugin_set_error(gp, NULL);
1050  continue;
1051  }
1052  if (freerdp_get_last_error(rfi->instance->context) == FREERDP_ERROR_SUCCESS)
1053  fprintf(stderr, "Could not check FreeRDP file descriptor\n");
1054  break;
1055  }
1056  }
1057  const gchar *host = freerdp_settings_get_string (rfi->settings, FreeRDP_ServerHostname);
1058  // TRANSLATORS: the placeholder may be either an IP/FQDN or a server hostname
1059  REMMINA_PLUGIN_AUDIT(_("Disconnected from %s via RDP"), host);
1060  freerdp_disconnect(rfi->instance);
1061  REMMINA_PLUGIN_DEBUG("RDP client disconnected");
1062 }
1063 
1064 static int remmina_rdp_load_static_channel_addin(rdpChannels *channels, rdpSettings *settings, char *name, void *data)
1065 {
1066  TRACE_CALL(__func__);
1067  PVIRTUALCHANNELENTRY entry = NULL;
1068  PVIRTUALCHANNELENTRYEX entryEx = NULL;
1069 
1070  entryEx = (PVIRTUALCHANNELENTRYEX)(void *)freerdp_load_channel_addin_entry(
1071  name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC | FREERDP_ADDIN_CHANNEL_ENTRYEX);
1072 
1073  if (!entryEx)
1074  entry = freerdp_load_channel_addin_entry(name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC);
1075 
1076  if (entryEx) {
1077  if (freerdp_channels_client_load_ex(channels, settings, entryEx, data) == 0) {
1078  fprintf(stderr, "loading channel %s\n", name);
1079  return TRUE;
1080  }
1081  } else if (entry) {
1082  if (freerdp_channels_client_load(channels, settings, entry, data) == 0) {
1083  fprintf(stderr, "loading channel %s\n", name);
1084  return TRUE;
1085  }
1086  }
1087 
1088  return FALSE;
1089 }
1090 
1091 static gchar *remmina_rdp_find_prdriver(char *smap, char *prn)
1092 {
1093  char c, *p, *dr;
1094  int matching;
1095  size_t sz;
1096 
1097  enum { S_WAITPR,
1098  S_INPRINTER,
1099  S_WAITCOLON,
1100  S_WAITDRIVER,
1101  S_INDRIVER,
1102  S_WAITSEMICOLON } state = S_WAITPR;
1103 
1104  matching = 0;
1105  while ((c = *smap++) != 0) {
1106  switch (state) {
1107  case S_WAITPR:
1108  if (c != '\"') return NULL;
1109  state = S_INPRINTER;
1110  p = prn;
1111  matching = 1;
1112  break;
1113  case S_INPRINTER:
1114  if (matching && c == *p && *p != 0) {
1115  p++;
1116  } else if (c == '\"') {
1117  if (*p != 0)
1118  matching = 0;
1119  state = S_WAITCOLON;
1120  } else {
1121  matching = 0;
1122  }
1123  break;
1124  case S_WAITCOLON:
1125  if (c != ':')
1126  return NULL;
1127  state = S_WAITDRIVER;
1128  break;
1129  case S_WAITDRIVER:
1130  if (c != '\"')
1131  return NULL;
1132  state = S_INDRIVER;
1133  dr = smap;
1134  break;
1135  case S_INDRIVER:
1136  if (c == '\"') {
1137  if (matching)
1138  goto found;
1139  else
1140  state = S_WAITSEMICOLON;
1141  }
1142  break;
1143  case S_WAITSEMICOLON:
1144  if (c != ';')
1145  return NULL;
1146  state = S_WAITPR;
1147  break;
1148  }
1149  }
1150  return NULL;
1151 
1152 found:
1153  sz = smap - dr;
1154  p = (char *)malloc(sz);
1155  memcpy(p, dr, sz);
1156  p[sz - 1] = 0;
1157  return p;
1158 }
1159 
1160 #ifdef HAVE_CUPS
1161 
1166 static int remmina_rdp_set_printers(void *user_data, unsigned flags, cups_dest_t *dest)
1167 {
1168  rfContext *rfi = (rfContext *)user_data;
1170 
1185  RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
1186  const gchar *s = remmina_plugin_service->file_get_string(remminafile, "printer_overrides");
1187 
1188  RDPDR_PRINTER *printer;
1189  printer = (RDPDR_PRINTER *)calloc(1, sizeof(RDPDR_PRINTER));
1190 
1191 #ifdef WITH_FREERDP3
1192  RDPDR_DEVICE *pdev;
1193  pdev = &(printer->device);
1194 #else
1195  RDPDR_PRINTER *pdev;
1196  pdev = printer;
1197 #endif
1198 
1199  pdev->Type = RDPDR_DTYP_PRINT;
1200  REMMINA_PLUGIN_DEBUG("Printer Type: %d", pdev->Type);
1201 
1202  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectPrinters, TRUE);
1203  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
1204 
1205  REMMINA_PLUGIN_DEBUG("Destination: %s", dest->name);
1206  if (!(pdev->Name = _strdup(dest->name))) {
1207  free(printer);
1208  return 1;
1209  }
1210 
1211  REMMINA_PLUGIN_DEBUG("Printer Name: %s", pdev->Name);
1212 
1213  if (s) {
1214  gchar *d = remmina_rdp_find_prdriver(strdup(s), pdev->Name);
1215  if (d) {
1216  printer->DriverName = strdup(d);
1217  REMMINA_PLUGIN_DEBUG("Printer DriverName set to: %s", printer->DriverName);
1218  g_free(d);
1219  } else {
1225  free(pdev->Name);
1226  free(printer);
1227  return 1;
1228  }
1229  } else {
1230  /* We set to a default driver*/
1231  printer->DriverName = _strdup("MS Publisher Imagesetter");
1232  }
1233 
1234  REMMINA_PLUGIN_DEBUG("Printer Driver: %s", printer->DriverName);
1235  if (!freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)printer)) {
1236  free(printer->DriverName);
1237  free(pdev->Name);
1238  free(printer);
1239  return 1;
1240  }
1241 
1242  return 1;
1243 }
1244 #endif /* HAVE_CUPS */
1245 
1246 /* Send Ctrl+Alt+Del keystrokes to the plugin drawing_area widget */
1248 {
1249  TRACE_CALL(__func__);
1250  guint keys[] = { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_Delete };
1251  rfContext *rfi = GET_PLUGIN_DATA(gp);
1252 
1253  remmina_plugin_service->protocol_plugin_send_keys_signals(rfi->drawing_area,
1254  keys, G_N_ELEMENTS(keys), GDK_KEY_PRESS | GDK_KEY_RELEASE);
1255 }
1256 
1257 static gboolean remmina_rdp_set_connection_type(rdpSettings *settings, guint32 type)
1258 {
1259  freerdp_settings_set_uint32(settings, FreeRDP_ConnectionType, type);
1260 
1261  if (type == CONNECTION_TYPE_MODEM) {
1262  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, TRUE);
1263  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, FALSE);
1264  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, FALSE);
1265  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE);
1266  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE);
1267  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, TRUE);
1268  } else if (type == CONNECTION_TYPE_BROADBAND_LOW) {
1269  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, TRUE);
1270  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, FALSE);
1271  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, FALSE);
1272  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE);
1273  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE);
1274  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
1275  } else if (type == CONNECTION_TYPE_SATELLITE) {
1276  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, TRUE);
1277  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, FALSE);
1278  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
1279  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE);
1280  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE);
1281  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
1282  } else if (type == CONNECTION_TYPE_BROADBAND_HIGH) {
1283  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, TRUE);
1284  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, FALSE);
1285  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
1286  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE);
1287  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE);
1288  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
1289  } else if (type == CONNECTION_TYPE_WAN) {
1290  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, FALSE);
1291  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, TRUE);
1292  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
1293  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, FALSE);
1294  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, FALSE);
1295  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
1296  } else if (type == CONNECTION_TYPE_LAN) {
1297  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, FALSE);
1298  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, TRUE);
1299  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
1300  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, FALSE);
1301  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, FALSE);
1302  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
1303  } else if (type == CONNECTION_TYPE_AUTODETECT) {
1304  freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, FALSE);
1305  freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, TRUE);
1306  freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE);
1307  freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, FALSE);
1308  freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, FALSE);
1309  freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE);
1310  freerdp_settings_set_bool(settings, FreeRDP_NetworkAutoDetect, TRUE);
1311 
1312  /* Automatically activate GFX and RFX codec support */
1313 #ifdef WITH_GFX_H264
1314  freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444, gfx_h264_available);
1315  freerdp_settings_set_bool(settings, FreeRDP_GfxH264, gfx_h264_available);
1316 #endif
1317  freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE);
1318  freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, TRUE);
1319  } else if (type == REMMINA_CONNECTION_TYPE_NONE) {
1320  return FALSE;
1321  } else {
1322  return FALSE;
1323  }
1324 
1325  return TRUE;
1326 }
1327 
1328 #ifdef GDK_WINDOWING_X11
1329 #if FREERDP_CHECK_VERSION(2, 3, 0)
1330 static gchar *remmina_get_rdp_kbd_remap(const gchar *keymap)
1331 {
1332  TRACE_CALL(__func__);
1333  guint *table;
1334  gchar keys[20];
1335  gchar *rdp_kbd_remap = NULL;
1336  gint i;
1337  Display *display;
1338 
1339  table = remmina_plugin_service->pref_keymap_get_table(keymap);
1340  if (!table)
1341  return rdp_kbd_remap;
1342  rdp_kbd_remap = g_malloc0(512);
1343  display = XOpenDisplay(0);
1344  for (i = 0; table[i] > 0; i += 2) {
1345  g_snprintf(keys, sizeof(keys), "0x%02x=0x%02x", freerdp_keyboard_get_rdp_scancode_from_x11_keycode(XKeysymToKeycode(display, table[i])),
1346  freerdp_keyboard_get_rdp_scancode_from_x11_keycode(XKeysymToKeycode(display, table[i + 1])));
1347  if (i > 0)
1348  g_strlcat(rdp_kbd_remap, ",", 512);
1349  g_strlcat(rdp_kbd_remap, keys, 512);
1350  }
1351  XCloseDisplay(display);
1352 
1353  return rdp_kbd_remap;
1354 }
1355 #endif
1356 #endif
1357 
1359 {
1360  TRACE_CALL(__func__);
1361  const gchar *s;
1362  gchar *sm;
1363  gchar *value;
1364  const gchar *cs;
1365  RemminaFile *remminafile;
1366  rfContext *rfi = GET_PLUGIN_DATA(gp);
1367  rdpChannels *channels;
1368  gchar *gateway_host;
1369  gint gateway_port;
1370  gchar *datapath = NULL;
1371  gboolean status = TRUE;
1372 #ifdef GDK_WINDOWING_X11
1373  gchar *rdp_kbd_remap;
1374 #endif
1375  gint i;
1376 
1377  gint desktopOrientation, desktopScaleFactor, deviceScaleFactor;
1378 
1379  channels = rfi->instance->context->channels;
1380 
1381  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
1382 
1383  datapath = g_build_path("/",
1384  remmina_plugin_service->file_get_user_datadir(),
1385  "RDP",
1386  NULL);
1387  REMMINA_PLUGIN_DEBUG("RDP data path is %s", datapath);
1388 
1389  if ((datapath != NULL) && (datapath[0] != '\0'))
1390  if (access(datapath, W_OK) == 0)
1391  freerdp_settings_set_string(rfi->settings, FreeRDP_ConfigPath, datapath);
1392  g_free(datapath);
1393 
1394  if (remmina_plugin_service->file_get_int(remminafile, "assistance_mode", 0)){
1395  rdpAssistanceFile* file = freerdp_assistance_file_new();
1396  if (!file){
1397  REMMINA_PLUGIN_DEBUG("Could not allocate assistance file structure");
1398  return FALSE;
1399  }
1400 
1401  if (remmina_plugin_service->file_get_string(remminafile, "assistance_file") == NULL ||
1402  remmina_plugin_service->file_get_string(remminafile, "assistance_pass") == NULL ){
1403 
1404  REMMINA_PLUGIN_DEBUG("Assistance file and password are not set while assistance mode is on");
1405  return FALSE;
1406  }
1407 
1408  status = freerdp_assistance_parse_file(file,
1409  remmina_plugin_service->file_get_string(remminafile, "assistance_file"),
1410  remmina_plugin_service->file_get_string(remminafile, "assistance_pass"));
1411 
1412  if (status < 0){
1413  REMMINA_PLUGIN_DEBUG("Could not parse assistance file");
1414  return FALSE;
1415  }
1416 
1417 
1418  if (!freerdp_assistance_populate_settings_from_assistance_file(file, rfi->settings)){
1419  REMMINA_PLUGIN_DEBUG("Could not populate settings from assistance file");
1420  return FALSE;
1421  }
1422  }
1423 
1424 
1425 #if defined(PROXY_TYPE_IGNORE)
1426  if (!remmina_plugin_service->file_get_int(remminafile, "useproxyenv", FALSE) ? TRUE : FALSE) {
1427  REMMINA_PLUGIN_DEBUG("Not using system proxy settings");
1428  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ProxyType, PROXY_TYPE_IGNORE);
1429  }
1430 #endif
1431 
1432  if (!remmina_rdp_tunnel_init(gp))
1433  return FALSE;
1434 
1435  freerdp_settings_set_bool(rfi->settings, FreeRDP_AutoReconnectionEnabled, (remmina_plugin_service->file_get_int(remminafile, "disableautoreconnect", FALSE) ? FALSE : TRUE));
1436  /* Disable RDP auto reconnection when SSH tunnel is enabled */
1437  if (remmina_plugin_service->file_get_int(remminafile, "ssh_tunnel_enabled", FALSE))
1438  freerdp_settings_set_bool(rfi->settings, FreeRDP_AutoReconnectionEnabled, FALSE);
1439 
1440  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, remmina_plugin_service->file_get_int(remminafile, "colordepth", 99));
1441 
1442  freerdp_settings_set_bool(rfi->settings, FreeRDP_SoftwareGdi, TRUE);
1443  REMMINA_PLUGIN_DEBUG("gfx_h264_available: %d", gfx_h264_available);
1444 
1445  /* Avoid using H.264 modes if they are not available on libfreerdp */
1446  if (!gfx_h264_available && (freerdp_settings_get_bool(rfi->settings, FreeRDP_ColorDepth) == 65 || freerdp_settings_get_bool(rfi->settings, FreeRDP_ColorDepth == 66)))
1447  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 64); // Fallback to GFX RFX
1448 
1449  if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 0) {
1450  /* RFX (Win7)*/
1451  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteFxCodec, TRUE);
1452  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, FALSE);
1453  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
1454  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 63) {
1455  /* /gfx (RFX Progressive) (Win8) */
1456  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
1457  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
1458  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, FALSE);
1459  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, FALSE);
1460  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 64) {
1461  /* /gfx:rfx (Win8) */
1462  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
1463  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteFxCodec, TRUE);
1464  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
1465  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, FALSE);
1466  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, FALSE);
1467  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 65) {
1468  /* /gfx:avc420 (Win8.1) */
1469  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
1470  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
1471  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, gfx_h264_available);
1472  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, FALSE);
1473  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 66) {
1474  /* /gfx:avc444 (Win10) */
1475  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
1476  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
1477  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, gfx_h264_available);
1478  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, gfx_h264_available);
1479  } else if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_ColorDepth) == 99) {
1480  /* Automatic (Let the server choose its best format) */
1481  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
1482  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteFxCodec, TRUE);
1483  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline, TRUE);
1484  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxH264, gfx_h264_available);
1485  freerdp_settings_set_bool(rfi->settings, FreeRDP_GfxAVC444, gfx_h264_available);
1486  }
1487 
1488  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_RemoteFxCodec) ||
1489  freerdp_settings_get_bool(rfi->settings, FreeRDP_NSCodec) ||
1490  freerdp_settings_get_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline)) {
1491  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathOutput, TRUE);
1492  freerdp_settings_set_bool(rfi->settings, FreeRDP_FrameMarkerCommandEnabled, TRUE);
1493  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ColorDepth, 32);
1494  rfi->bpp = 32;
1495  }
1496 
1497  gint w = remmina_plugin_service->get_profile_remote_width(gp);
1498  gint h = remmina_plugin_service->get_profile_remote_height(gp);
1499  /* multiple of 4 */
1500  w = (w + 3) & ~0x3;
1501  h = (h + 3) & ~0x3;
1502  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopWidth, w);
1503  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopHeight, h);
1504  REMMINA_PLUGIN_DEBUG("Resolution set by the user: %dx%d", w, h);
1505 
1506  /* Workaround for FreeRDP issue #5417: in GFX AVC modes we can't go under
1507  * AVC_MIN_DESKTOP_WIDTH x AVC_MIN_DESKTOP_HEIGHT */
1508  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline) &&
1509  freerdp_settings_get_bool(rfi->settings, FreeRDP_GfxH264)) {
1510  if (freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth) <
1511  AVC_MIN_DESKTOP_WIDTH)
1512  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopWidth,
1513  AVC_MIN_DESKTOP_WIDTH);
1514  if (freerdp_settings_get_uint32(rfi->settings,
1515  FreeRDP_DesktopHeight) <
1516  AVC_MIN_DESKTOP_HEIGHT)
1517  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopHeight,
1518  AVC_MIN_DESKTOP_HEIGHT);
1519  }
1520 
1521  /* Workaround for FreeRDP issue #5119. This will make our horizontal resolution
1522  * an even value, but it will add a vertical black 1 pixel line on the
1523  * right of the desktop */
1524  if ((freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth) & 1) != 0) {
1525  UINT32 tmp = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth);
1526  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopWidth, tmp - 1);
1527  }
1528 
1529  remmina_plugin_service->protocol_plugin_set_width(gp, freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth));
1530  remmina_plugin_service->protocol_plugin_set_height(gp, freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight));
1531 
1532  w = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth);
1533  h = freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight);
1534  REMMINA_PLUGIN_DEBUG("Resolution set after workarounds: %dx%d", w, h);
1535 
1536 
1537  if (remmina_plugin_service->file_get_string(remminafile, "username"))
1538  freerdp_settings_set_string(rfi->settings, FreeRDP_Username, remmina_plugin_service->file_get_string(remminafile, "username"));
1539 
1540  if (remmina_plugin_service->file_get_string(remminafile, "domain"))
1541  freerdp_settings_set_string(rfi->settings, FreeRDP_Domain, remmina_plugin_service->file_get_string(remminafile, "domain"));
1542 
1543  s = remmina_plugin_service->file_get_string(remminafile, "password");
1544  if (s) freerdp_settings_set_string(rfi->settings, FreeRDP_Password, s);
1545 
1546  freerdp_settings_set_bool(rfi->settings, FreeRDP_AutoLogonEnabled, TRUE);
1547 
1552  gchar *proxy_type = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_type"));
1553  gchar *proxy_username = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_username"));
1554  gchar *proxy_password = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_password"));
1555  gchar *proxy_hostname = g_strdup(remmina_plugin_service->file_get_string(remminafile, "proxy_hostname"));
1556  gint proxy_port = remmina_plugin_service->file_get_int(remminafile, "proxy_port", 80);
1557  REMMINA_PLUGIN_DEBUG("proxy_type: %s", proxy_type);
1558  REMMINA_PLUGIN_DEBUG("proxy_username: %s", proxy_username);
1559  REMMINA_PLUGIN_DEBUG("proxy_password: %s", proxy_password);
1560  REMMINA_PLUGIN_DEBUG("proxy_hostname: %s", proxy_hostname);
1561  REMMINA_PLUGIN_DEBUG("proxy_port: %d", proxy_port);
1562  if (proxy_type && proxy_hostname) {
1563  if (g_strcmp0(proxy_type, "no_proxy") == 0)
1564  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ProxyType, PROXY_TYPE_IGNORE);
1565  else if (g_strcmp0(proxy_type, "http") == 0)
1566  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ProxyType, PROXY_TYPE_HTTP);
1567  else if (g_strcmp0(proxy_type, "socks5") == 0)
1568  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ProxyType, PROXY_TYPE_SOCKS);
1569  else
1570  g_warning("Invalid proxy protocol, at the moment only no_proxy, HTTP and SOCKS5 are supported");
1571  REMMINA_PLUGIN_DEBUG("ProxyType set to: %" PRIu32, freerdp_settings_get_uint32(rfi->settings, FreeRDP_ProxyType));
1572  freerdp_settings_set_string(rfi->settings, FreeRDP_ProxyHostname, proxy_hostname);
1573  if (proxy_username)
1574  freerdp_settings_set_string(rfi->settings, FreeRDP_ProxyUsername, proxy_username);
1575  if (proxy_password)
1576  freerdp_settings_set_string(rfi->settings, FreeRDP_ProxyPassword, proxy_password);
1577  if (proxy_port)
1578  freerdp_settings_set_uint16(rfi->settings, FreeRDP_ProxyPort, proxy_port);
1579  }
1580  g_free(proxy_hostname);
1581  g_free(proxy_username);
1582  g_free(proxy_password);
1583 
1584  if (remmina_plugin_service->file_get_int(remminafile, "base-cred-for-gw", FALSE)) {
1585  // Reset gateway credentials
1586  remmina_plugin_service->file_set_string(remminafile, "gateway_username", NULL);
1587  remmina_plugin_service->file_set_string(remminafile, "gateway_domain", NULL);
1588  remmina_plugin_service->file_set_string(remminafile, "gateway_password", NULL);
1589  }
1590 
1591  /* Remote Desktop Gateway server address */
1592  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayEnabled, FALSE);
1593  s = remmina_plugin_service->file_get_string(remminafile, "gateway_server");
1594  if (s) {
1595  cs = remmina_plugin_service->file_get_string(remminafile, "gwtransp");
1596 #if FREERDP_CHECK_VERSION(2, 3, 1)
1597  if (remmina_plugin_service->file_get_int(remminafile, "websockets", FALSE))
1598  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpUseWebsockets, TRUE);
1599  else
1600  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpUseWebsockets, FALSE);
1601 #endif
1602  if (g_strcmp0(cs, "http") == 0) {
1603  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayRpcTransport, FALSE);
1604  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpTransport, TRUE);
1605  } else if (g_strcmp0(cs, "rpc") == 0) {
1606  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayRpcTransport, TRUE);
1607  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpTransport, FALSE);
1608  } else if (g_strcmp0(cs, "auto") == 0) {
1609  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayRpcTransport, TRUE);
1610  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayHttpTransport, TRUE);
1611  }
1612  remmina_plugin_service->get_server_port(s, 443, &gateway_host, &gateway_port);
1613  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayHostname, gateway_host);
1614  freerdp_settings_set_uint32(rfi->settings, FreeRDP_GatewayPort, gateway_port);
1615  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayEnabled, TRUE);
1616  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, TRUE);
1617  }
1618  /* Remote Desktop Gateway domain */
1619  if (remmina_plugin_service->file_get_string(remminafile, "gateway_domain")) {
1620  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayDomain, remmina_plugin_service->file_get_string(remminafile, "gateway_domain"));
1621  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, FALSE);
1622  }
1623  /* Remote Desktop Gateway username */
1624  if (remmina_plugin_service->file_get_string(remminafile, "gateway_username")) {
1625  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayUsername, remmina_plugin_service->file_get_string(remminafile, "gateway_username"));
1626  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, FALSE);
1627  }
1628  /* Remote Desktop Gateway password */
1629  s = remmina_plugin_service->file_get_string(remminafile, "gateway_password");
1630  if (s) {
1631  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayPassword, s);
1632  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, FALSE);
1633  }
1634  /* If no different credentials were provided for the Remote Desktop Gateway
1635  * use the same authentication credentials for the host */
1636  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_GatewayEnabled) && freerdp_settings_get_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials)) {
1637  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayDomain, freerdp_settings_get_string(rfi->settings, FreeRDP_Domain));
1638  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayUsername, freerdp_settings_get_string(rfi->settings, FreeRDP_Username));
1639  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayPassword, freerdp_settings_get_string(rfi->settings, FreeRDP_Password));
1640  }
1641  /* Remote Desktop Gateway usage */
1642  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_GatewayEnabled))
1643  freerdp_set_gateway_usage_method(rfi->settings,
1644  remmina_plugin_service->file_get_int(remminafile, "gateway_usage", FALSE) ? TSC_PROXY_MODE_DETECT : TSC_PROXY_MODE_DIRECT);
1645 
1646  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayAccessToken,
1647  remmina_plugin_service->file_get_string(remminafile, "gatewayaccesstoken"));
1648 
1649  freerdp_settings_set_uint32(rfi->settings, FreeRDP_AuthenticationLevel, remmina_plugin_service->file_get_int(
1650  remminafile, "authentication level", freerdp_settings_get_uint32(rfi->settings, FreeRDP_AuthenticationLevel)));
1651 
1652  /* Certificate ignore */
1653  freerdp_settings_set_bool(rfi->settings, FreeRDP_IgnoreCertificate, remmina_plugin_service->file_get_int(remminafile, "cert_ignore", 0));
1654  freerdp_settings_set_bool(rfi->settings, FreeRDP_OldLicenseBehaviour, remmina_plugin_service->file_get_int(remminafile, "old-license", 0));
1655  freerdp_settings_set_bool(rfi->settings, FreeRDP_AllowUnanouncedOrdersFromServer, remmina_plugin_service->file_get_int(remminafile, "relax-order-checks", 0));
1656  freerdp_settings_set_uint32(rfi->settings, FreeRDP_GlyphSupportLevel, (remmina_plugin_service->file_get_int(remminafile, "glyph-cache", 0) ? GLYPH_SUPPORT_FULL : GLYPH_SUPPORT_NONE));
1657 
1658  if ((cs = remmina_plugin_service->file_get_string(remminafile, "clientname")))
1659  freerdp_settings_set_string(rfi->settings, FreeRDP_ClientHostname, cs);
1660  else
1661  freerdp_settings_set_string(rfi->settings, FreeRDP_ClientHostname, g_get_host_name());
1662 
1663  /* Client Build number is optional, if not specified defaults to 0, allow for comments to appear after number */
1664  if ((cs = remmina_plugin_service->file_get_string(remminafile, "clientbuild"))) {
1665  if (*cs) {
1666  UINT32 val = strtoul(cs, NULL, 0);
1667  freerdp_settings_set_uint32(rfi->settings, FreeRDP_ClientBuild, val);
1668  }
1669  }
1670 
1671 
1672  if (remmina_plugin_service->file_get_string(remminafile, "loadbalanceinfo")) {
1673  char *tmp = strdup(remmina_plugin_service->file_get_string(remminafile, "loadbalanceinfo"));
1674  rfi->settings->LoadBalanceInfo = (BYTE *)tmp;
1675 
1676  freerdp_settings_set_uint32(rfi->settings, FreeRDP_LoadBalanceInfoLength, strlen(tmp));
1677  }
1678 
1679  if (remmina_plugin_service->file_get_string(remminafile, "exec"))
1680  freerdp_settings_set_string(rfi->settings, FreeRDP_AlternateShell, remmina_plugin_service->file_get_string(remminafile, "exec"));
1681 
1682  if (remmina_plugin_service->file_get_string(remminafile, "execpath"))
1683  freerdp_settings_set_string(rfi->settings, FreeRDP_ShellWorkingDirectory, remmina_plugin_service->file_get_string(remminafile, "execpath"));
1684 
1685  sm = g_strdup_printf("rdp_quality_%i", remmina_plugin_service->file_get_int(remminafile, "quality", DEFAULT_QUALITY_0));
1686  value = remmina_plugin_service->pref_get_value(sm);
1687  g_free(sm);
1688 
1689  if (value && value[0]) {
1690  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, strtoul(value, NULL, 16));
1691  } else {
1692  switch (remmina_plugin_service->file_get_int(remminafile, "quality", DEFAULT_QUALITY_0)) {
1693  case 9:
1694  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, DEFAULT_QUALITY_9);
1695  break;
1696 
1697  case 2:
1698  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, DEFAULT_QUALITY_2);
1699  break;
1700 
1701  case 1:
1702  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, DEFAULT_QUALITY_1);
1703  break;
1704 
1705  case 0:
1706  default:
1707  freerdp_settings_set_uint32(rfi->settings, FreeRDP_PerformanceFlags, DEFAULT_QUALITY_0);
1708  break;
1709  }
1710  }
1711  g_free(value);
1712 
1713  if ((cs = remmina_plugin_service->file_get_string(remminafile, "network"))) {
1714  guint32 type = 0;
1715 
1716  if (g_strcmp0(cs, "modem") == 0)
1717  type = CONNECTION_TYPE_MODEM;
1718  else if (g_strcmp0(cs, "broadband") == 0)
1719  type = CONNECTION_TYPE_BROADBAND_HIGH;
1720  else if (g_strcmp0(cs, "broadband-low") == 0)
1721  type = CONNECTION_TYPE_BROADBAND_LOW;
1722  else if (g_strcmp0(cs, "broadband-high") == 0)
1723  type = CONNECTION_TYPE_BROADBAND_HIGH;
1724  else if (g_strcmp0(cs, "wan") == 0)
1725  type = CONNECTION_TYPE_WAN;
1726  else if (g_strcmp0(cs, "lan") == 0)
1727  type = CONNECTION_TYPE_LAN;
1728  else if ((g_strcmp0(cs, "autodetect") == 0))
1729  type = CONNECTION_TYPE_AUTODETECT;
1730  else if ((g_strcmp0(cs, "none") == 0))
1731  type = REMMINA_CONNECTION_TYPE_NONE;
1732  else
1733  type = REMMINA_CONNECTION_TYPE_NONE;
1734 
1735  if (!remmina_rdp_set_connection_type(rfi->settings, type))
1736  REMMINA_PLUGIN_DEBUG("Network settings not set");
1737  }
1738 
1739  /* PerformanceFlags bitmask need also to be splitted into BOOL variables
1740  * like freerdp_settings_set_bool(rfi->settings, FreeRDP_DisableWallpaper, freerdp_settings_set_bool(rfi->settings, FreeRDP_AllowFontSmoothing…
1741  * or freerdp_get_param_bool() function will return the wrong value
1742  */
1743  freerdp_performance_flags_split(rfi->settings);
1744 
1745 #ifdef GDK_WINDOWING_X11
1746 #if FREERDP_CHECK_VERSION(2, 3, 0)
1747  rdp_kbd_remap = remmina_get_rdp_kbd_remap(remmina_plugin_service->file_get_string(remminafile, "keymap"));
1748  if (rdp_kbd_remap != NULL) {
1749  freerdp_settings_set_string(rfi->settings, FreeRDP_KeyboardRemappingList, rdp_kbd_remap);
1750  REMMINA_PLUGIN_DEBUG("rdp_keyboard_remapping_list: %s", rfi->settings->KeyboardRemappingList);
1751  g_free(rdp_kbd_remap);
1752  }
1753  else {
1754  freerdp_settings_set_string(rfi->settings, FreeRDP_KeyboardRemappingList, remmina_plugin_service->pref_get_value("rdp_kbd_remap"));
1755  REMMINA_PLUGIN_DEBUG("rdp_keyboard_remapping_list: %s", rfi->settings->KeyboardRemappingList);
1756  }
1757 #endif
1758 #endif
1759 
1760  freerdp_settings_set_uint32(rfi->settings, FreeRDP_KeyboardLayout, remmina_rdp_settings_get_keyboard_layout());
1761 
1762  if (remmina_plugin_service->file_get_int(remminafile, "console", FALSE))
1763  freerdp_settings_set_bool(rfi->settings, FreeRDP_ConsoleSession, TRUE);
1764 
1765  if (remmina_plugin_service->file_get_int(remminafile, "restricted-admin", FALSE)) {
1766  freerdp_settings_set_bool(rfi->settings, FreeRDP_ConsoleSession, TRUE);
1767  freerdp_settings_set_bool(rfi->settings, FreeRDP_RestrictedAdminModeRequired, TRUE);
1768  }
1769 
1770  if (remmina_plugin_service->file_get_string(remminafile, "pth")) {
1771  freerdp_settings_set_bool(rfi->settings, FreeRDP_ConsoleSession, TRUE);
1772  freerdp_settings_set_bool(rfi->settings, FreeRDP_RestrictedAdminModeRequired, TRUE);
1773  freerdp_settings_set_string(rfi->settings, FreeRDP_PasswordHash, remmina_plugin_service->file_get_string(remminafile, "pth"));
1774  remmina_plugin_service->file_set_int(remminafile, "restricted-admin", TRUE);
1775  }
1776 
1777  cs = remmina_plugin_service->file_get_string(remminafile, "security");
1778  if (g_strcmp0(cs, "rdp") == 0) {
1779  freerdp_settings_set_bool(rfi->settings, FreeRDP_RdpSecurity, TRUE);
1780  freerdp_settings_set_bool(rfi->settings, FreeRDP_TlsSecurity, FALSE);
1781  freerdp_settings_set_bool(rfi->settings, FreeRDP_NlaSecurity, FALSE);
1782  freerdp_settings_set_bool(rfi->settings, FreeRDP_ExtSecurity, FALSE);
1783  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseRdpSecurityLayer, TRUE);
1784  } else if (g_strcmp0(cs, "tls") == 0) {
1785  freerdp_settings_set_bool(rfi->settings, FreeRDP_RdpSecurity, FALSE);
1786  freerdp_settings_set_bool(rfi->settings, FreeRDP_TlsSecurity, TRUE);
1787  freerdp_settings_set_bool(rfi->settings, FreeRDP_NlaSecurity, FALSE);
1788  freerdp_settings_set_bool(rfi->settings, FreeRDP_ExtSecurity, FALSE);
1789  } else if (g_strcmp0(cs, "nla") == 0) {
1790  freerdp_settings_set_bool(rfi->settings, FreeRDP_RdpSecurity, FALSE);
1791  freerdp_settings_set_bool(rfi->settings, FreeRDP_TlsSecurity, FALSE);
1792  freerdp_settings_set_bool(rfi->settings, FreeRDP_NlaSecurity, TRUE);
1793  freerdp_settings_set_bool(rfi->settings, FreeRDP_ExtSecurity, FALSE);
1794  } else if (g_strcmp0(cs, "ext") == 0) {
1795  freerdp_settings_set_bool(rfi->settings, FreeRDP_RdpSecurity, FALSE);
1796  freerdp_settings_set_bool(rfi->settings, FreeRDP_TlsSecurity, FALSE);
1797  freerdp_settings_set_bool(rfi->settings, FreeRDP_NlaSecurity, FALSE);
1798  freerdp_settings_set_bool(rfi->settings, FreeRDP_ExtSecurity, TRUE);
1799  } else {
1800  /* This is "-nego" switch of xfreerdp */
1801  freerdp_settings_set_bool(rfi->settings, FreeRDP_NegotiateSecurityLayer, TRUE);
1802  }
1803 
1804  cs = remmina_plugin_service->file_get_string(remminafile, "tls-seclevel");
1805  if (cs && g_strcmp0(cs,"")!=0) {
1806  i = atoi(cs);
1807  freerdp_settings_set_uint32(rfi->settings, FreeRDP_TlsSecLevel, i);
1808  }
1809 
1810  freerdp_settings_set_bool(rfi->settings, FreeRDP_CompressionEnabled, TRUE);
1811  if (remmina_plugin_service->file_get_int(remminafile, "disable_fastpath", FALSE)) {
1812  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathInput, FALSE);
1813  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathOutput, FALSE);
1814  } else {
1815  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathInput, TRUE);
1816  freerdp_settings_set_bool(rfi->settings, FreeRDP_FastPathOutput, TRUE);
1817  }
1818 
1819  /* Orientation and scaling settings */
1820  remmina_rdp_settings_get_orientation_scale_prefs(&desktopOrientation, &desktopScaleFactor, &deviceScaleFactor);
1821 
1822  freerdp_settings_set_uint16(rfi->settings, FreeRDP_DesktopOrientation, desktopOrientation);
1823  if (desktopScaleFactor != 0 && deviceScaleFactor != 0) {
1824  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopScaleFactor, desktopScaleFactor);
1825  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DeviceScaleFactor, deviceScaleFactor);
1826  }
1827 
1828  /* Try to enable "Display Control Virtual Channel Extension", needed to
1829  * dynamically resize remote desktop. This will automatically open
1830  * the "disp" dynamic channel, if available */
1831  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportDisplayControl, TRUE);
1832 
1833  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_SupportDisplayControl)) {
1834  CLPARAM *d[1];
1835  int dcount;
1836 
1837  dcount = 1;
1838  d[0] = "disp";
1839  freerdp_client_add_dynamic_channel(rfi->settings, dcount, d);
1840  }
1841 
1842  if (freerdp_settings_get_bool(rfi->settings, FreeRDP_SupportGraphicsPipeline)) {
1843  CLPARAM *d[1];
1844 
1845  int dcount;
1846 
1847  dcount = 1;
1848  d[0] = "rdpgfx";
1849  freerdp_client_add_dynamic_channel(rfi->settings, dcount, d);
1850  }
1851 
1852  /* Sound settings */
1853  cs = remmina_plugin_service->file_get_string(remminafile, "sound");
1854  if (g_strcmp0(cs, "remote") == 0) {
1855  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteConsoleAudio, TRUE);
1856  } else if (g_str_has_prefix(cs, "local")) {
1857  freerdp_settings_set_bool(rfi->settings, FreeRDP_AudioPlayback, TRUE);
1858  freerdp_settings_set_bool(rfi->settings, FreeRDP_AudioCapture, TRUE);
1859  } else {
1860  /* Disable sound */
1861  freerdp_settings_set_bool(rfi->settings, FreeRDP_AudioPlayback, FALSE);
1862  freerdp_settings_set_bool(rfi->settings, FreeRDP_RemoteConsoleAudio, FALSE);
1863  }
1864 
1865  cs = remmina_plugin_service->file_get_string(remminafile, "microphone");
1866  if (cs != NULL && cs[0] != '\0') {
1867  if (g_strcmp0(cs, "0") == 0) {
1868  REMMINA_PLUGIN_DEBUG("“microphone” was set to 0, setting to \"\"");
1869  remmina_plugin_service->file_set_string(remminafile, "microphone", "");
1870  } else {
1871  freerdp_settings_set_bool(rfi->settings, FreeRDP_AudioCapture, TRUE);
1872  REMMINA_PLUGIN_DEBUG("“microphone” set to “%s”", cs);
1873  CLPARAM **p;
1874  size_t count;
1875 
1876  p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("audin", g_strdup(cs), &count);
1877 
1878  freerdp_client_add_dynamic_channel(rfi->settings, count, p);
1879  g_free(p);
1880  }
1881  }
1882 
1883  cs = remmina_plugin_service->file_get_string(remminafile, "audio-output");
1884  if (cs != NULL && cs[0] != '\0') {
1885  REMMINA_PLUGIN_DEBUG("audio output set to %s", cs);
1886  CLPARAM **p;
1887  size_t count;
1888 
1889  p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("rdpsnd", g_strdup(cs), &count);
1890  status = freerdp_client_add_static_channel(rfi->settings, count, p);
1891  if (status)
1892  status = freerdp_client_add_dynamic_channel(rfi->settings, count, p);
1893  g_free(p);
1894  }
1895 
1896 
1897  cs = remmina_plugin_service->file_get_string(remminafile, "freerdp_log_level");
1898  if (cs != NULL && cs[0] != '\0')
1899  REMMINA_PLUGIN_DEBUG("Log level set to to %s", cs);
1900  else
1901  cs = g_strdup("INFO");
1902  wLog *root = WLog_GetRoot();
1903  WLog_SetStringLogLevel(root, cs);
1904 
1905  cs = remmina_plugin_service->file_get_string(remminafile, "freerdp_log_filters");
1906  if (cs != NULL && cs[0] != '\0') {
1907  REMMINA_PLUGIN_DEBUG("Log filters set to to %s", cs);
1908  WLog_AddStringLogFilters(cs);
1909  } else {
1910  WLog_AddStringLogFilters(NULL);
1911  }
1912 
1913 
1914  cs = remmina_plugin_service->file_get_string(remminafile, "usb");
1915  if (cs != NULL && cs[0] != '\0') {
1916  CLPARAM **p;
1917  size_t count;
1918  p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("urbdrc", g_strdup(cs), &count);
1919  freerdp_client_add_dynamic_channel(rfi->settings, count, p);
1920  g_free(p);
1921  }
1922 
1923  cs = remmina_plugin_service->file_get_string(remminafile, "vc");
1924  if (cs != NULL && cs[0] != '\0') {
1925  CLPARAM **p;
1926  size_t count;
1927  p = remmina_rdp_CommandLineParseCommaSeparatedValues(g_strdup(cs), &count);
1928  freerdp_client_add_static_channel(rfi->settings, count, p);
1929  g_free(p);
1930  }
1931 
1932  cs = remmina_plugin_service->file_get_string(remminafile, "dvc");
1933  if (cs != NULL && cs[0] != '\0') {
1934  CLPARAM **p;
1935  size_t count;
1936  p = remmina_rdp_CommandLineParseCommaSeparatedValues(g_strdup(cs), &count);
1937  freerdp_client_add_dynamic_channel(rfi->settings, count, p);
1938  g_free(p);
1939  }
1940 
1941  cs = remmina_plugin_service->file_get_string(remminafile, "rdp2tcp");
1942  if (cs != NULL && cs[0] != '\0') {
1943  g_free(rfi->settings->RDP2TCPArgs);
1944  rfi->settings->RDP2TCPArgs = g_strdup(cs);
1945  REMMINA_PLUGIN_DEBUG("rdp2tcp set to %s", rfi->settings->RDP2TCPArgs);
1946  remmina_rdp_load_static_channel_addin(channels, rfi->settings, "rdp2tcp", rfi->settings->RDP2TCPArgs);
1947  }
1948 
1949  int vermaj, vermin, verrev;
1950  freerdp_get_version(&vermaj, &vermin, &verrev);
1951 
1952 #if FREERDP_CHECK_VERSION(2, 1, 0)
1953  cs = remmina_plugin_service->file_get_string(remminafile, "timeout");
1954  if (cs != NULL && cs[0] != '\0') {
1955  const gchar *endptr = NULL;
1956  guint64 val = g_ascii_strtoull(cs, (gchar **)&endptr, 10);
1957  if (val > 600000 || val <= 0)
1958  val = 600000;
1959  freerdp_settings_set_uint32(rfi->settings, FreeRDP_TcpAckTimeout, (UINT32)val);
1960  }
1961 #endif
1962 
1963  if (remmina_plugin_service->file_get_int(remminafile, "preferipv6", FALSE) ? TRUE : FALSE)
1964  freerdp_settings_set_bool(rfi->settings, FreeRDP_PreferIPv6OverIPv4, TRUE);
1965 
1966  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectClipboard, remmina_plugin_service->file_get_int(remminafile, "disableclipboard", FALSE) ? FALSE : TRUE);
1967 
1968  cs = remmina_plugin_service->file_get_string(remminafile, "sharefolder");
1969  if (cs != NULL && cs[0] != '\0') {
1970  gchar *ccs = g_strdup(cs);
1971  REMMINA_PLUGIN_DEBUG("[Deprecated->migrating] - Old sharefolder %s to \"drive \"", ccs);
1972  if (!remmina_plugin_service->file_get_string(remminafile, "drive")) {
1973  remmina_plugin_service->file_set_string(remminafile, "drive", g_strdup(ccs));
1974  remmina_plugin_service->file_set_string(remminafile, "sharefolder", NULL);
1975  REMMINA_PLUGIN_DEBUG("[Deprecated->migrated] - drive set to %s", g_strdup(ccs));
1976  }
1977  g_free(ccs);
1978  //CLPARAM **p;
1979  //size_t count;
1980  //p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("drive", g_strdup(cs), &count);
1981  //status = freerdp_client_add_device_channel(rfi->settings, count, p);
1982  //g_free(p);
1983  }
1984  cs = remmina_plugin_service->file_get_string(remminafile, "drive");
1985  if (cs != NULL && cs[0] != '\0') {
1986  REMMINA_PLUGIN_DEBUG("Redirect directory set to %s", cs);
1987  CLPARAM **p;
1988  size_t count;
1989 
1990  gchar **folders = g_strsplit(cs, ";", -1);
1991  for (i = 0; folders[i] != NULL; i++) {
1992  REMMINA_PLUGIN_DEBUG("Parsing folder %s", folders[i]);
1993  p = remmina_rdp_CommandLineParseCommaSeparatedValuesEx("drive", g_strdup(folders[i]), &count);
1994  status = freerdp_client_add_device_channel(rfi->settings, count, p);
1995  g_free(p);
1996  }
1997  g_strfreev(folders);
1998  }
1999 
2000  if (remmina_plugin_service->file_get_int(remminafile, "shareprinter", FALSE)) {
2001 #ifdef HAVE_CUPS
2002  REMMINA_PLUGIN_DEBUG("Sharing printers");
2003  const gchar *po = remmina_plugin_service->file_get_string(remminafile, "printer_overrides");
2004  if (po && po[0] != 0) {
2005  /* Fallback to remmina code to override print drivers */
2006  if (cupsEnumDests(CUPS_DEST_FLAGS_NONE, 1000, NULL, 0, 0, remmina_rdp_set_printers, rfi))
2007  REMMINA_PLUGIN_DEBUG("All printers have been shared");
2008  else
2009  REMMINA_PLUGIN_DEBUG("Cannot share printers, are there any available?");
2010  } else {
2011  /* Use libfreerdp code to map all printers */
2012  CLPARAM *d[1];
2013  int dcount;
2014  dcount = 1;
2015  d[0] = "printer";
2016  freerdp_client_add_device_channel(rfi->settings, dcount, d);
2017  }
2018 #endif /* HAVE_CUPS */
2019  }
2020 
2021  if (remmina_plugin_service->file_get_int(remminafile, "span", FALSE)) {
2022  freerdp_settings_set_bool(rfi->settings, FreeRDP_SpanMonitors, TRUE);
2023  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseMultimon, TRUE);
2024  freerdp_settings_set_bool(rfi->settings, FreeRDP_Fullscreen, TRUE);
2025  remmina_plugin_service->file_set_int(remminafile, "multimon", 1);
2026  }
2027 
2028  if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) {
2029  guint32 maxwidth = 0;
2030  guint32 maxheight = 0;
2031  gchar *monitorids;
2032  guint32 i;
2033  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseMultimon, TRUE);
2034  /* TODO Add an option for this */
2035  freerdp_settings_set_bool(rfi->settings, FreeRDP_ForceMultimon, TRUE);
2036  freerdp_settings_set_bool(rfi->settings, FreeRDP_Fullscreen, TRUE);
2037 
2038  gchar *monitorids_string = g_strdup(remmina_plugin_service->file_get_string(remminafile, "monitorids"));
2039  /* Otherwise we get all the attached monitors
2040  * monitorids may contains desktop orientation values.
2041  * But before we check if there are orientation attributes
2042  */
2043  if (monitorids_string != NULL && monitorids_string[0] != '\0') {
2044  if (g_strstr_len(monitorids_string, -1, ",") != NULL) {
2045  if (g_strstr_len(monitorids_string, -1, ":") != NULL) {
2046  rdpMonitor *base = (rdpMonitor *)freerdp_settings_get_pointer(rfi->settings, FreeRDP_MonitorDefArray);
2047  /* We have an ID and an orientation degree */
2048  gchar **temp_items;
2049  gchar **rot_items;
2050  temp_items = g_strsplit(monitorids_string, ",", -1);
2051  for (i = 0; i < g_strv_length(temp_items); i++) {
2052  rot_items = g_strsplit(temp_items[i], ":", -1);
2053  rdpMonitor *current = &base[atoi(rot_items[0])];
2054  if (i == 0)
2055  monitorids = g_strdup(rot_items[0]);
2056  else
2057  monitorids = g_strdup_printf("%s,%s", monitorids, rot_items[0]);
2058  current->attributes.orientation = atoi(rot_items[1]);
2059  REMMINA_PLUGIN_DEBUG("Monitor n %d orientation: %d", i, current->attributes.orientation);
2060  }
2061  } else {
2062  monitorids = g_strdup(monitorids_string);
2063  }
2064  } else {
2065  monitorids = g_strdup(monitorids_string);
2066  }
2067  } else {
2068  monitorids = g_strdup(monitorids_string);
2069  }
2070  remmina_rdp_monitor_get(rfi, &monitorids, &maxwidth, &maxheight);
2071  if (monitorids != NULL && monitorids[0] != '\0') {
2072  UINT32 *base = (UINT32 *)freerdp_settings_get_pointer(rfi->settings, FreeRDP_MonitorIds);
2073  gchar **items;
2074  items = g_strsplit(monitorids, ",", -1);
2075  freerdp_settings_set_uint32(rfi->settings, FreeRDP_NumMonitorIds, g_strv_length(items));
2076  REMMINA_PLUGIN_DEBUG("NumMonitorIds: %d", freerdp_settings_get_uint32(rfi->settings, FreeRDP_NumMonitorIds));
2077  for (i = 0; i < g_strv_length(items); i++) {
2078  UINT32 *current = &base[i];
2079  *current = atoi(items[i]);
2080  REMMINA_PLUGIN_DEBUG("Added monitor with ID %" PRIu32, *current);
2081  }
2082  g_free(monitorids);
2083  g_strfreev(items);
2084  }
2085  if (maxwidth && maxheight) {
2086  REMMINA_PLUGIN_DEBUG("Setting DesktopWidth and DesktopHeight to: %dx%d", maxwidth, maxheight);
2087  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopWidth, maxwidth);
2088  freerdp_settings_set_uint32(rfi->settings, FreeRDP_DesktopHeight, maxheight);
2089  REMMINA_PLUGIN_DEBUG("DesktopWidth and DesktopHeight set to: %dx%d", freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth), freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight));
2090  } else {
2091  REMMINA_PLUGIN_DEBUG("Cannot set Desktop Size, we are using the previously set values: %dx%d", freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth), freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight));
2092  }
2093  remmina_plugin_service->protocol_plugin_set_width(gp, freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopWidth));
2094  remmina_plugin_service->protocol_plugin_set_height(gp, freerdp_settings_get_uint32(rfi->settings, FreeRDP_DesktopHeight));
2095  }
2096 
2097  const gchar *sn = remmina_plugin_service->file_get_string(remminafile, "smartcardname");
2098  if (remmina_plugin_service->file_get_int(remminafile, "sharesmartcard", FALSE) ||
2099  (sn != NULL && sn[0] != '\0')) {
2100  RDPDR_SMARTCARD *smartcard;
2101  smartcard = (RDPDR_SMARTCARD *)calloc(1, sizeof(RDPDR_SMARTCARD));
2102 
2103 #ifdef WITH_FREERDP3
2104  RDPDR_DEVICE *sdev;
2105  sdev = &(smartcard->device);
2106 #else
2107  RDPDR_SMARTCARD *sdev;
2108  sdev = smartcard;
2109 #endif
2110 
2111  sdev->Type = RDPDR_DTYP_SMARTCARD;
2112 
2113  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
2114 
2115  if (sn != NULL && sn[0] != '\0')
2116  sdev->Name = _strdup(sn);
2117 
2118  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectSmartCards, TRUE);
2119 
2120  freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)smartcard);
2121  }
2122 
2123  if (remmina_plugin_service->file_get_int(remminafile, "passwordispin", FALSE))
2124  /* Option works only combined with Username and Domain, because FreeRDP
2125  * doesn’t know anything about info on smart card */
2126  freerdp_settings_set_bool(rfi->settings, FreeRDP_PasswordIsSmartcardPin, TRUE);
2127 
2128  /* /serial[:<name>[,<path>[,<driver>[,permissive]]]] */
2129  if (remmina_plugin_service->file_get_int(remminafile, "shareserial", FALSE)) {
2130  RDPDR_SERIAL *serial;
2131  serial = (RDPDR_SERIAL *)calloc(1, sizeof(RDPDR_SERIAL));
2132 
2133 #ifdef WITH_FREERDP3
2134  RDPDR_DEVICE *sdev;
2135  sdev = &(serial->device);
2136 #else
2137  RDPDR_SERIAL *sdev;
2138  sdev = serial;
2139 #endif
2140 
2141  sdev->Type = RDPDR_DTYP_SERIAL;
2142 
2143  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
2144 
2145  const gchar *sn = remmina_plugin_service->file_get_string(remminafile, "serialname");
2146  if (sn != NULL && sn[0] != '\0')
2147  sdev->Name = _strdup(sn);
2148 
2149  const gchar *sd = remmina_plugin_service->file_get_string(remminafile, "serialdriver");
2150  if (sd != NULL && sd[0] != '\0')
2151  serial->Driver = _strdup(sd);
2152 
2153  const gchar *sp = remmina_plugin_service->file_get_string(remminafile, "serialpath");
2154  if (sp != NULL && sp[0] != '\0')
2155  serial->Path = _strdup(sp);
2156 
2157  if (remmina_plugin_service->file_get_int(remminafile, "serialpermissive", FALSE))
2158  serial->Permissive = _strdup("permissive");
2159 
2160  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectSerialPorts, TRUE);
2161 
2162  freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)serial);
2163  }
2164 
2165  if (remmina_plugin_service->file_get_int(remminafile, "shareparallel", FALSE)) {
2166  RDPDR_PARALLEL *parallel;
2167  parallel = (RDPDR_PARALLEL *)calloc(1, sizeof(RDPDR_PARALLEL));
2168 
2169 #ifdef WITH_FREERDP3
2170  RDPDR_DEVICE *pdev;
2171  pdev = &(parallel->device);
2172 #else
2173  RDPDR_PARALLEL *pdev;
2174  pdev = parallel;
2175 #endif
2176 
2177  pdev->Type = RDPDR_DTYP_PARALLEL;
2178 
2179  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
2180 
2181  freerdp_settings_set_bool(rfi->settings, FreeRDP_RedirectParallelPorts, TRUE);
2182 
2183  const gchar *pn = remmina_plugin_service->file_get_string(remminafile, "parallelname");
2184  if (pn != NULL && pn[0] != '\0')
2185  pdev->Name = _strdup(pn);
2186  const gchar *dp = remmina_plugin_service->file_get_string(remminafile, "parallelpath");
2187  if (dp != NULL && dp[0] != '\0')
2188  parallel->Path = _strdup(dp);
2189 
2190  freerdp_device_collection_add(rfi->settings, (RDPDR_DEVICE *)parallel);
2191  }
2192 
2196  if (remmina_plugin_service->file_get_int(remminafile, "multitransport", FALSE)) {
2197  freerdp_settings_set_bool(rfi->settings, FreeRDP_DeviceRedirection, TRUE);
2198  freerdp_settings_set_bool(rfi->settings, FreeRDP_SupportMultitransport, TRUE);
2199  freerdp_settings_set_uint32(rfi->settings, FreeRDP_MultitransportFlags,
2200  (TRANSPORT_TYPE_UDP_FECR | TRANSPORT_TYPE_UDP_FECL | TRANSPORT_TYPE_UDP_PREFERRED));
2201  } else {
2202  freerdp_settings_set_uint32(rfi->settings, FreeRDP_MultitransportFlags, 0);
2203  }
2204 
2205  /* If needed, force interactive authentication by deleting all authentication fields,
2206  * forcing libfreerdp to call our callbacks for authentication.
2207  * This usually happens from a second attempt of connection, never on the 1st one. */
2209  freerdp_settings_set_string(rfi->settings, FreeRDP_Username, NULL);
2210  freerdp_settings_set_string(rfi->settings, FreeRDP_Password, NULL);
2211  freerdp_settings_set_string(rfi->settings, FreeRDP_Domain, NULL);
2212 
2213  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayDomain, NULL);
2214  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayUsername, NULL);
2215  freerdp_settings_set_string(rfi->settings, FreeRDP_GatewayPassword, NULL);
2216 
2217  freerdp_settings_set_bool(rfi->settings, FreeRDP_GatewayUseSameCredentials, FALSE);
2218  }
2219 
2220  gboolean orphaned;
2221 
2222  if (!freerdp_connect(rfi->instance)) {
2223  orphaned = (GET_PLUGIN_DATA(rfi->protocol_widget) == NULL);
2224  if (!orphaned) {
2225  UINT32 e;
2226 
2227  e = freerdp_get_last_error(rfi->instance->context);
2228 
2229  switch (e) {
2230  case FREERDP_ERROR_AUTHENTICATION_FAILED:
2231  case STATUS_LOGON_FAILURE: // wrong return code from FreeRDP introduced at the end of July 2016? (fixed with b86c0ba)
2232 #ifdef FREERDP_ERROR_CONNECT_LOGON_FAILURE
2233  case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
2234 #endif
2235  /* Logon failure, will retry with interactive authentication */
2237  break;
2238  case STATUS_ACCOUNT_LOCKED_OUT:
2239 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT
2240  case FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT:
2241 #endif
2242  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nAccount locked out."),
2243  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2244  break;
2245  case STATUS_ACCOUNT_EXPIRED:
2246 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED
2247  case FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED:
2248 #endif
2249  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nAccount expired."),
2250  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2251  break;
2252  case STATUS_PASSWORD_EXPIRED:
2253 #ifdef FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED
2254  case FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED:
2255 #endif
2256  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nPassword expired."),
2257  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2258  break;
2259  case STATUS_ACCOUNT_DISABLED:
2260 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED
2261  case FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED:
2262 #endif
2263  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nAccount disabled."),
2264  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2265  break;
2266 #ifdef FREERDP_ERROR_SERVER_INSUFFICIENT_PRIVILEGES
2267  /* https://msdn.microsoft.com/en-us/library/ee392247.aspx */
2268  case FREERDP_ERROR_SERVER_INSUFFICIENT_PRIVILEGES:
2269  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nInsufficient user privileges."),
2270  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2271  break;
2272 #endif
2273  case STATUS_ACCOUNT_RESTRICTION:
2274 #ifdef FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION
2275  case FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION:
2276 #endif
2277  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nAccount restricted."),
2278  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2279  break;
2280 
2281  case STATUS_PASSWORD_MUST_CHANGE:
2282 #ifdef FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE
2283  case FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE:
2284 #endif
2285  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not access the RDP server “%s”.\nChange user password before connecting."),
2286  freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2287  break;
2288 
2289  case FREERDP_ERROR_CONNECT_FAILED:
2290  remmina_plugin_service->protocol_plugin_set_error(gp, _("Lost connection to the RDP server “%s”."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2291  break;
2292  case FREERDP_ERROR_DNS_NAME_NOT_FOUND:
2293  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not find the address for the RDP server “%s”."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2294  break;
2295  case FREERDP_ERROR_TLS_CONNECT_FAILED:
2296  remmina_plugin_service->protocol_plugin_set_error(gp,
2297  _("Could not connect to the RDP server “%s” via TLS. See the DEBUG traces from a terminal for more information."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2298  break;
2299  case FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED:
2300  // TRANSLATORS: the placeholder may be either an IP/FQDN or a server hostname
2301  remmina_plugin_service->protocol_plugin_set_error(gp, _("Unable to establish a connection to the RDP server “%s”. Check “Security protocol negotiation”."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2302  break;
2303 #ifdef FREERDP_ERROR_POST_CONNECT_FAILED
2304  case FREERDP_ERROR_POST_CONNECT_FAILED:
2305  /* remmina_rdp_post_connect() returned FALSE to libfreerdp. We saved the error on rfi->postconnect_error */
2306  switch (rfi->postconnect_error) {
2307  case REMMINA_POSTCONNECT_ERROR_OK:
2308  /* We should never come here */
2309  remmina_plugin_service->protocol_plugin_set_error(gp, _("Cannot connect to the RDP server “%s”."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2310  break;
2311  case REMMINA_POSTCONNECT_ERROR_GDI_INIT:
2312  remmina_plugin_service->protocol_plugin_set_error(gp, _("Could not start libfreerdp-gdi."));
2313  break;
2314  case REMMINA_POSTCONNECT_ERROR_NO_H264:
2315  remmina_plugin_service->protocol_plugin_set_error(gp, _("You requested a H.264 GFX mode for the server “%s”, but your libfreerdp does not support H.264. Please use a non-AVC colour depth setting."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2316  break;
2317  }
2318  break;
2319 #endif
2320 #ifdef FREERDP_ERROR_SERVER_DENIED_CONNECTION
2321  case FREERDP_ERROR_SERVER_DENIED_CONNECTION:
2322  remmina_plugin_service->protocol_plugin_set_error(gp, _("The “%s” server refused the connection."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2323  break;
2324 #endif
2325  case 0x800759DB:
2326  // E_PROXY_NAP_ACCESSDENIED https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tsgu/84cd92e4-592c-4219-95d8-18021ac654b0
2327  remmina_plugin_service->protocol_plugin_set_error(gp, _("The Remote Desktop Gateway “%s” denied the user “%s\\%s” access due to policy."),
2328  freerdp_settings_get_string(rfi->settings, FreeRDP_GatewayHostname), freerdp_settings_get_string(rfi->settings, FreeRDP_GatewayDomain), freerdp_settings_get_string(rfi->settings, FreeRDP_GatewayUsername));
2329  break;
2330 
2331  case FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS:
2332  rfi->user_cancelled = TRUE;
2333  break;
2334 
2335  default:
2336  g_printf("libfreerdp returned code is %08X\n", e);
2337  remmina_plugin_service->protocol_plugin_set_error(gp, _("Cannot connect to the “%s” RDP server."), freerdp_settings_get_string(rfi->settings, FreeRDP_ServerHostname));
2338  break;
2339  }
2340  }
2341 
2342  return FALSE;
2343  }
2344 
2345  if (GET_PLUGIN_DATA(rfi->protocol_widget) == NULL) orphaned = true; else orphaned = false;
2346  if (!orphaned && freerdp_get_last_error(rfi->instance->context) == FREERDP_ERROR_SUCCESS && !rfi->user_cancelled)
2348 
2349  return TRUE;
2350 }
2351 
2352 static void rfi_uninit(rfContext *rfi)
2353 {
2354  freerdp *instance;
2355 
2356  instance = rfi->instance;
2357 
2358  if (rfi->remmina_plugin_thread) {
2359  rfi->thread_cancelled = TRUE; // Avoid all rf_queue function to run
2360  pthread_cancel(rfi->remmina_plugin_thread);
2361  if (rfi->remmina_plugin_thread)
2362  pthread_join(rfi->remmina_plugin_thread, NULL);
2363  }
2364 
2365  if (instance) {
2366  if (rfi->connected) {
2367  freerdp_abort_connect(instance);
2368  rfi->connected = false;
2369  }
2370  }
2371 
2372  if (instance) {
2373  RDP_CLIENT_ENTRY_POINTS *pEntryPoints = instance->pClientEntryPoints;
2374  if (pEntryPoints)
2375  IFCALL(pEntryPoints->GlobalUninit);
2376  free(instance->pClientEntryPoints);
2377  freerdp_context_free(instance); /* context is rfContext* rfi */
2378  freerdp_free(instance); /* This implicitly frees instance->context and rfi is no longer valid */
2379  }
2380 }
2381 
2382 static gboolean complete_cleanup_on_main_thread(gpointer data)
2383 {
2384  TRACE_CALL(__func__);
2385 
2386  gboolean orphaned;
2387  rfContext *rfi = (rfContext *)data;
2389 
2391 
2392  gdi_free(rfi->instance);
2393 
2394  gp = rfi->protocol_widget;
2395  if (GET_PLUGIN_DATA(gp) == NULL) orphaned = true; else orphaned = false;
2396 
2398  if (!orphaned) remmina_rdp_event_uninit(gp);
2399 
2400  if (!orphaned) g_object_steal_data(G_OBJECT(gp), "plugin-data");
2401 
2402  rfi_uninit(rfi);
2403 
2404  /* Notify the RemminaProtocolWidget that we closed our connection, and the GUI interface
2405  * can be removed */
2406  if (!orphaned)
2407  remmina_plugin_service->protocol_plugin_signal_connection_closed(gp);
2408 
2409  return G_SOURCE_REMOVE;
2410 }
2411 
2412 static gpointer remmina_rdp_main_thread(gpointer data)
2413 {
2414  TRACE_CALL(__func__);
2416  rfContext *rfi;
2417 
2418  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
2419  CANCEL_ASYNC
2420 
2421  gp = (RemminaProtocolWidget *)data;
2422 
2423  rfi = GET_PLUGIN_DATA(gp);
2424 
2426  do
2427  remmina_rdp_main(gp);
2428  while (!remmina_plugin_service->protocol_plugin_has_error(gp) && rfi->attempt_interactive_authentication == TRUE && !rfi->user_cancelled);
2429 
2430  rfi->remmina_plugin_thread = 0;
2431 
2432  /* cleanup */
2433  g_idle_add(complete_cleanup_on_main_thread, (gpointer)rfi);
2434 
2435 
2436  return NULL;
2437 }
2438 
2440 {
2441  TRACE_CALL(__func__);
2442  freerdp *instance;
2443  rfContext *rfi;
2444 
2445  instance = freerdp_new();
2446  instance->PreConnect = remmina_rdp_pre_connect;
2447  instance->PostConnect = remmina_rdp_post_connect;
2448  instance->PostDisconnect = remmina_rdp_post_disconnect;
2449  instance->Authenticate = remmina_rdp_authenticate;
2450  instance->GatewayAuthenticate = remmina_rdp_gw_authenticate;
2451  //instance->VerifyCertificate = remmina_rdp_verify_certificate;
2452  instance->VerifyCertificateEx = remmina_rdp_verify_certificate_ex;
2453  //instance->VerifyChangedCertificate = remmina_rdp_verify_changed_certificate;
2454  instance->VerifyChangedCertificateEx = remmina_rdp_verify_changed_certificate_ex;
2455 
2456  instance->ContextSize = sizeof(rfContext);
2457  freerdp_context_new(instance);
2458  rfi = (rfContext *)instance->context;
2459 
2460  g_object_set_data_full(G_OBJECT(gp), "plugin-data", rfi, free);
2461 
2462  rfi->protocol_widget = gp;
2463  rfi->instance = instance;
2464  rfi->settings = instance->settings;
2465  rfi->connected = false;
2466  rfi->is_reconnecting = false;
2467  rfi->stop_reconnecting_requested = false;
2468  rfi->user_cancelled = FALSE;
2469  rfi->last_x = 0;
2470  rfi->last_y = 0;
2471 
2472  freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0);
2473 
2475 }
2476 
2478 {
2479  TRACE_CALL(__func__);
2480  rfContext *rfi = GET_PLUGIN_DATA(gp);
2481  RemminaFile *remminafile;
2482  const gchar *profile_name, *p;
2483  gchar thname[16], c;
2484  gint nthname = 0;
2485 
2486  rfi->scale = remmina_plugin_service->remmina_protocol_widget_get_current_scale_mode(gp);
2487 
2488  remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
2489 
2490 
2491  if (pthread_create(&rfi->remmina_plugin_thread, NULL, remmina_rdp_main_thread, gp)) {
2492  remmina_plugin_service->protocol_plugin_set_error(gp, "%s",
2493  "Could not start pthread.");
2494 
2495  rfi->remmina_plugin_thread = 0;
2496 
2497  return FALSE;
2498  }
2499 
2500  /* Generate a thread name to be used with pthread_setname_np() for debugging */
2501  profile_name = remmina_plugin_service->file_get_string(remminafile, "name");
2502  p = profile_name;
2503  strcpy(thname, "RemmRDP:");
2504  if (p) {
2505  nthname = strlen(thname);
2506  while ((c = *p) != 0 && nthname < sizeof(thname) - 1) {
2507  if (isalnum(c))
2508  thname[nthname++] = c;
2509  p++;
2510  }
2511  } else {
2512  strcat(thname, "<NONAM>");
2513  nthname = strlen(thname);
2514  }
2515  thname[nthname] = 0;
2516 #if defined(__linux__)
2517  pthread_setname_np(rfi->remmina_plugin_thread, thname);
2518 #elif defined(__FreeBSD__)
2519  pthread_set_name_np(rfi->remmina_plugin_thread, thname);
2520 #endif
2521 
2522  return TRUE;
2523 }
2524 
2526 {
2527  TRACE_CALL(__func__);
2528 
2529  REMMINA_PLUGIN_DEBUG("Requesting to close the connection");
2530  RemminaPluginRdpEvent rdp_event = { 0 };
2531  rfContext *rfi = GET_PLUGIN_DATA(gp);
2532 
2533  if (!remmina_plugin_service->is_main_thread())
2534  g_warning("WARNING: %s called on a subthread, which may not work or crash Remmina.", __func__);
2535 
2536  if (rfi && !rfi->connected) {
2537  /* libfreerdp is attempting to connect, we cannot interrupt our main thread
2538  * in the connect phase.
2539  * So we remove "plugin-data" from gp, so our rfi remains "orphan"
2540  */
2542  g_object_steal_data(G_OBJECT(gp), "plugin-data");
2543  remmina_plugin_service->protocol_plugin_signal_connection_closed(gp);
2544  return FALSE;
2545  }
2546 
2547 
2548  if (rfi && rfi->clipboard.srv_clip_data_wait == SCDW_BUSY_WAIT) {
2549  REMMINA_PLUGIN_DEBUG("[RDP] requesting clipboard transfer to abort");
2550  /* Allow clipboard transfer from server to terminate */
2551  rfi->clipboard.srv_clip_data_wait = SCDW_ABORTING;
2552  usleep(100000);
2553  }
2554 
2555  if (rfi->is_reconnecting) {
2556  /* Special case: window closed when attempting to reconnect */
2557  rfi->stop_reconnecting_requested = TRUE;
2558  return FALSE;
2559  }
2560 
2561  rdp_event.type = REMMINA_RDP_EVENT_DISCONNECT;
2562  remmina_rdp_event_event_push(gp, &rdp_event);
2563 
2564  return FALSE;
2565 }
2566 
2568 {
2569  TRACE_CALL(__func__);
2570  return TRUE;
2571 }
2572 
2574 {
2575  TRACE_CALL(__func__);
2576  rfContext *rfi = GET_PLUGIN_DATA(gp);
2577 
2578  switch (feature->id) {
2579  case REMMINA_RDP_FEATURE_UNFOCUS:
2581  break;
2582 
2583  case REMMINA_RDP_FEATURE_SCALE:
2584  if (rfi) {
2585  rfi->scale = remmina_plugin_service->remmina_protocol_widget_get_current_scale_mode(gp);
2587  } else {
2588  REMMINA_PLUGIN_DEBUG("Remmina RDP plugin warning: Null value for rfi by REMMINA_RDP_FEATURE_SCALE");
2589  }
2590  break;
2591 
2592  case REMMINA_RDP_FEATURE_MULTIMON:
2593  if (rfi) {
2594  RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
2595  if (remmina_plugin_service->file_get_int(remminafile, "multimon", FALSE)) {
2596  freerdp_settings_set_bool(rfi->settings, FreeRDP_UseMultimon, TRUE);
2597  /* TODO Add an option for this */
2598  freerdp_settings_set_bool(rfi->settings, FreeRDP_ForceMultimon, TRUE);
2599  freerdp_settings_set_bool(rfi->settings, FreeRDP_Fullscreen, TRUE);
2601  }
2602  } else {
2603  REMMINA_PLUGIN_DEBUG("Remmina RDP plugin warning: Null value for rfi by REMMINA_RDP_FEATURE_MULTIMON");
2604  }
2605  break;
2606 
2607  case REMMINA_RDP_FEATURE_DYNRESUPDATE:
2608  break;
2609 
2610  case REMMINA_RDP_FEATURE_TOOL_REFRESH:
2611  if (rfi)
2612  gtk_widget_queue_draw_area(rfi->drawing_area, 0, 0,
2613  remmina_plugin_service->protocol_plugin_get_width(gp),
2614  remmina_plugin_service->protocol_plugin_get_height(gp));
2615  else
2616  REMMINA_PLUGIN_DEBUG("Remmina RDP plugin warning: Null value for rfi by REMMINA_RDP_FEATURE_TOOL_REFRESH");
2617  break;
2618 
2619  case REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL:
2621  break;
2622 
2623  default:
2624  break;
2625  }
2626 }
2627 
2628 /* Send a keystroke to the plugin window */
2629 static void remmina_rdp_keystroke(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
2630 {
2631  TRACE_CALL(__func__);
2632  rfContext *rfi = GET_PLUGIN_DATA(gp);
2633 
2634  remmina_plugin_service->protocol_plugin_send_keys_signals(rfi->drawing_area,
2635  keystrokes, keylen, GDK_KEY_PRESS | GDK_KEY_RELEASE);
2636  return;
2637 }
2638 
2640 {
2641  rfContext *rfi = GET_PLUGIN_DATA(gp);
2642  rdpGdi *gdi;
2643  size_t szmem;
2644 
2645  UINT32 bytesPerPixel;
2646  UINT32 bitsPerPixel;
2647 
2648  if (!rfi)
2649  return FALSE;
2650 
2651  gdi = ((rdpContext *)rfi)->gdi;
2652 
2653  bytesPerPixel = GetBytesPerPixel(gdi->hdc->format);
2654  bitsPerPixel = GetBitsPerPixel(gdi->hdc->format);
2655 
2659  szmem = gdi->width * gdi->height * bytesPerPixel;
2660 
2661  REMMINA_PLUGIN_DEBUG("allocating %zu bytes for a full screenshot", szmem);
2662  rpsd->buffer = malloc(szmem);
2663  if (!rpsd->buffer) {
2664  REMMINA_PLUGIN_DEBUG("could not set aside %zu bytes for a full screenshot", szmem);
2665  return FALSE;
2666  }
2667  rpsd->width = gdi->width;
2668  rpsd->height = gdi->height;
2669  rpsd->bitsPerPixel = bitsPerPixel;
2670  rpsd->bytesPerPixel = bytesPerPixel;
2671 
2672  memcpy(rpsd->buffer, gdi->primary_buffer, szmem);
2673 
2674  /* Returning TRUE instruct also the caller to deallocate rpsd->buffer */
2675  return TRUE;
2676 }
2677 
2678 /* Array of key/value pairs for colour depths */
2679 static gpointer colordepth_list[] =
2680 {
2681  /* 1st one is the default in a new install */
2682  "99", N_("Automatic (32 bpp) (Server chooses its best format)"),
2683  "66", N_("GFX AVC444 (32 bpp)"),
2684  "65", N_("GFX AVC420 (32 bpp)"),
2685  "64", N_("GFX RFX (32 bpp)"),
2686  "63", N_("GFX RFX Progressive (32 bpp)"),
2687  "0", N_("RemoteFX (32 bpp)"),
2688  "32", N_("True colour (32 bpp)"),
2689  "24", N_("True colour (24 bpp)"),
2690  "16", N_("High colour (16 bpp)"),
2691  "15", N_("High colour (15 bpp)"),
2692  "8", N_("256 colours (8 bpp)"),
2693  NULL
2694 };
2695 
2696 /* Array of key/value pairs for the FreeRDP logging level */
2697 static gpointer log_level[] =
2698 {
2699  "INFO", "INFO",
2700  "FATAL", "FATAL",
2701  "ERROR", "ERROR",
2702  "WARN", "WARN",
2703  "DEBUG", "DEBUG",
2704  "TRACE", "TRACE",
2705  "OFF", "OFF",
2706  NULL
2707 };
2708 
2709 
2710 /* Array of key/value pairs for quality selection */
2711 static gpointer quality_list[] =
2712 {
2713  "0", N_("Poor (fastest)"),
2714  "1", N_("Medium"),
2715  "2", N_("Good"),
2716  "9", N_("Best (slowest)"),
2717  NULL
2718 };
2719 
2720 /* Array of key/value pairs for quality selection */
2721 static gpointer network_list[] =
2722 {
2723  "none", N_("None"),
2724  "autodetect", N_("Auto-detect"),
2725  "modem", N_("Modem"),
2726  "broadband-low", N_("Low performance broadband"),
2727  "satellite", N_("Satellite"),
2728  "broadband-high", N_("High performance broadband"),
2729  "wan", N_("WAN"),
2730  "lan", N_("LAN"),
2731  NULL
2732 };
2733 
2734 /* Array of key/value pairs for sound options */
2735 static gpointer sound_list[] =
2736 {
2737  "off", N_("Off"),
2738  "local", N_("Local"),
2739  "remote", N_("Remote"),
2740  NULL
2741 };
2742 
2743 /* Array of key/value pairs for security */
2744 static gpointer security_list[] =
2745 {
2746  "", N_("Automatic negotiation"),
2747  "nla", N_("NLA protocol security"),
2748  "tls", N_("TLS protocol security"),
2749  "rdp", N_("RDP protocol security"),
2750  "ext", N_("NLA extended protocol security"),
2751  NULL
2752 };
2753 
2754 /* Array of key/value pairs for mouse movement */
2755 static gpointer mouse_jitter_list[] =
2756 {
2757  "No", N_("No"),
2758  "60", N_("Every 1 min"),
2759  "180", N_("Every 3 min"),
2760  "300", N_("Every 5 min"),
2761  "600", N_("Every 10 min"),
2762  NULL
2763 };
2764 
2765 static gpointer gwtransp_list[] =
2766 {
2767  "http", "HTTP",
2768  "rpc", "RPC",
2769  "auto", "Auto",
2770  NULL
2771 };
2772 
2773 static gpointer tls_seclevel[] =
2774 {
2775  "", N_("Default"),
2776  "0", N_("0 — Windows 7 compatible"),
2777  "1", N_("1"),
2778  "2", N_("2"),
2779  "3", N_("3"),
2780  "4", N_("4"),
2781  "5", N_("5"),
2782  NULL
2783 };
2784 
2785 static gchar clientbuild_list[] =
2786  N_("2600 (Windows XP), 7601 (Windows Vista/7), 9600 (Windows 8 and newer)");
2787 
2788 static gchar clientbuild_tooltip[] =
2789  N_("Used i.a. by terminal services in a smart card channel to distinguish client capabilities:\n"
2790  " • < 4034: Windows XP base smart card functions\n"
2791  " • 4034-7064: Windows Vista/7: SCardReadCache(),\n"
2792  " SCardWriteCache(), SCardGetTransmitCount()\n"
2793  " • >= 7065: Windows 8 and newer: SCardGetReaderIcon(),\n"
2794  " SCardGetDeviceTypeId()");
2795 
2796 static gchar microphone_tooltip[] =
2797  N_("Options for redirection of audio input:\n"
2798  " • [sys:<sys>,][dev:<dev>,][format:<format>,][rate:<rate>,]\n"
2799  " [channel:<channel>] Audio input (microphone)\n"
2800  " • sys:pulse\n"
2801  " • format:1\n"
2802  " • sys:oss,dev:1,format:1\n"
2803  " • sys:alsa");
2804 
2805 static gchar audio_tooltip[] =
2806  N_("Options for redirection of audio output:\n"
2807  " • [sys:<sys>,][dev:<dev>,][format:<format>,][rate:<rate>,]\n"
2808  " [channel:<channel>] Audio output\n"
2809  " • sys:pulse\n"
2810  " • format:1\n"
2811  " • sys:oss,dev:1,format:1\n"
2812  " • sys:alsa");
2813 
2814 
2815 static gchar usb_tooltip[] =
2816  N_("Options for redirection of USB device:\n"
2817  " • [dbg,][id:<vid>:<pid>#…,][addr:<bus>:<addr>#…,][auto]\n"
2818  " • auto\n"
2819  " • id:054c:0268#4669:6e6b,addr:04:0c");
2820 
2821 static gchar timeout_tooltip[] =
2822  N_("Advanced setting for high latency links:\n"
2823  "Adjusts the connection timeout. Use if your connection times out.\n"
2824  "The highest possible value is 600000 ms (10 minutes).\n");
2825 
2826 static gchar network_tooltip[] =
2827  N_("Performance optimisations based on the network connection type:\n"
2828  "Using auto-detection is advised.\n"
2829  "If “Auto-detect” fails, choose the most appropriate option in the list.\n");
2830 
2831 static gchar monitorids_tooltip[] =
2832  N_("Comma-separated list of monitor IDs and desktop orientations:\n"
2833  " • [<id>:<orientation-in-degrees>,]\n"
2834  " • 0,1,2,3\n"
2835  " • 0:270,1:90\n"
2836  "Orientations are specified in degrees, valid values are:\n"
2837  " • 0 (landscape)\n"
2838  " • 90 (portrait)\n"
2839  " • 180 (landscape flipped)\n"
2840  " • 270 (portrait flipped)\n"
2841  "\n");
2842 
2843 static gchar drive_tooltip[] =
2844  N_("Redirect directory <path> as named share <name>.\n"
2845  " • <name>,<fullpath>[;<name>,<fullpath>[;…]]\n"
2846  " • MyHome,/home/remminer\n"
2847  " • /home/remminer\n"
2848  " • MyHome,/home/remminer;SomePath,/path/to/somepath\n"
2849  "Hotplug support is enabled with:\n"
2850  " • hotplug,*\n"
2851  "\n");
2852 
2853 /* Array of RemminaProtocolSetting for basic settings.
2854  * Each item is composed by:
2855  * a) RemminaProtocolSettingType for setting type
2856  * b) Setting name
2857  * c) Setting description
2858  * d) Compact disposition
2859  * e) Values for REMMINA_PROTOCOL_SETTING_TYPE_SELECT or REMMINA_PROTOCOL_SETTING_TYPE_COMBO
2860  * f) Setting tooltip
2861  * g) Validation data pointer, will be passed to the validation callback method.
2862  * h) Validation callback method (Can be NULL. Every entry will be valid then.)
2863  * use following prototype:
2864  * gboolean mysetting_validator_method(gpointer key, gpointer value,
2865  * gpointer validator_data);
2866  * gpointer key is a gchar* containing the setting's name,
2867  * gpointer value contains the value which should be validated,
2868  * gpointer validator_data contains your passed data.
2869  */
2871 {
2872  { REMMINA_PROTOCOL_SETTING_TYPE_SERVER, "server", NULL, FALSE, NULL, NULL, NULL, NULL },
2873  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "username", N_("Username"), FALSE, NULL, NULL, NULL, NULL },
2874  { REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD, "password", N_("Password"), FALSE, NULL, NULL, NULL, NULL },
2875  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "domain", N_("Domain"), FALSE, NULL, NULL, NULL, NULL },
2876  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "drive", N_("Share folder"), FALSE, NULL, drive_tooltip, NULL, NULL },
2877  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "restricted-admin", N_("Restricted admin mode"), FALSE, NULL, NULL, NULL, NULL },
2878  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "pth", N_("Password hash"), FALSE, NULL, N_("Restricted admin mode password hash"), NULL, NULL },
2879  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "left-handed", N_("Left-handed mouse support"), TRUE, NULL, N_("Swap left and right mouse buttons for left-handed mouse support"), NULL, NULL },
2880  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disable-smooth-scrolling", N_("Disable smooth scrolling"), TRUE, NULL, NULL, NULL, NULL },
2881  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "multimon", N_("Enable multi monitor"), TRUE, NULL, NULL, NULL, NULL },
2882  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "span", N_("Span screen over multiple monitors"), TRUE, NULL, NULL, NULL, NULL },
2883  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "monitorids", N_("List monitor IDs"), FALSE, NULL, monitorids_tooltip, NULL, NULL },
2884  { REMMINA_PROTOCOL_SETTING_TYPE_RESOLUTION, "resolution", NULL, FALSE, NULL, NULL, NULL, NULL },
2885  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "colordepth", N_("Colour depth"), FALSE, colordepth_list, NULL, NULL, NULL },
2886  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "network", N_("Network connection type"), FALSE, network_list, network_tooltip, NULL, NULL },
2887  { REMMINA_PROTOCOL_SETTING_TYPE_KEYMAP, "keymap", NULL, FALSE, NULL, NULL, NULL, NULL },
2888  { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL, NULL, NULL }
2889 };
2890 
2891 /* Array of RemminaProtocolSetting for advanced settings.
2892  * Each item is composed by:
2893  * a) RemminaProtocolSettingType for setting type
2894  * b) Setting name
2895  * c) Setting description
2896  * d) Compact disposition
2897  * e) Values for REMMINA_PROTOCOL_SETTING_TYPE_SELECT or REMMINA_PROTOCOL_SETTING_TYPE_COMBO
2898  * f) Setting Tooltip
2899  */
2901 {
2902  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "quality", N_("Quality"), FALSE, quality_list, NULL },
2903  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "security", N_("Security protocol negotiation"), FALSE, security_list, NULL },
2904  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "gwtransp", N_("Gateway transport type"), FALSE, gwtransp_list, NULL },
2905  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "tls-seclevel", N_("TLS Security Level"), FALSE, tls_seclevel, NULL },
2906  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "freerdp_log_level", N_("FreeRDP log level"), FALSE, log_level, NULL },
2907  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "freerdp_log_filters", N_("FreeRDP log filters"), FALSE, NULL, N_("tag:level[,tag:level[,…]]") },
2908  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "sound", N_("Audio output mode"), FALSE, sound_list, NULL },
2909  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "audio-output", N_("Redirect local audio output"), TRUE, NULL, audio_tooltip },
2910  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "microphone", N_("Redirect local microphone"), TRUE, NULL, microphone_tooltip },
2911  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "timeout", N_("Connection timeout in ms"), TRUE, NULL, timeout_tooltip },
2912  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "gateway_server", N_("Remote Desktop Gateway server"), FALSE, NULL, NULL },
2913  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "gateway_username", N_("Remote Desktop Gateway username"), FALSE, NULL, NULL },
2914  { REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD, "gateway_password", N_("Remote Desktop Gateway password"), FALSE, NULL, NULL },
2915  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "gateway_domain", N_("Remote Desktop Gateway domain"), FALSE, NULL, NULL },
2916  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "clientname", N_("Client name"), FALSE, NULL, NULL },
2917  { REMMINA_PROTOCOL_SETTING_TYPE_COMBO, "clientbuild", N_("Client build"), FALSE, clientbuild_list, clientbuild_tooltip },
2918  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "exec", N_("Start-up program"), FALSE, NULL, NULL },
2919  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "execpath", N_("Start-up path"), FALSE, NULL, NULL },
2920  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "loadbalanceinfo", N_("Load balance info"), FALSE, NULL, NULL },
2921  // TRANSLATORS: Do not use typographic quotation marks, these must stay as "double quote", also know as “Typewriter ("programmer's") quote, ambidextrous.”
2922  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "printer_overrides", N_("Override printer drivers"), FALSE, NULL, N_("\"Samsung_CLX-3300_Series\":\"Samsung CLX-3300 Series PS\";\"Canon MF410\":\"Canon MF410 Series UFR II\"") },
2923  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "usb", N_("USB device redirection"), TRUE, NULL, usb_tooltip },
2924  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "serialname", N_("Local serial name"), FALSE, NULL, N_("COM1, COM2, etc.") },
2925  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "serialdriver", N_("Local serial driver"), FALSE, NULL, N_("Serial") },
2926  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "serialpath", N_("Local serial path"), FALSE, NULL, N_("/dev/ttyS0, /dev/ttyS1, etc.") },
2927  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "parallelname", N_("Local parallel name"), FALSE, NULL, NULL },
2928  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "parallelpath", N_("Local parallel device"), FALSE, NULL, NULL },
2929  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "smartcardname", N_("Name of smart card"), FALSE, NULL, NULL },
2930  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "dvc", N_("Dynamic virtual channel"), FALSE, NULL, N_("<channel>[,<options>]") },
2931  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "vc", N_("Static virtual channel"), FALSE, NULL, N_("<channel>[,<options>]") },
2932  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "rdp2tcp", N_("TCP redirection"), FALSE, NULL, N_("/PATH/TO/rdp2tcp") },
2933  { REMMINA_PROTOCOL_SETTING_TYPE_TEXT, "rdp_reconnect_attempts", N_("Reconnect attempts number"), FALSE, NULL, N_("The maximum number of reconnect attempts upon an RDP disconnect (default: 20)") },
2934  { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "rdp_mouse_jitter", N_("Move mouse when connection is idle"), FALSE, mouse_jitter_list, NULL },
2935 
2936  { REMMINA_PROTOCOL_SETTING_TYPE_ASSISTANCE, "assistance_mode", N_("Attempt to connect in assistance mode"), TRUE, NULL },
2937  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "preferipv6", N_("Prefer IPv6 AAAA record over IPv4 A record"), TRUE, NULL, NULL },
2938  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "shareprinter", N_("Share printers"), TRUE, NULL, NULL },
2939  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "shareserial", N_("Share serial ports"), TRUE, NULL, NULL },
2940  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "serialpermissive", N_("(SELinux) permissive mode for serial ports"), TRUE, NULL, NULL },
2941  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "shareparallel", N_("Share parallel ports"), TRUE, NULL, NULL },
2942  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "sharesmartcard", N_("Share a smart card"), TRUE, NULL, NULL },
2943  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disableclipboard", N_("Turn off clipboard sync"), TRUE, NULL, NULL },
2944  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "cert_ignore", N_("Ignore certificate"), TRUE, NULL, NULL },
2945  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "old-license", N_("Use the old license workflow"), TRUE, NULL, N_("It disables CAL and hwId is set to 0") },
2946  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disablepasswordstoring", N_("Forget passwords after use"), TRUE, NULL, NULL },
2947  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "console", N_("Attach to console (2003/2003 R2)"), TRUE, NULL, NULL },
2948  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disable_fastpath", N_("Turn off fast-path"), TRUE, NULL, NULL },
2949  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "gateway_usage", N_("Server detection using Remote Desktop Gateway"), TRUE, NULL, NULL },
2950 #if defined(PROXY_TYPE_IGNORE)
2951  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "useproxyenv", N_("Use system proxy settings"), TRUE, NULL, NULL },
2952 #endif
2953  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disableautoreconnect", N_("Turn off automatic reconnection"), TRUE, NULL, NULL },
2954  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "relax-order-checks", N_("Relax order checks"), TRUE, NULL, NULL },
2955  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "glyph-cache", N_("Glyph cache"), TRUE, NULL, NULL },
2956  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "multitransport", N_("Enable multitransport protocol (UDP)"), TRUE, NULL, N_("Using the UDP protocol may improve performance") },
2957  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "base-cred-for-gw", N_("Use base credentials for gateway too"), TRUE, NULL, NULL },
2958 #if FREERDP_CHECK_VERSION(2, 3, 1)
2959  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "websockets", N_("Enable Gateway websockets support"), TRUE, NULL, NULL },
2960 #endif
2961  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "no-suppress", N_("Update framebuffer even when not visible"), TRUE, NULL },
2962  { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL }
2963 };
2964 
2965 /* Array for available features.
2966  * The last element of the array must be REMMINA_PROTOCOL_FEATURE_TYPE_END. */
2968 {
2969  { REMMINA_PROTOCOL_FEATURE_TYPE_PREF, REMMINA_RDP_FEATURE_VIEWONLY, GINT_TO_POINTER(REMMINA_PROTOCOL_FEATURE_PREF_CHECK), "viewonly",
2970  N_("View only") },
2971  { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, REMMINA_RDP_FEATURE_TOOL_REFRESH, N_("Refresh"), NULL, NULL },
2972  { REMMINA_PROTOCOL_FEATURE_TYPE_SCALE, REMMINA_RDP_FEATURE_SCALE, NULL, NULL, NULL },
2973  { REMMINA_PROTOCOL_FEATURE_TYPE_DYNRESUPDATE, REMMINA_RDP_FEATURE_DYNRESUPDATE, NULL, NULL, NULL },
2974  { REMMINA_PROTOCOL_FEATURE_TYPE_MULTIMON, REMMINA_RDP_FEATURE_MULTIMON, NULL, NULL, NULL },
2975  { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, REMMINA_RDP_FEATURE_TOOL_SENDCTRLALTDEL, N_("Send Ctrl+Alt+Delete"), NULL, NULL },
2976  { REMMINA_PROTOCOL_FEATURE_TYPE_UNFOCUS, REMMINA_RDP_FEATURE_UNFOCUS, NULL, NULL, NULL },
2977  { REMMINA_PROTOCOL_FEATURE_TYPE_END, 0, NULL, NULL, NULL }
2978 };
2979 
2980 /* This will be filled with version info string */
2982 
2983 /* Protocol plugin definition and features */
2985 {
2987  "RDP", // Name
2988  N_("RDP - Remote Desktop Protocol"), // Description
2989  GETTEXT_PACKAGE, // Translation domain
2990  remmina_plugin_rdp_version, // Version number
2991  "org.remmina.Remmina-rdp-symbolic", // Icon for normal connection
2992  "org.remmina.Remmina-rdp-ssh-symbolic", // Icon for SSH connection
2993  remmina_rdp_basic_settings, // Array for basic settings
2994  remmina_rdp_advanced_settings, // Array for advanced settings
2995  REMMINA_PROTOCOL_SSH_SETTING_TUNNEL, // SSH settings type
2996  remmina_rdp_features, // Array for available features
2997  remmina_rdp_init, // Plugin initialization
2998  remmina_rdp_open_connection, // Plugin open connection
2999  remmina_rdp_close_connection, // Plugin close connection
3000  remmina_rdp_query_feature, // Query for available features
3001  remmina_rdp_call_feature, // Call a feature
3002  remmina_rdp_keystroke, // Send a keystroke
3003  remmina_rdp_get_screenshot, // Screenshot
3004  remmina_rdp_event_on_map, // RCW map event
3005  remmina_rdp_event_on_unmap // RCW unmap event
3006 };
3007 
3008 /* File plugin definition and features */
3010 {
3011  REMMINA_PLUGIN_TYPE_FILE, // Type
3012  "RDPF", // Name
3013  N_("RDP - RDP File Handler"), // Description
3014  GETTEXT_PACKAGE, // Translation domain
3015  remmina_plugin_rdp_version, // Version number
3016  remmina_rdp_file_import_test, // Test import function
3017  remmina_rdp_file_import, // Import function
3018  remmina_rdp_file_export_test, // Test export function
3019  remmina_rdp_file_export, // Export function
3020  NULL
3021 };
3022 
3023 /* Preferences plugin definition and features */
3025 {
3026  REMMINA_PLUGIN_TYPE_PREF, // Type
3027  "RDPS", // Name
3028  N_("RDP - Preferences"), // Description
3029  GETTEXT_PACKAGE, // Translation domain
3030  remmina_plugin_rdp_version, // Version number
3031  "RDP", // Label
3032  remmina_rdp_settings_new // Preferences body function
3033 };
3034 
3035 static char *buildconfig_strstr(const char *bc, const char *option)
3036 {
3037  TRACE_CALL(__func__);
3038 
3039  char *p, *n;
3040 
3041  p = strcasestr(bc, option);
3042  if (p == NULL)
3043  return NULL;
3044 
3045  if (p > bc && *(p - 1) > ' ')
3046  return NULL;
3047 
3048  n = p + strlen(option);
3049  if (*n > ' ')
3050  return NULL;
3051 
3052  return p;
3053 }
3054 
3055 G_MODULE_EXPORT gboolean remmina_plugin_entry(RemminaPluginService *service)
3056 {
3057  int vermaj, vermin, verrev;
3058 
3059  TRACE_CALL(__func__);
3060  remmina_plugin_service = service;
3061 
3062  /* Check that we are linked to the correct version of libfreerdp */
3063 
3064  freerdp_get_version(&vermaj, &vermin, &verrev);
3065  if (vermaj < FREERDP_REQUIRED_MAJOR ||
3066  (vermaj == FREERDP_REQUIRED_MAJOR && (vermin < FREERDP_REQUIRED_MINOR ||
3067  (vermin == FREERDP_REQUIRED_MINOR && verrev < FREERDP_REQUIRED_REVISION)))) {
3068  g_printf("Upgrade your FreeRDP library version from %d.%d.%d to at least libfreerdp %d.%d.%d "
3069  "to run the RDP plugin.\n",
3070  vermaj, vermin, verrev,
3071  FREERDP_REQUIRED_MAJOR, FREERDP_REQUIRED_MINOR, FREERDP_REQUIRED_REVISION);
3072  return FALSE;
3073  }
3074 
3075  bindtextdomain(GETTEXT_PACKAGE, REMMINA_RUNTIME_LOCALEDIR);
3076  bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
3077 
3078  if (!service->register_plugin((RemminaPlugin *)&remmina_rdp))
3079  return FALSE;
3080 
3081  remmina_rdpf.export_hints = _("Export connection in Windows .rdp file format");
3082 
3083  if (!service->register_plugin((RemminaPlugin *)&remmina_rdpf))
3084  return FALSE;
3085 
3086  if (!service->register_plugin((RemminaPlugin *)&remmina_rdps))
3087  return FALSE;
3088 
3089  if (buildconfig_strstr(freerdp_get_build_config(), "WITH_GFX_H264=ON")) {
3090  gfx_h264_available = TRUE;
3091  REMMINA_PLUGIN_DEBUG("gfx_h264_available: %d", gfx_h264_available);
3092  } else {
3093  gfx_h264_available = FALSE;
3094  REMMINA_PLUGIN_DEBUG("gfx_h264_available: %d", gfx_h264_available);
3095  /* Remove values 65 and 66 from colordepth_list array by shifting it */
3096  gpointer *src, *dst;
3097  dst = src = colordepth_list;
3098  while (*src) {
3099  if (strcmp(*src, "66") != 0 && strcmp(*src, "65") != 0) {
3100  if (dst != src) {
3101  *dst = *src;
3102  *(dst + 1) = *(src + 1);
3103  }
3104  dst += 2;
3105  }
3106  src += 2;
3107  }
3108  *dst = NULL;
3109  }
3110 
3112  "RDP plugin: %s (Git %s), Compiled with libfreerdp %s (%s), Running with libfreerdp %s (rev %s), H.264 %s",
3113  VERSION, REMMINA_GIT_REVISION,
3114 #ifdef WITH_FREERDP3
3115  FREERDP_VERSION_FULL, FREERDP_GIT_REVISION,
3116 #else
3117  FREERDP_VERSION_FULL, GIT_REVISION,
3118 #endif
3119  freerdp_get_version_string(),
3120  freerdp_get_build_revision(),
3121  gfx_h264_available ? "Yes" : "No"
3122  );
3123 
3125 
3126  return TRUE;
3127 }
CliprdrClientContext * context
Definition: rdp_plugin.h:135
gint w
Definition: rdp_plugin.h:262
struct remmina_plugin_rdp_event::@42::@45 mouse_event
gboolean thread_cancelled
Definition: rdp_plugin.h:332
gboolean is_reconnecting
Definition: rdp_plugin.h:344
-
static gpointer tls_seclevel[]
Definition: rdp_plugin.c:2771
-
static gchar network_tooltip[]
Definition: rdp_plugin.c:2824
+
static gpointer tls_seclevel[]
Definition: rdp_plugin.c:2773
+
static gchar network_tooltip[]
Definition: rdp_plugin.c:2826
gint y
Definition: rdp_plugin.h:262
RemminaScaleMode(* remmina_protocol_widget_get_current_scale_mode)(RemminaProtocolWidget *gp)
Definition: plugin.h:172
static int remmina_rdp_load_static_channel_addin(rdpChannels *channels, rdpSettings *settings, char *name, void *data)
Definition: rdp_plugin.c:1064
-
static gboolean remmina_rdp_open_connection(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:2475
+
static gboolean remmina_rdp_open_connection(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:2477
gboolean user_cancelled
Definition: rdp_plugin.h:331
-
static gpointer quality_list[]
Definition: rdp_plugin.c:2709
+
static gpointer quality_list[]
Definition: rdp_plugin.c:2711
static void remmina_rdp_send_ctrlaltdel(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:1247
gboolean attempt_interactive_authentication
Definition: rdp_plugin.h:390
@@ -110,13 +110,13 @@ $(document).ready(function(){initNavTree('rdp__plugin_8c_source.html','');});
void(* file_set_int)(RemminaFile *remminafile, const gchar *setting, gint value)
Definition: plugin.h:221
-
static RemminaProtocolPlugin remmina_rdp
Definition: rdp_plugin.c:2982
+
static RemminaProtocolPlugin remmina_rdp
Definition: rdp_plugin.c:2984
gboolean remmina_rdp_event_on_unmap(RemminaProtocolWidget *gp)
Definition: rdp_event.c:74
gboolean remmina_rdp_file_export_test(RemminaFilePlugin *plugin, RemminaFile *remminafile)
Definition: rdp_file.c:205
-
static gpointer log_level[]
Definition: rdp_plugin.c:2695
+
static gpointer log_level[]
Definition: rdp_plugin.c:2697
gchar *(* file_get_user_datadir)(void)
Definition: plugin.h:214
static BOOL rf_auto_reconnect(rfContext *rfi)
Definition: rdp_plugin.c:401
typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
Definition: types.h:44
@@ -136,13 +136,13 @@ $(document).ready(function(){initNavTree('rdp__plugin_8c_source.html','');});
void remmina_rdp_settings_get_orientation_scale_prefs(int *desktopOrientation, int *desktopScaleFactor, int *deviceScaleFactor)
Definition: rdp_settings.c:707
-
static gboolean remmina_rdp_query_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Definition: rdp_plugin.c:2565
+
static gboolean remmina_rdp_query_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Definition: rdp_plugin.c:2567
static DWORD remmina_rdp_verify_certificate_ex(freerdp *instance, const char *host, UINT16 port, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, DWORD flags)
Definition: rdp_plugin.c:914
-
static gchar microphone_tooltip[]
Definition: rdp_plugin.c:2794
+
static gchar microphone_tooltip[]
Definition: rdp_plugin.c:2796
gint(* protocol_plugin_init_certificate)(RemminaProtocolWidget *gp, const gchar *subject, const gchar *issuer, const gchar *fingerprint)
Definition: plugin.h:192
static BOOL rf_desktop_resize(rdpContext *context)
Definition: rdp_plugin.c:580
static CLPARAM ** remmina_rdp_CommandLineParseCommaSeparatedValues(const char *list, size_t *count)
Definition: rdp_plugin.c:204
@@ -155,10 +155,10 @@ $(document).ready(function(){initNavTree('rdp__plugin_8c_source.html','');});
static gboolean complete_cleanup_on_main_thread(gpointer data)
Definition: rdp_plugin.c:2382
static gboolean remmina_rdp_main(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:1358
void remmina_rdp_clipboard_init(rfContext *rfi)
Definition: rdp_cliprdr.c:934
-
static const RemminaProtocolSetting remmina_rdp_advanced_settings[]
Definition: rdp_plugin.c:2898
+
static const RemminaProtocolSetting remmina_rdp_advanced_settings[]
Definition: rdp_plugin.c:2900
RemminaProtocolWidget * protocol_widget
Definition: rdp_plugin.h:323
int reconnect_nattempt
Definition: rdp_plugin.h:352
-
static gpointer network_list[]
Definition: rdp_plugin.c:2719
+
static gpointer network_list[]
Definition: rdp_plugin.c:2721
void remmina_rdp_OnChannelConnectedEventHandler(void *context, ChannelConnectedEventArgs *e)
Definition: rdp_channels.c:46
void(* protocol_plugin_send_keys_signals)(GtkWidget *widget, const guint *keyvals, int length, GdkEventType action)
Definition: plugin.h:212
@@ -172,7 +172,7 @@ $(document).ready(function(){initNavTree('rdp__plugin_8c_source.html','');});
gint(* file_get_int)(RemminaFile *remminafile, const gchar *setting, gint default_value)
Definition: plugin.h:222
static void remmina_rdp_post_disconnect(freerdp *instance)
Definition: rdp_plugin.c:978
-
static gpointer mouse_jitter_list[]
Definition: rdp_plugin.c:2753
+
static gpointer mouse_jitter_list[]
Definition: rdp_plugin.c:2755
@@ -181,8 +181,9 @@ $(document).ready(function(){initNavTree('rdp__plugin_8c_source.html','');});
static CLPARAM ** remmina_rdp_CommandLineParseCommaSeparatedValuesEx(const char *name, const char *list, size_t *count)
Definition: rdp_plugin.c:125
-
static gchar clientbuild_tooltip[]
Definition: rdp_plugin.c:2786
+
static gchar clientbuild_tooltip[]
Definition: rdp_plugin.c:2788
RemminaPluginRdpEventType type
Definition: rdp_plugin.h:191
+
UINT16 last_x
Definition: rdp_plugin.h:383
gboolean(* protocol_plugin_init_get_savepassword)(RemminaProtocolWidget *gp)
Definition: plugin.h:197
@@ -196,33 +197,34 @@ $(document).ready(function(){initNavTree('rdp__plugin_8c_source.html','');});
static int remmina_rdp_set_printers(void *user_data, unsigned flags, cups_dest_t *dest)
Callback function used by cupsEnumDests.
Definition: rdp_plugin.c:1166
GtkWidget * drawing_area
Definition: rdp_plugin.h:355
-
static gpointer sound_list[]
Definition: rdp_plugin.c:2733
+
static gpointer sound_list[]
Definition: rdp_plugin.c:2735
cairo_format_t cairo_format
Definition: rdp_plugin.h:367
-
int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1460
+
int remmina_rdp_event_queue_ui_sync_retint(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1463
-
void remmina_rdp_event_init(RemminaProtocolWidget *gp)
Definition: rdp_event.c:909
+
void remmina_rdp_event_init(RemminaProtocolWidget *gp)
Definition: rdp_event.c:912
gboolean(* protocol_plugin_has_error)(RemminaProtocolWidget *gp)
Definition: plugin.h:175
gchar *(* pref_get_value)(const gchar *key)
Definition: plugin.h:227
-
static const RemminaProtocolFeature remmina_rdp_features[]
Definition: rdp_plugin.c:2965
-
static RemminaFilePlugin remmina_rdpf
Definition: rdp_plugin.c:3007
-
G_MODULE_EXPORT gboolean remmina_plugin_entry(RemminaPluginService *service)
Definition: rdp_plugin.c:3053
-
static gpointer security_list[]
Definition: rdp_plugin.c:2742
+
UINT16 last_y
Definition: rdp_plugin.h:384
+
static const RemminaProtocolFeature remmina_rdp_features[]
Definition: rdp_plugin.c:2967
+
static RemminaFilePlugin remmina_rdpf
Definition: rdp_plugin.c:3009
+
G_MODULE_EXPORT gboolean remmina_plugin_entry(RemminaPluginService *service)
Definition: rdp_plugin.c:3055
+
static gpointer security_list[]
Definition: rdp_plugin.c:2744
static BOOL rf_process_event_queue(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:213
-
void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1454
-
static void remmina_rdp_keystroke(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
Definition: rdp_plugin.c:2627
+
void remmina_rdp_event_queue_ui_async(RemminaProtocolWidget *gp, RemminaPluginRdpUiObject *ui)
Definition: rdp_event.c:1457
+
static void remmina_rdp_keystroke(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
Definition: rdp_plugin.c:2629
gboolean stop_reconnecting_requested
Definition: rdp_plugin.h:345
struct remmina_plugin_rdp_event::@42::@44 key_event
gboolean remmina_rdp_file_import_test(RemminaFilePlugin *plugin, const gchar *from_file)
Definition: rdp_file.c:41
gboolean remmina_rdp_file_export(RemminaFilePlugin *plugin, RemminaFile *remminafile, const gchar *to_file)
Definition: rdp_file.c:282
-
static gpointer colordepth_list[]
Definition: rdp_plugin.c:2677
+
static gpointer colordepth_list[]
Definition: rdp_plugin.c:2679
struct remmina_plugin_rdp_event::@42::@46 clipboard_formatlist
-
static gchar audio_tooltip[]
Definition: rdp_plugin.c:2803
+
static gchar audio_tooltip[]
Definition: rdp_plugin.c:2805
gint(* protocol_plugin_get_height)(RemminaProtocolWidget *gp)
Definition: plugin.h:170
gint(* protocol_plugin_init_auth)(RemminaProtocolWidget *gp, RemminaMessagePanelFlags pflags, const gchar *title, const gchar *default_username, const gchar *default_password, const gchar *default_domain, const gchar *password_prompt)
Definition: plugin.h:191
-
static gchar monitorids_tooltip[]
Definition: rdp_plugin.c:2829
+
static gchar monitorids_tooltip[]
Definition: rdp_plugin.c:2831
void remmina_rdp_event_send_delayed_monitor_layout(RemminaProtocolWidget *gp)
Definition: rdp_event.c:483
GAsyncQueue * event_queue
Definition: rdp_plugin.h:380
@@ -232,7 +234,7 @@ $(document).ready(function(){initNavTree('rdp__plugin_8c_source.html','');});
rfClipboard clipboard
Definition: rdp_plugin.h:386
gint(* get_profile_remote_height)(RemminaProtocolWidget *gp)
Definition: plugin.h:253
HANDLE event_handle
Definition: rdp_plugin.h:382
-
void remmina_rdp_event_uninit(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1041
+
void remmina_rdp_event_uninit(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1044
void remmina_rdp_mouse_jitter(RemminaProtocolWidget *gp)
Definition: rdp_event.c:561
@@ -243,16 +245,16 @@ $(document).ready(function(){initNavTree('rdp__plugin_8c_source.html','');});
guint *(* pref_keymap_get_table)(const gchar *keymap)
Definition: plugin.h:232
void(* protocol_plugin_desktop_resize)(RemminaProtocolWidget *gp)
Definition: plugin.h:190
static BOOL remmina_rdp_post_connect(freerdp *instance)
Definition: rdp_plugin.c:700
-
static gchar usb_tooltip[]
Definition: rdp_plugin.c:2813
+
static gchar usb_tooltip[]
Definition: rdp_plugin.c:2815
struct remmina_plugin_rdp_event::@42::@48 clipboard_formatdatarequest
GtkWidget * remmina_rdp_settings_new(RemminaPrefPlugin *plugin)
Definition: rdp_settings.c:696
-
static RemminaPrefPlugin remmina_rdps
Definition: rdp_plugin.c:3022
+
static RemminaPrefPlugin remmina_rdps
Definition: rdp_plugin.c:3024
gint srcBpp
Definition: rdp_plugin.h:363
gchar *(* protocol_plugin_init_get_username)(RemminaProtocolWidget *gp)
Definition: plugin.h:194
-
static gboolean remmina_rdp_close_connection(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:2523
+
static gboolean remmina_rdp_close_connection(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:2525
void remmina_rdp_clipboard_free(rfContext *rfi)
Definition: rdp_cliprdr.c:939
@@ -264,49 +266,49 @@ $(document).ready(function(){initNavTree('rdp__plugin_8c_source.html','');});
RemminaScaleMode scale
Definition: rdp_plugin.h:330
static BOOL rf_keyboard_set_ime_status(rdpContext *context, UINT16 imeId, UINT32 imeState, UINT32 imeConvMode)
Definition: rdp_plugin.c:663
void remmina_rdp_OnChannelDisconnectedEventHandler(void *context, ChannelDisconnectedEventArgs *e)
Definition: rdp_channels.c:86
-
static char remmina_plugin_rdp_version[256]
Definition: rdp_plugin.c:2979
+
static char remmina_plugin_rdp_version[256]
Definition: rdp_plugin.c:2981
freerdp * instance
Definition: rdp_plugin.h:327
static BOOL rf_keyboard_set_indicators(rdpContext *context, UINT16 led_flags)
Definition: rdp_plugin.c:634
static BOOL remmina_rdp_gw_authenticate(freerdp *instance, char **username, char **password, char **domain)
Definition: rdp_plugin.c:834
DispClientContext * dispcontext
Definition: rdp_plugin.h:335
-
static char * buildconfig_strstr(const char *bc, const char *option)
Definition: rdp_plugin.c:3033
-
static gchar clientbuild_list[]
Definition: rdp_plugin.c:2783
+
static char * buildconfig_strstr(const char *bc, const char *option)
Definition: rdp_plugin.c:3035
+
static gchar clientbuild_list[]
Definition: rdp_plugin.c:2785
static DWORD remmina_rdp_verify_certificate(freerdp *instance, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, BOOL host_mismatch) __attribute__((unused))
Definition: rdp_plugin.c:937
-
void remmina_rdp_event_update_scale(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1115
+
void remmina_rdp_event_update_scale(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1118
static BOOL rf_begin_paint(rdpContext *context)
Definition: rdp_plugin.c:518
rdpSettings * settings
Definition: rdp_plugin.h:326
void(* file_set_string)(RemminaFile *remminafile, const gchar *setting, const gchar *value)
Definition: plugin.h:218
void(* protocol_plugin_set_height)(RemminaProtocolWidget *gp, gint height)
Definition: plugin.h:171
static BOOL rf_end_paint(rdpContext *context)
Definition: rdp_plugin.c:533
static gpointer remmina_rdp_main_thread(gpointer data)
Definition: rdp_plugin.c:2412
-
void remmina_rdp_event_unfocus(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1309
+
void remmina_rdp_event_unfocus(RemminaProtocolWidget *gp)
Definition: rdp_event.c:1312
static BOOL remmina_rdp_pre_connect(freerdp *instance)
Definition: rdp_plugin.c:675
static gchar * remmina_rdp_find_prdriver(char *smap, char *prn)
Definition: rdp_plugin.c:1091
-
static gchar timeout_tooltip[]
Definition: rdp_plugin.c:2819
+
static gchar timeout_tooltip[]
Definition: rdp_plugin.c:2821
static gboolean remmina_rdp_tunnel_init(RemminaProtocolWidget *gp)
Definition: rdp_plugin.c:342
struct remmina_plugin_rdp_ui_object::@50::@57 event
gchar *(* protocol_plugin_start_direct_tunnel)(RemminaProtocolWidget *gp, gint default_port, gboolean port_plus)
Definition: plugin.h:181
void remmina_rdp_monitor_get(rfContext *rfi, gchar **monitorids, guint32 *maxwidth, guint32 *maxheight)
Set the MonitorIDs, the maxwidth and maxheight.
Definition: rdp_monitor.c:68
-
static const RemminaProtocolSetting remmina_rdp_basic_settings[]
Definition: rdp_plugin.c:2868
-
static gboolean remmina_rdp_get_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
Definition: rdp_plugin.c:2637
+
static const RemminaProtocolSetting remmina_rdp_basic_settings[]
Definition: rdp_plugin.c:2870
+
static gboolean remmina_rdp_get_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
Definition: rdp_plugin.c:2639
void remmina_rdp_event_event_push(RemminaProtocolWidget *gp, const RemminaPluginRdpEvent *e)
Definition: rdp_event.c:150
const gchar *(* file_get_string)(RemminaFile *remminafile, const gchar *setting)
Definition: plugin.h:219
-
static gchar drive_tooltip[]
Definition: rdp_plugin.c:2841
+
static gchar drive_tooltip[]
Definition: rdp_plugin.c:2843
RemminaPluginService * remmina_plugin_service
Definition: rdp_plugin.c:112
unsigned char * buffer
Definition: types.h:84
gboolean remmina_rdp_event_on_map(RemminaProtocolWidget *gp)
Definition: rdp_event.c:52
struct timeval clientformatdatarequest_tv
Definition: rdp_plugin.h:151
-
static gpointer gwtransp_list[]
Definition: rdp_plugin.c:2763
+
static gpointer gwtransp_list[]
Definition: rdp_plugin.c:2765
rdpContext context
Definition: rdp_plugin.h:320
-
static void remmina_rdp_call_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Definition: rdp_plugin.c:2571
+
static void remmina_rdp_call_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Definition: rdp_plugin.c:2573
gchar *(* protocol_plugin_init_get_domain)(RemminaProtocolWidget *gp)
Definition: plugin.h:196
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:953
gboolean(* is_main_thread)(void)
Definition: plugin.h:250
-- cgit v1.2.3