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