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_file.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-2023 Antenore Gatta, Giovanni Panozzo
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  * In addition, as a special exception, the copyright holders give
23  * permission to link the code of portions of this program with the
24  * OpenSSL library under certain conditions as described in each
25  * individual source file, and distribute linked combinations
26  * including the two.
27  * You must obey the GNU General Public License in all respects
28  * for all of the code used other than OpenSSL. * If you modify
29  * file(s) with this exception, you may extend this exception to your
30  * version of the file(s), but you are not obligated to do so. * If you
31  * do not wish to do so, delete this exception statement from your
32  * version. * If you delete this exception statement from all source
33  * files in the program, then also delete it here.
34  *
35  */
36 
37 #include "remmina/plugin.h"
38 #include "rdp_plugin.h"
39 #include "rdp_file.h"
40 
41 gboolean remmina_rdp_file_import_test(RemminaFilePlugin *plugin, const gchar *from_file)
42 {
43  TRACE_CALL(__func__);
44  gchar *ext;
45 
46  ext = strrchr(from_file, '.');
47 
48  if (!ext)
49  return FALSE;
50 
51  ext++;
52 
53  if (g_strcmp0(ext, "RDP") == 0)
54  return TRUE;
55 
56  if (g_strcmp0(ext, "rdp") == 0)
57  return TRUE;
58 
59  return FALSE;
60 }
61 
62 static void remmina_rdp_file_import_field(RemminaFile *remminafile, const gchar *key, const gchar *value)
63 {
64  TRACE_CALL(__func__);
65  if (g_strcmp0(key, "desktopwidth") == 0) {
66  remmina_plugin_service->file_set_string(remminafile, "resolution_width", value);
67  } else if (g_strcmp0(key, "desktopheight") == 0) {
68  remmina_plugin_service->file_set_string(remminafile, "resolution_height", value);
69  } else if (g_strcmp0(key, "session bpp") == 0) {
70  remmina_plugin_service->file_set_string(remminafile, "colordepth", value);
71  } else if (g_strcmp0(key, "keyboardhook") == 0) {
72  remmina_plugin_service->file_set_int(remminafile, "keyboard_grab", (atoi(value) == 1));
73  } else if (g_strcmp0(key, "full address") == 0) {
74  remmina_plugin_service->file_set_string(remminafile, "server", value);
75  } else if (g_strcmp0(key, "audiomode") == 0) {
76  switch (atoi(value)) {
77  case 0:
78  remmina_plugin_service->file_set_string(remminafile, "sound", "local");
79  break;
80  case 1:
81  remmina_plugin_service->file_set_string(remminafile, "sound", "remote");
82  break;
83  }
84  } else if (g_strcmp0(key, "redirectprinters") == 0) {
85  remmina_plugin_service->file_set_int(remminafile, "shareprinter", (atoi(value) == 1));
86  } else if (g_strcmp0(key, "redirectsmartcard") == 0) {
87  remmina_plugin_service->file_set_int(remminafile, "sharesmartcard", (atoi(value) == 1));
88  } else if (g_strcmp0(key, "redirectclipboard") == 0) {
89  remmina_plugin_service->file_set_int(remminafile, "disableclipboard", (atoi(value) != 1));
90  } else if (g_strcmp0(key, "alternate shell") == 0) {
91  remmina_plugin_service->file_set_string(remminafile, "exec", value);
92  } else if (g_strcmp0(key, "shell working directory") == 0) {
93  remmina_plugin_service->file_set_string(remminafile, "execpath", value);
94  } else if (g_strcmp0(key, "loadbalanceinfo") == 0) {
95  remmina_plugin_service->file_set_string(remminafile, "loadbalanceinfo", value);
96  } else if (g_strcmp0(key, "gatewayhostname") == 0) {
97  remmina_plugin_service->file_set_string(remminafile, "gateway_server", value);
98  } else if (g_strcmp0(key, "gatewayusagemethod") == 0) {
99  remmina_plugin_service->file_set_int(remminafile, "gateway_usage", (atoi(value) == TSC_PROXY_MODE_DETECT));
100  } else if (g_strcmp0(key, "gatewayaccesstoken") == 0) {
101  remmina_plugin_service->file_set_string(remminafile, "gatewayaccesstoken", value);
102  } else if (g_strcmp0(key, "authentication level") == 0) {
103  remmina_plugin_service->file_set_int(remminafile, "authentication level", atoi(value));
104  }
105  /* tsclient fields, import only */
106  else if (g_strcmp0(key, "client hostname") == 0) {
107  remmina_plugin_service->file_set_string(remminafile, "clientname", value);
108  } else if (g_strcmp0(key, "domain") == 0) {
109  remmina_plugin_service->file_set_string(remminafile, "domain", value);
110  } else if (g_strcmp0(key, "username") == 0) {
111  remmina_plugin_service->file_set_string(remminafile, "username", value);
112  } else if (g_strcmp0(key, "password") == 0) {
113  remmina_plugin_service->file_set_string(remminafile, "password", value);
114  }
115 }
116 
117 static RemminaFile *remmina_rdp_file_import_channel(GIOChannel *channel)
118 {
119  TRACE_CALL(__func__);
120  gchar *p;
121  const gchar *enc;
122  gchar *line = NULL;
123  GError *error = NULL;
124  gsize bytes_read = 0;
125  RemminaFile *remminafile;
126  guchar magic[2] = { 0 };
127 
128  if (g_io_channel_set_encoding(channel, NULL, &error) != G_IO_STATUS_NORMAL) {
129  g_print("g_io_channel_set_encoding: %s\n", error->message);
130  return NULL;
131  }
132 
133  /* Try to detect the UTF-16 encoding */
134  if (g_io_channel_read_chars(channel, (gchar *)magic, 2, &bytes_read, &error) != G_IO_STATUS_NORMAL) {
135  g_print("g_io_channel_read_chars: %s\n", error->message);
136  return NULL;
137  }
138 
139  if (magic[0] == 0xFF && magic[1] == 0xFE) {
140  enc = "UTF-16LE";
141  } else if (magic[0] == 0xFE && magic[1] == 0xFF) {
142  enc = "UTF-16BE";
143  } else {
144  enc = "UTF-8";
145  if (g_io_channel_seek_position(channel, 0, G_SEEK_SET, &error) != G_IO_STATUS_NORMAL) {
146  g_print("g_io_channel_seek: failed\n");
147  return NULL;
148  }
149  }
150 
151  if (g_io_channel_set_encoding(channel, enc, &error) != G_IO_STATUS_NORMAL) {
152  g_print("g_io_channel_set_encoding: %s\n", error->message);
153  return NULL;
154  }
155 
156  remminafile = remmina_plugin_service->file_new();
157 
158  while (g_io_channel_read_line(channel, &line, NULL, &bytes_read, &error) == G_IO_STATUS_NORMAL) {
159  if (line == NULL)
160  break;
161 
162  line[bytes_read] = '\0';
163  p = strchr(line, ':');
164 
165  if (p) {
166  *p++ = '\0';
167  p = strchr(p, ':');
168 
169  if (p) {
170  p++;
171  remmina_rdp_file_import_field(remminafile, line, p);
172  }
173  }
174 
175  g_free(line);
176  }
177 
178  remmina_plugin_service->file_set_string(remminafile, "name",
179  remmina_plugin_service->file_get_string(remminafile, "server"));
180  remmina_plugin_service->file_set_string(remminafile, "protocol", "RDP");
181 
182  return remminafile;
183 }
184 
185 RemminaFile *remmina_rdp_file_import(RemminaFilePlugin *plugin,const gchar *from_file)
186 {
187  TRACE_CALL(__func__);
188  GIOChannel *channel;
189  GError *error = NULL;
190  RemminaFile *remminafile;
191 
192  channel = g_io_channel_new_file(from_file, "r", &error);
193 
194  if (channel == NULL) {
195  g_print("Failed to import %s: %s\n", from_file, error->message);
196  return NULL;
197  }
198 
199  remminafile = remmina_rdp_file_import_channel(channel);
200  g_io_channel_shutdown(channel, TRUE, &error);
201 
202  return remminafile;
203 }
204 
206 {
207  TRACE_CALL(__func__);
208  if (g_strcmp0(remmina_plugin_service->file_get_string(remminafile, "protocol"), "RDP") == 0)
209  return TRUE;
210 
211  return FALSE;
212 }
213 
214 gboolean remmina_rdp_file_export_channel(RemminaFile *remminafile, FILE *fp)
215 {
216  TRACE_CALL(__func__);
217  const gchar *cs;
218  int w, h;
219 
220  fprintf(fp, "screen mode id:i:2\r\n");
221  w = remmina_plugin_service->file_get_int(remminafile, "resolution_width", -1);
222  h = remmina_plugin_service->file_get_int(remminafile, "resolution_height", -1);
223  if (w > 0 && h > 0) {
224  fprintf(fp, "desktopwidth:i:%d\r\n", w);
225  fprintf(fp, "desktopheight:i:%d\r\n", h);
226  }
227 
228  fprintf(fp, "session bpp:i:%i\r\n", remmina_plugin_service->file_get_int(remminafile, "colordepth", 8));
229  //fprintf(fp, "winposstr:s:0,1,123,34,931,661\r\n");
230  fprintf(fp, "compression:i:1\r\n");
231  fprintf(fp, "keyboardhook:i:2\r\n");
232  fprintf(fp, "displayconnectionbar:i:1\r\n");
233  fprintf(fp, "disable wallpaper:i:1\r\n");
234  fprintf(fp, "disable full window drag:i:1\r\n");
235  fprintf(fp, "allow desktop composition:i:0\r\n");
236  fprintf(fp, "allow font smoothing:i:0\r\n");
237  fprintf(fp, "disable menu anims:i:1\r\n");
238  fprintf(fp, "disable themes:i:0\r\n");
239  fprintf(fp, "disable cursor setting:i:0\r\n");
240  fprintf(fp, "bitmapcachepersistenable:i:1\r\n");
241  cs = remmina_plugin_service->file_get_string(remminafile, "server");
242  fprintf(fp, "full address:s:%s\r\n", cs ? cs : "");
243  if (g_strcmp0(remmina_plugin_service->file_get_string(remminafile, "sound"), "local") == 0)
244  fprintf(fp, "audiomode:i:0\r\n");
245  else if (g_strcmp0(remmina_plugin_service->file_get_string(remminafile, "sound"), "remote") == 0)
246  fprintf(fp, "audiomode:i:1\r\n");
247  else
248  fprintf(fp, "audiomode:i:2\r\n");
249  if (g_strcmp0(remmina_plugin_service->file_get_string(remminafile, "microphone"), "") == 0)
250  fprintf(fp, "audiocapturemode:i:0\r\n");
251  else if (g_strcmp0(remmina_plugin_service->file_get_string(remminafile, "microphone"), "0") == 0)
252  fprintf(fp, "audiocapturemode:i:1\r\n");
253  else
254  fprintf(fp, "audiocapturemode:i:1\r\n");
255  fprintf(fp, "redirectprinters:i:%i\r\n", remmina_plugin_service->file_get_int(remminafile, "shareprinter", FALSE) ? 1 : 0);
256  fprintf(fp, "redirectsmartcard:i:%i\r\n", remmina_plugin_service->file_get_int(remminafile, "sharesmartcard", FALSE) ? 1 : 0);
257  fprintf(fp, "redirectcomports:i:0\r\n");
258  fprintf(fp, "redirectsmartcards:i:0\r\n");
259  fprintf(fp, "redirectclipboard:i:1\r\n");
260  fprintf(fp, "redirectposdevices:i:0\r\n");
261  fprintf(fp, "autoreconnection enabled:i:1\r\n");
262  fprintf(fp, "authentication level:i:0\r\n");
263  fprintf(fp, "prompt for credentials:i:1\r\n");
264  fprintf(fp, "negotiate security layer:i:1\r\n");
265  fprintf(fp, "remoteapplicationmode:i:0\r\n");
266  cs = remmina_plugin_service->file_get_string(remminafile, "exec");
267  fprintf(fp, "alternate shell:s:%s\r\n", cs ? cs : "");
268  cs = remmina_plugin_service->file_get_string(remminafile, "execpath");
269  fprintf(fp, "shell working directory:s:%s\r\n", cs ? cs : "");
270  cs = remmina_plugin_service->file_get_string(remminafile, "gateway_server");
271  fprintf(fp, "gatewayhostname:s:%s\r\n", cs ? cs : "");
272  fprintf(fp, "gatewayusagemethod:i:4\r\n");
273  fprintf(fp, "gatewaycredentialssource:i:4\r\n");
274  fprintf(fp, "gatewayprofileusagemethod:i:0\r\n");
275  fprintf(fp, "precommand:s:\r\n");
276  fprintf(fp, "promptcredentialonce:i:1\r\n");
277  fprintf(fp, "drivestoredirect:s:\r\n");
278 
279  return TRUE;
280 }
281 
282 gboolean remmina_rdp_file_export(RemminaFilePlugin *plugin, RemminaFile *remminafile, const gchar *to_file)
283 {
284  TRACE_CALL(__func__);
285  FILE *fp;
286  gchar *p;
287  gboolean ret;
288 
289  p = strrchr(to_file, '.');
290 
291  if (p && (g_strcmp0(p + 1, "rdp") == 0 || g_strcmp0(p + 1, "RDP") == 0))
292  p = g_strdup(to_file);
293  else
294  p = g_strdup_printf("%s.rdp", to_file);
295 
296  fp = g_fopen(p, "w+");
297 
298  if (fp == NULL) {
299  g_print("Failed to export %s\n", p);
300  g_free(p);
301  return FALSE;
302  }
303 
304  g_free(p);
305  ret = remmina_rdp_file_export_channel(remminafile, fp);
306  fclose(fp);
307 
308  return ret;
309 }
gboolean remmina_rdp_file_export_channel(RemminaFile *remminafile, FILE *fp)
Definition: rdp_file.c:214
void(* file_set_int)(RemminaFile *remminafile, const gchar *setting, gint value)
Definition: plugin.h:221
gboolean remmina_rdp_file_export_test(RemminaFilePlugin *plugin, RemminaFile *remminafile)
Definition: rdp_file.c:205
typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
Definition: types.h:44
static RemminaFile * remmina_rdp_file_import_channel(GIOChannel *channel)
Definition: rdp_file.c:117
gint(* file_get_int)(RemminaFile *remminafile, const gchar *setting, gint default_value)
Definition: plugin.h:222
static RemminaPluginService * remmina_plugin_service
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 void remmina_rdp_file_import_field(RemminaFile *remminafile, const gchar *key, const gchar *value)
Definition: rdp_file.c:62
void(* file_set_string)(RemminaFile *remminafile, const gchar *setting, const gchar *value)
Definition: plugin.h:218
const gchar *(* file_get_string)(RemminaFile *remminafile, const gchar *setting)
Definition: plugin.h:219
RemminaFile *(* file_new)(void)
Definition: plugin.h:216
RemminaFile * remmina_rdp_file_import(RemminaFilePlugin *plugin, const gchar *from_file)
Definition: rdp_file.c:185