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