FreeRDP/client/X11/xfreerdp.c

1145 lines
28 KiB
C
Raw Normal View History

2011-08-07 17:52:40 +04:00
/**
* FreeRDP: A Remote Desktop Protocol Client
* X11 Client
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <X11/Xlib.h>
#include <X11/Xutil.h>
2011-09-29 08:33:16 +04:00
#ifdef WITH_XCURSOR
#include <X11/Xcursor/Xcursor.h>
#endif
#ifdef WITH_XINERAMA
#include <X11/extensions/Xinerama.h>
#endif
2011-09-19 02:44:49 +04:00
#include <errno.h>
2011-08-26 06:01:33 +04:00
#include <stdio.h>
#include <stdlib.h>
2011-08-09 04:31:21 +04:00
#include <locale.h>
2011-09-19 02:44:49 +04:00
#include <unistd.h>
#include <string.h>
#include <termios.h>
2011-09-19 02:44:49 +04:00
#include <pthread.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/select.h>
#include <freerdp/constants.h>
2011-10-04 13:40:03 +04:00
#include <freerdp/codec/nsc.h>
#include <freerdp/codec/rfx.h>
#include <freerdp/codec/color.h>
#include <freerdp/codec/bitmap.h>
2011-08-07 17:52:40 +04:00
#include <freerdp/utils/args.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/semaphore.h>
2011-09-29 08:33:16 +04:00
#include <freerdp/utils/memory.h>
2011-08-07 17:52:40 +04:00
#include <freerdp/utils/event.h>
2011-09-29 08:37:30 +04:00
#include <freerdp/utils/signal.h>
#include <freerdp/utils/passphrase.h>
2011-08-11 07:07:03 +04:00
#include <freerdp/plugins/cliprdr.h>
#include <freerdp/rail.h>
2011-08-07 17:52:40 +04:00
2011-08-26 02:07:52 +04:00
#include "xf_gdi.h"
#include "xf_rail.h"
2011-09-20 12:27:59 +04:00
#include "xf_tsmf.h"
2011-08-07 17:52:40 +04:00
#include "xf_event.h"
2011-09-23 07:37:17 +04:00
#include "xf_cliprdr.h"
#include "xf_monitor.h"
#include "xf_graphics.h"
2011-08-26 06:01:33 +04:00
#include "xf_keyboard.h"
2011-08-07 17:52:40 +04:00
#include "xfreerdp.h"
static freerdp_sem g_sem;
2011-08-07 17:52:40 +04:00
static int g_thread_count = 0;
static uint8 g_disconnect_reason = 0;
2011-08-07 17:52:40 +04:00
2011-09-20 12:27:59 +04:00
static long xv_port = 0;
static const size_t password_size = 512;
2011-09-20 12:27:59 +04:00
2011-08-07 17:52:40 +04:00
struct thread_data
{
freerdp* instance;
};
int xf_process_client_args(rdpSettings* settings, const char* opt, const char* val, void* user_data);
int xf_process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data);
void xf_context_new(freerdp* instance, rdpContext* context)
{
context->channels = freerdp_channels_new();
}
void xf_context_free(freerdp* instance, rdpContext* context)
{
}
void xf_sw_begin_paint(rdpContext* context)
2011-08-07 17:52:40 +04:00
{
rdpGdi* gdi = context->gdi;
2011-08-07 17:52:40 +04:00
gdi->primary->hdc->hwnd->invalid->null = 1;
gdi->primary->hdc->hwnd->ninvalid = 0;
2011-08-07 17:52:40 +04:00
}
void xf_sw_end_paint(rdpContext* context)
2011-08-07 17:52:40 +04:00
{
rdpGdi* gdi;
2011-08-07 17:52:40 +04:00
xfInfo* xfi;
sint32 x, y;
uint32 w, h;
2011-08-07 17:52:40 +04:00
xfi = ((xfContext*) context)->xfi;
gdi = context->gdi;
2011-08-07 17:52:40 +04:00
if (xfi->remote_app != true)
{
if (xfi->complex_regions != true)
{
if (gdi->primary->hdc->hwnd->invalid->null)
return;
x = gdi->primary->hdc->hwnd->invalid->x;
y = gdi->primary->hdc->hwnd->invalid->y;
w = gdi->primary->hdc->hwnd->invalid->w;
h = gdi->primary->hdc->hwnd->invalid->h;
XPutImage(xfi->display, xfi->primary, xfi->gc, xfi->image, x, y, x, y, w, h);
XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, x, y, w, h, x, y);
}
else
{
int i;
int ninvalid;
HGDI_RGN cinvalid;
if (gdi->primary->hdc->hwnd->ninvalid < 1)
return;
ninvalid = gdi->primary->hdc->hwnd->ninvalid;
cinvalid = gdi->primary->hdc->hwnd->cinvalid;
for (i = 0; i < ninvalid; i++)
{
x = cinvalid[i].x;
y = cinvalid[i].y;
w = cinvalid[i].w;
h = cinvalid[i].h;
XPutImage(xfi->display, xfi->primary, xfi->gc, xfi->image, x, y, x, y, w, h);
XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, x, y, w, h, x, y);
}
XFlush(xfi->display);
}
}
else
{
if (gdi->primary->hdc->hwnd->invalid->null)
return;
x = gdi->primary->hdc->hwnd->invalid->x;
y = gdi->primary->hdc->hwnd->invalid->y;
w = gdi->primary->hdc->hwnd->invalid->w;
h = gdi->primary->hdc->hwnd->invalid->h;
xf_rail_paint(xfi, context->rail, x, y, x + w - 1, y + h - 1);
}
2011-08-07 17:52:40 +04:00
}
void xf_sw_desktop_resize(rdpContext* context)
{
xfInfo* xfi;
rdpSettings* settings;
xfi = ((xfContext*) context)->xfi;
settings = xfi->instance->settings;
if (xfi->fullscreen != true)
{
rdpGdi* gdi = context->gdi;
gdi_resize(gdi, xfi->width, xfi->height);
if (xfi->image)
{
xfi->image->data = NULL;
XDestroyImage(xfi->image);
xfi->image = XCreateImage(xfi->display, xfi->visual, xfi->depth, ZPixmap, 0,
(char*) gdi->primary_buffer, gdi->width, gdi->height, xfi->scanline_pad, 0);
}
}
}
void xf_hw_begin_paint(rdpContext* context)
{
xfInfo* xfi;
xfi = ((xfContext*) context)->xfi;
xfi->hdc->hwnd->invalid->null = 1;
xfi->hdc->hwnd->ninvalid = 0;
}
void xf_hw_end_paint(rdpContext* context)
{
xfInfo* xfi;
sint32 x, y;
uint32 w, h;
xfi = ((xfContext*) context)->xfi;
if (xfi->remote_app)
{
if (xfi->hdc->hwnd->invalid->null)
return;
x = xfi->hdc->hwnd->invalid->x;
y = xfi->hdc->hwnd->invalid->y;
w = xfi->hdc->hwnd->invalid->w;
h = xfi->hdc->hwnd->invalid->h;
xf_rail_paint(xfi, context->rail, x, y, x + w - 1, y + h - 1);
}
}
void xf_hw_desktop_resize(rdpContext* context)
{
xfInfo* xfi;
boolean same;
rdpSettings* settings;
xfi = ((xfContext*) context)->xfi;
settings = xfi->instance->settings;
if (xfi->fullscreen != true)
{
xfi->width = settings->width;
xfi->height = settings->height;
if (xfi->window)
xf_ResizeDesktopWindow(xfi, xfi->window, settings->width, settings->height);
if (xfi->primary)
{
same = (xfi->primary == xfi->drawing) ? true : false;
XFreePixmap(xfi->display, xfi->primary);
xfi->primary = XCreatePixmap(xfi->display, xfi->drawable,
xfi->width, xfi->height, xfi->depth);
if (same)
xfi->drawing = xfi->primary;
}
}
}
2011-08-07 17:52:40 +04:00
boolean xf_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, int* wcount)
{
xfInfo* xfi = ((xfContext*) instance->context)->xfi;
2011-08-07 17:52:40 +04:00
rfds[*rcount] = (void*)(long)(xfi->xfds);
(*rcount)++;
return true;
2011-08-07 17:52:40 +04:00
}
boolean xf_check_fds(freerdp* instance, fd_set* set)
{
XEvent xevent;
xfInfo* xfi = ((xfContext*) instance->context)->xfi;
while (XPending(xfi->display))
{
memset(&xevent, 0, sizeof(xevent));
XNextEvent(xfi->display, &xevent);
if (xf_event_process(instance, &xevent) != true)
return false;
}
2011-08-07 17:52:40 +04:00
return true;
2011-08-07 17:52:40 +04:00
}
void xf_create_window(xfInfo* xfi)
{
XEvent xevent;
char* win_title;
2011-10-07 23:50:07 +04:00
int width, height;
2011-10-07 23:50:07 +04:00
width = xfi->width;
height = xfi->height;
xfi->attribs.background_pixel = BlackPixelOfScreen(xfi->screen);
xfi->attribs.border_pixel = WhitePixelOfScreen(xfi->screen);
xfi->attribs.backing_store = xfi->primary ? NotUseful : Always;
xfi->attribs.override_redirect = xfi->fullscreen;
xfi->attribs.colormap = xfi->colormap;
xfi->attribs.bit_gravity = ForgetGravity;
xfi->attribs.win_gravity = StaticGravity;
xfreerdp: a quick workaround for some issues with TS Remote App. Currently in Remote App mode we have no option to interact with the remote desktop host before the first RAIL window is created. In many situations this interaction possibility is absolutely required. One example is that screen which gets displayed if another user is logged on. It requires clicking a button in pre-RAIL mode so that the currently logged on user gets notified to confirm or deny the connection. Another example is the option to log on graphically (e.g. for hosts that don't support NLA) without predefined credentials. Also if the administrator sets the "User must change password at next logon" option there is currently no way to do this in TS Remote App mode. This change basically lets xfreerdp create the main window in Remote App mode like in a normal session and xfi->remote_app is not set to true initially. As soon as the rail exec result event or the first rail window creation request is received (whatever comes first) the main window gets destroyed and xfi->remote_app is set to true. The second change is to disconnect immediately if the rail exec result event reports an error, e.g. if the specified app cannot be found or if it is not in the list of allowed applications. This fixes FreeRDP github issue #143 and issue #308. I'm aware that this is not the most elegant solution but it is definitely an improvement and probably good enough for 1.0. A nicer solution would be hiding the main window and only displaying it if no rail exec result or rail window creation event is received after a certain timeout ...
2012-01-02 13:27:04 +04:00
if (xfi->instance->settings->window_title != NULL)
{
win_title = xstrdup(xfi->instance->settings->window_title);
xfreerdp: a quick workaround for some issues with TS Remote App. Currently in Remote App mode we have no option to interact with the remote desktop host before the first RAIL window is created. In many situations this interaction possibility is absolutely required. One example is that screen which gets displayed if another user is logged on. It requires clicking a button in pre-RAIL mode so that the currently logged on user gets notified to confirm or deny the connection. Another example is the option to log on graphically (e.g. for hosts that don't support NLA) without predefined credentials. Also if the administrator sets the "User must change password at next logon" option there is currently no way to do this in TS Remote App mode. This change basically lets xfreerdp create the main window in Remote App mode like in a normal session and xfi->remote_app is not set to true initially. As soon as the rail exec result event or the first rail window creation request is received (whatever comes first) the main window gets destroyed and xfi->remote_app is set to true. The second change is to disconnect immediately if the rail exec result event reports an error, e.g. if the specified app cannot be found or if it is not in the list of allowed applications. This fixes FreeRDP github issue #143 and issue #308. I'm aware that this is not the most elegant solution but it is definitely an improvement and probably good enough for 1.0. A nicer solution would be hiding the main window and only displaying it if no rail exec result or rail window creation event is received after a certain timeout ...
2012-01-02 13:27:04 +04:00
}
else if (xfi->instance->settings->port == 3389)
{
win_title = xmalloc(1 + sizeof("FreeRDP: ") + strlen(xfi->instance->settings->hostname));
xfreerdp: a quick workaround for some issues with TS Remote App. Currently in Remote App mode we have no option to interact with the remote desktop host before the first RAIL window is created. In many situations this interaction possibility is absolutely required. One example is that screen which gets displayed if another user is logged on. It requires clicking a button in pre-RAIL mode so that the currently logged on user gets notified to confirm or deny the connection. Another example is the option to log on graphically (e.g. for hosts that don't support NLA) without predefined credentials. Also if the administrator sets the "User must change password at next logon" option there is currently no way to do this in TS Remote App mode. This change basically lets xfreerdp create the main window in Remote App mode like in a normal session and xfi->remote_app is not set to true initially. As soon as the rail exec result event or the first rail window creation request is received (whatever comes first) the main window gets destroyed and xfi->remote_app is set to true. The second change is to disconnect immediately if the rail exec result event reports an error, e.g. if the specified app cannot be found or if it is not in the list of allowed applications. This fixes FreeRDP github issue #143 and issue #308. I'm aware that this is not the most elegant solution but it is definitely an improvement and probably good enough for 1.0. A nicer solution would be hiding the main window and only displaying it if no rail exec result or rail window creation event is received after a certain timeout ...
2012-01-02 13:27:04 +04:00
sprintf(win_title, "FreeRDP: %s", xfi->instance->settings->hostname);
}
else
{
win_title = xmalloc(1 + sizeof("FreeRDP: ") + strlen(xfi->instance->settings->hostname) + sizeof(":00000"));
xfreerdp: a quick workaround for some issues with TS Remote App. Currently in Remote App mode we have no option to interact with the remote desktop host before the first RAIL window is created. In many situations this interaction possibility is absolutely required. One example is that screen which gets displayed if another user is logged on. It requires clicking a button in pre-RAIL mode so that the currently logged on user gets notified to confirm or deny the connection. Another example is the option to log on graphically (e.g. for hosts that don't support NLA) without predefined credentials. Also if the administrator sets the "User must change password at next logon" option there is currently no way to do this in TS Remote App mode. This change basically lets xfreerdp create the main window in Remote App mode like in a normal session and xfi->remote_app is not set to true initially. As soon as the rail exec result event or the first rail window creation request is received (whatever comes first) the main window gets destroyed and xfi->remote_app is set to true. The second change is to disconnect immediately if the rail exec result event reports an error, e.g. if the specified app cannot be found or if it is not in the list of allowed applications. This fixes FreeRDP github issue #143 and issue #308. I'm aware that this is not the most elegant solution but it is definitely an improvement and probably good enough for 1.0. A nicer solution would be hiding the main window and only displaying it if no rail exec result or rail window creation event is received after a certain timeout ...
2012-01-02 13:27:04 +04:00
sprintf(win_title, "FreeRDP: %s:%i", xfi->instance->settings->hostname, xfi->instance->settings->port);
}
xfreerdp: a quick workaround for some issues with TS Remote App. Currently in Remote App mode we have no option to interact with the remote desktop host before the first RAIL window is created. In many situations this interaction possibility is absolutely required. One example is that screen which gets displayed if another user is logged on. It requires clicking a button in pre-RAIL mode so that the currently logged on user gets notified to confirm or deny the connection. Another example is the option to log on graphically (e.g. for hosts that don't support NLA) without predefined credentials. Also if the administrator sets the "User must change password at next logon" option there is currently no way to do this in TS Remote App mode. This change basically lets xfreerdp create the main window in Remote App mode like in a normal session and xfi->remote_app is not set to true initially. As soon as the rail exec result event or the first rail window creation request is received (whatever comes first) the main window gets destroyed and xfi->remote_app is set to true. The second change is to disconnect immediately if the rail exec result event reports an error, e.g. if the specified app cannot be found or if it is not in the list of allowed applications. This fixes FreeRDP github issue #143 and issue #308. I'm aware that this is not the most elegant solution but it is definitely an improvement and probably good enough for 1.0. A nicer solution would be hiding the main window and only displaying it if no rail exec result or rail window creation event is received after a certain timeout ...
2012-01-02 13:27:04 +04:00
xfi->window = xf_CreateDesktopWindow(xfi, win_title, width, height, xfi->decorations);
xfree(win_title);
xfreerdp: a quick workaround for some issues with TS Remote App. Currently in Remote App mode we have no option to interact with the remote desktop host before the first RAIL window is created. In many situations this interaction possibility is absolutely required. One example is that screen which gets displayed if another user is logged on. It requires clicking a button in pre-RAIL mode so that the currently logged on user gets notified to confirm or deny the connection. Another example is the option to log on graphically (e.g. for hosts that don't support NLA) without predefined credentials. Also if the administrator sets the "User must change password at next logon" option there is currently no way to do this in TS Remote App mode. This change basically lets xfreerdp create the main window in Remote App mode like in a normal session and xfi->remote_app is not set to true initially. As soon as the rail exec result event or the first rail window creation request is received (whatever comes first) the main window gets destroyed and xfi->remote_app is set to true. The second change is to disconnect immediately if the rail exec result event reports an error, e.g. if the specified app cannot be found or if it is not in the list of allowed applications. This fixes FreeRDP github issue #143 and issue #308. I'm aware that this is not the most elegant solution but it is definitely an improvement and probably good enough for 1.0. A nicer solution would be hiding the main window and only displaying it if no rail exec result or rail window creation event is received after a certain timeout ...
2012-01-02 13:27:04 +04:00
if (xfi->parent_window)
XReparentWindow(xfi->display, xfi->window->handle, xfi->parent_window, 0, 0);
xfreerdp: a quick workaround for some issues with TS Remote App. Currently in Remote App mode we have no option to interact with the remote desktop host before the first RAIL window is created. In many situations this interaction possibility is absolutely required. One example is that screen which gets displayed if another user is logged on. It requires clicking a button in pre-RAIL mode so that the currently logged on user gets notified to confirm or deny the connection. Another example is the option to log on graphically (e.g. for hosts that don't support NLA) without predefined credentials. Also if the administrator sets the "User must change password at next logon" option there is currently no way to do this in TS Remote App mode. This change basically lets xfreerdp create the main window in Remote App mode like in a normal session and xfi->remote_app is not set to true initially. As soon as the rail exec result event or the first rail window creation request is received (whatever comes first) the main window gets destroyed and xfi->remote_app is set to true. The second change is to disconnect immediately if the rail exec result event reports an error, e.g. if the specified app cannot be found or if it is not in the list of allowed applications. This fixes FreeRDP github issue #143 and issue #308. I'm aware that this is not the most elegant solution but it is definitely an improvement and probably good enough for 1.0. A nicer solution would be hiding the main window and only displaying it if no rail exec result or rail window creation event is received after a certain timeout ...
2012-01-02 13:27:04 +04:00
if (xfi->fullscreen)
xf_SetWindowFullscreen(xfi, xfi->window, xfi->fullscreen);
xfreerdp: a quick workaround for some issues with TS Remote App. Currently in Remote App mode we have no option to interact with the remote desktop host before the first RAIL window is created. In many situations this interaction possibility is absolutely required. One example is that screen which gets displayed if another user is logged on. It requires clicking a button in pre-RAIL mode so that the currently logged on user gets notified to confirm or deny the connection. Another example is the option to log on graphically (e.g. for hosts that don't support NLA) without predefined credentials. Also if the administrator sets the "User must change password at next logon" option there is currently no way to do this in TS Remote App mode. This change basically lets xfreerdp create the main window in Remote App mode like in a normal session and xfi->remote_app is not set to true initially. As soon as the rail exec result event or the first rail window creation request is received (whatever comes first) the main window gets destroyed and xfi->remote_app is set to true. The second change is to disconnect immediately if the rail exec result event reports an error, e.g. if the specified app cannot be found or if it is not in the list of allowed applications. This fixes FreeRDP github issue #143 and issue #308. I'm aware that this is not the most elegant solution but it is definitely an improvement and probably good enough for 1.0. A nicer solution would be hiding the main window and only displaying it if no rail exec result or rail window creation event is received after a certain timeout ...
2012-01-02 13:27:04 +04:00
/* wait for VisibilityNotify */
do
{
xfreerdp: a quick workaround for some issues with TS Remote App. Currently in Remote App mode we have no option to interact with the remote desktop host before the first RAIL window is created. In many situations this interaction possibility is absolutely required. One example is that screen which gets displayed if another user is logged on. It requires clicking a button in pre-RAIL mode so that the currently logged on user gets notified to confirm or deny the connection. Another example is the option to log on graphically (e.g. for hosts that don't support NLA) without predefined credentials. Also if the administrator sets the "User must change password at next logon" option there is currently no way to do this in TS Remote App mode. This change basically lets xfreerdp create the main window in Remote App mode like in a normal session and xfi->remote_app is not set to true initially. As soon as the rail exec result event or the first rail window creation request is received (whatever comes first) the main window gets destroyed and xfi->remote_app is set to true. The second change is to disconnect immediately if the rail exec result event reports an error, e.g. if the specified app cannot be found or if it is not in the list of allowed applications. This fixes FreeRDP github issue #143 and issue #308. I'm aware that this is not the most elegant solution but it is definitely an improvement and probably good enough for 1.0. A nicer solution would be hiding the main window and only displaying it if no rail exec result or rail window creation event is received after a certain timeout ...
2012-01-02 13:27:04 +04:00
XMaskEvent(xfi->display, VisibilityChangeMask, &xevent);
}
xfreerdp: a quick workaround for some issues with TS Remote App. Currently in Remote App mode we have no option to interact with the remote desktop host before the first RAIL window is created. In many situations this interaction possibility is absolutely required. One example is that screen which gets displayed if another user is logged on. It requires clicking a button in pre-RAIL mode so that the currently logged on user gets notified to confirm or deny the connection. Another example is the option to log on graphically (e.g. for hosts that don't support NLA) without predefined credentials. Also if the administrator sets the "User must change password at next logon" option there is currently no way to do this in TS Remote App mode. This change basically lets xfreerdp create the main window in Remote App mode like in a normal session and xfi->remote_app is not set to true initially. As soon as the rail exec result event or the first rail window creation request is received (whatever comes first) the main window gets destroyed and xfi->remote_app is set to true. The second change is to disconnect immediately if the rail exec result event reports an error, e.g. if the specified app cannot be found or if it is not in the list of allowed applications. This fixes FreeRDP github issue #143 and issue #308. I'm aware that this is not the most elegant solution but it is definitely an improvement and probably good enough for 1.0. A nicer solution would be hiding the main window and only displaying it if no rail exec result or rail window creation event is received after a certain timeout ...
2012-01-02 13:27:04 +04:00
while (xevent.type != VisibilityNotify);
xfi->unobscured = (xevent.xvisibility.state == VisibilityUnobscured);
XSetWMProtocols(xfi->display, xfi->window->handle, &(xfi->WM_DELETE_WINDOW), 1);
xfi->drawable = xfi->window->handle;
}
2011-08-24 08:46:34 +04:00
void xf_toggle_fullscreen(xfInfo* xfi)
{
Pixmap contents = 0;
contents = XCreatePixmap(xfi->display, xfi->window->handle, xfi->width, xfi->height, xfi->depth);
XCopyArea(xfi->display, xfi->primary, contents, xfi->gc, 0, 0, xfi->width, xfi->height, 0, 0);
2011-09-14 06:20:04 +04:00
XDestroyWindow(xfi->display, xfi->window->handle);
xfi->fullscreen = (xfi->fullscreen) ? false : true;
xf_create_window(xfi);
2011-08-24 08:46:34 +04:00
XCopyArea(xfi->display, contents, xfi->primary, xfi->gc, 0, 0, xfi->width, xfi->height, 0, 0);
XFreePixmap(xfi->display, contents);
}
boolean xf_get_pixmap_info(xfInfo* xfi)
{
int i;
int vi_count;
int pf_count;
XVisualInfo* vi;
XVisualInfo* vis;
XVisualInfo template;
XPixmapFormatValues* pf;
XPixmapFormatValues* pfs;
pfs = XListPixmapFormats(xfi->display, &pf_count);
if (pfs == NULL)
{
printf("xf_get_pixmap_info: XListPixmapFormats failed\n");
return 1;
}
for (i = 0; i < pf_count; i++)
{
pf = pfs + i;
if (pf->depth == xfi->depth)
{
xfi->bpp = pf->bits_per_pixel;
xfi->scanline_pad = pf->scanline_pad;
break;
}
}
XFree(pfs);
memset(&template, 0, sizeof(template));
template.class = TrueColor;
template.screen = xfi->screen_number;
vis = XGetVisualInfo(xfi->display, VisualClassMask | VisualScreenMask, &template, &vi_count);
if (vis == NULL)
{
printf("xf_get_pixmap_info: XGetVisualInfo failed\n");
return false;
2011-08-24 08:46:34 +04:00
}
vi = NULL;
2011-08-24 08:46:34 +04:00
for (i = 0; i < vi_count; i++)
{
vi = vis + i;
if (vi->depth == xfi->depth)
{
xfi->visual = vi->visual;
break;
}
}
if (vi)
{
/*
* Detect if the server visual has an inverted colormap
* (BGR vs RGB, or red being the least significant byte)
*/
if (vi->red_mask & 0xFF)
{
xfi->clrconv->invert = true;
}
}
2011-08-24 08:46:34 +04:00
XFree(vis);
if ((xfi->visual == NULL) || (xfi->scanline_pad == 0))
{
return false;
2011-08-24 08:46:34 +04:00
}
return true;
2011-08-24 08:46:34 +04:00
}
static int (*_def_error_handler)(Display*, XErrorEvent*);
int xf_error_handler(Display* d, XErrorEvent* ev)
{
char buf[256];
int do_abort = true;
XGetErrorText(d, ev->error_code, buf, sizeof(buf));
printf("%s", buf);
if (do_abort)
abort();
_def_error_handler(d, ev);
return false;
}
int _xf_error_handler(Display* d, XErrorEvent* ev)
{
/*
* ungrab the keyboard, in case a debugger is running in
* another window. This make xf_error_handler() a potential
* debugger breakpoint.
*/
XUngrabKeyboard(d, CurrentTime);
return xf_error_handler(d, ev);
}
2011-08-07 17:52:40 +04:00
boolean xf_pre_connect(freerdp* instance)
{
xfInfo* xfi;
boolean bitmap_cache;
2011-08-07 17:52:40 +04:00
rdpSettings* settings;
int arg_parse_result;
2011-08-07 17:52:40 +04:00
xfi = (xfInfo*) xzalloc(sizeof(xfInfo));
((xfContext*) instance->context)->xfi = xfi;
xfi->_context = instance->context;
xfi->context = (xfContext*) instance->context;
xfi->context->settings = instance->settings;
xfi->instance = instance;
arg_parse_result = freerdp_parse_args(instance->settings, instance->context->argc,instance->context->argv,
xf_process_plugin_args, instance->context->channels, xf_process_client_args, xfi);
if (arg_parse_result < 0)
{
if (arg_parse_result == FREERDP_ARGS_PARSE_FAILURE)
printf("failed to parse arguments.\n");
exit(XF_EXIT_PARSE_ARGUMENTS);
}
2011-08-07 17:52:40 +04:00
settings = instance->settings;
bitmap_cache = settings->bitmap_cache;
2011-08-07 17:52:40 +04:00
settings->os_major_type = OSMAJORTYPE_UNIX;
settings->os_minor_type = OSMINORTYPE_NATIVE_XSERVER;
settings->order_support[NEG_DSTBLT_INDEX] = true;
settings->order_support[NEG_PATBLT_INDEX] = true;
settings->order_support[NEG_SCRBLT_INDEX] = true;
settings->order_support[NEG_OPAQUE_RECT_INDEX] = true;
settings->order_support[NEG_DRAWNINEGRID_INDEX] = false;
settings->order_support[NEG_MULTIDSTBLT_INDEX] = false;
settings->order_support[NEG_MULTIPATBLT_INDEX] = false;
settings->order_support[NEG_MULTISCRBLT_INDEX] = false;
settings->order_support[NEG_MULTIOPAQUERECT_INDEX] = true;
settings->order_support[NEG_MULTI_DRAWNINEGRID_INDEX] = false;
settings->order_support[NEG_LINETO_INDEX] = true;
settings->order_support[NEG_POLYLINE_INDEX] = true;
settings->order_support[NEG_MEMBLT_INDEX] = bitmap_cache;
settings->order_support[NEG_MEM3BLT_INDEX] = false;
settings->order_support[NEG_MEMBLT_V2_INDEX] = bitmap_cache;
settings->order_support[NEG_MEM3BLT_V2_INDEX] = false;
settings->order_support[NEG_SAVEBITMAP_INDEX] = false;
settings->order_support[NEG_GLYPH_INDEX_INDEX] = true;
settings->order_support[NEG_FAST_INDEX_INDEX] = true;
settings->order_support[NEG_FAST_GLYPH_INDEX] = true;
settings->order_support[NEG_POLYGON_SC_INDEX] = false;
settings->order_support[NEG_POLYGON_CB_INDEX] = false;
settings->order_support[NEG_ELLIPSE_SC_INDEX] = false;
settings->order_support[NEG_ELLIPSE_CB_INDEX] = false;
2011-08-07 17:52:40 +04:00
freerdp_channels_pre_connect(xfi->_context->channels, instance);
2011-08-07 17:52:40 +04:00
xfi->display = XOpenDisplay(NULL);
if (xfi->display == NULL)
{
printf("xf_pre_connect: failed to open display: %s\n", XDisplayName(NULL));
printf("Please check that the $DISPLAY environment variable is properly set.\n");
return false;
}
if (xfi->debug)
{
printf("Enabling X11 debug mode.\n");
XSynchronize(xfi->display, true);
_def_error_handler = XSetErrorHandler(_xf_error_handler);
}
xfi->_NET_WM_ICON = XInternAtom(xfi->display, "_NET_WM_ICON", False);
xfi->_MOTIF_WM_HINTS = XInternAtom(xfi->display, "_MOTIF_WM_HINTS", False);
xfi->_NET_CURRENT_DESKTOP = XInternAtom(xfi->display, "_NET_CURRENT_DESKTOP", False);
xfi->_NET_WORKAREA = XInternAtom(xfi->display, "_NET_WORKAREA", False);
xfi->_NET_WM_STATE = XInternAtom(xfi->display, "_NET_WM_STATE", False);
xfi->_NET_WM_STATE_FULLSCREEN = XInternAtom(xfi->display, "_NET_WM_STATE_FULLSCREEN", False);
xfi->_NET_WM_WINDOW_TYPE = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE", False);
xfi->_NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
xfi->_NET_WM_WINDOW_TYPE_DIALOG = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
xfi->_NET_WM_WINDOW_TYPE_POPUP= XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_POPUP", False);
xfi->_NET_WM_WINDOW_TYPE_UTILITY = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_UTILITY", False);
xfi->_NET_WM_WINDOW_TYPE_DROPDOWN_MENU = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False);
xfi->_NET_WM_STATE_SKIP_TASKBAR = XInternAtom(xfi->display, "_NET_WM_STATE_SKIP_TASKBAR", False);
xfi->_NET_WM_STATE_SKIP_PAGER = XInternAtom(xfi->display, "_NET_WM_STATE_SKIP_PAGER", False);
xfi->_NET_WM_MOVERESIZE = XInternAtom(xfi->display, "_NET_WM_MOVERESIZE", False);
xfi->_NET_MOVERESIZE_WINDOW = XInternAtom(xfi->display, "_NET_MOVERESIZE_WINDOW", False);
xfi->WM_PROTOCOLS = XInternAtom(xfi->display, "WM_PROTOCOLS", False);
xfi->WM_DELETE_WINDOW = XInternAtom(xfi->display, "WM_DELETE_WINDOW", False);
xf_kbd_init(xfi);
2011-09-07 10:19:11 +04:00
xfi->clrconv = xnew(CLRCONV);
xfi->clrconv->alpha = true;
xfi->clrconv->invert = false;
xfi->clrconv->rgb555 = false;
2011-10-21 20:17:04 +04:00
xfi->clrconv->palette = xnew(rdpPalette);
instance->context->cache = cache_new(instance->settings);
xfi->xfds = ConnectionNumber(xfi->display);
xfi->screen_number = DefaultScreen(xfi->display);
xfi->screen = ScreenOfDisplay(xfi->display, xfi->screen_number);
xfi->depth = DefaultDepthOfScreen(xfi->screen);
xfi->big_endian = (ImageByteOrder(xfi->display) == MSBFirst);
xfi->mouse_motion = settings->mouse_motion;
xfi->complex_regions = true;
2011-10-07 23:50:07 +04:00
xfi->decorations = settings->decorations;
2011-08-19 19:12:30 +04:00
xfi->fullscreen = settings->fullscreen;
xfi->grab_keyboard = settings->grab_keyboard;
xfi->fullscreen_toggle = true;
xfi->sw_gdi = settings->sw_gdi;
xfi->parent_window = (Window) settings->parent_window_xid;
xf_detect_monitors(xfi, settings);
return true;
}
void cpuid(unsigned info, unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx)
{
#ifdef __GNUC__
#if defined(__i386__) || defined(__x86_64__)
*eax = info;
__asm volatile
("mov %%ebx, %%edi;" /* 32bit PIC: don't clobber ebx */
"cpuid;"
"mov %%ebx, %%esi;"
"mov %%edi, %%ebx;"
:"+a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx)
: :"edi");
#endif
#endif
}
uint32 xf_detect_cpu()
{
unsigned int eax, ebx, ecx, edx = 0;
uint32 cpu_opt = 0;
cpuid(1, &eax, &ebx, &ecx, &edx);
if (edx & (1<<26))
{
DEBUG("SSE2 detected");
cpu_opt |= CPU_SSE2;
}
return cpu_opt;
}
2011-08-07 17:52:40 +04:00
boolean xf_post_connect(freerdp* instance)
{
xfInfo* xfi;
XGCValues gcv;
rdpCache* cache;
rdpChannels* channels;
RFX_CONTEXT* rfx_context = NULL;
2011-08-07 17:52:40 +04:00
xfi = ((xfContext*) instance->context)->xfi;
cache = instance->context->cache;
channels = xfi->_context->channels;
2011-08-07 17:52:40 +04:00
if (xf_get_pixmap_info(xfi) != true)
return false;
2011-10-21 02:18:45 +04:00
xf_register_graphics(instance->context->graphics);
if (xfi->sw_gdi)
{
rdpGdi* gdi;
uint32 flags;
flags = CLRCONV_ALPHA;
if (xfi->bpp > 16)
flags |= CLRBUF_32BPP;
else
flags |= CLRBUF_16BPP;
gdi_init(instance, flags, NULL);
gdi = instance->context->gdi;
xfi->primary_buffer = gdi->primary_buffer;
rfx_context = gdi->rfx_context;
}
else
{
xfi->srcBpp = instance->settings->color_depth;
xf_gdi_register_update_callbacks(instance->update);
xfi->hdc = gdi_GetDC();
xfi->hdc->bitsPerPixel = xfi->bpp;
xfi->hdc->bytesPerPixel = xfi->bpp / 8;
xfi->hdc->alpha = xfi->clrconv->alpha;
xfi->hdc->invert = xfi->clrconv->invert;
xfi->hdc->rgb555 = xfi->clrconv->rgb555;
xfi->hdc->hwnd = (HGDI_WND) malloc(sizeof(GDI_WND));
xfi->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0);
xfi->hdc->hwnd->invalid->null = 1;
xfi->hdc->hwnd->count = 32;
xfi->hdc->hwnd->cinvalid = (HGDI_RGN) malloc(sizeof(GDI_RGN) * xfi->hdc->hwnd->count);
xfi->hdc->hwnd->ninvalid = 0;
xfi->primary_buffer = (uint8*) xzalloc(xfi->width * xfi->height * xfi->bpp);
if (instance->settings->rfx_codec)
{
rfx_context = (void*) rfx_context_new();
xfi->rfx_context = rfx_context;
}
if (instance->settings->ns_codec)
xfi->nsc_context = (void*) nsc_context_new();
}
2011-08-26 02:07:52 +04:00
if (rfx_context)
{
#ifdef WITH_SSE2
/* detect only if needed */
rfx_context_set_cpu_opt(rfx_context, xf_detect_cpu());
#endif
}
2011-10-07 23:50:07 +04:00
xfi->width = instance->settings->width;
xfi->height = instance->settings->height;
xf_create_window(xfi);
memset(&gcv, 0, sizeof(gcv));
xfi->modifier_map = XGetModifierMapping(xfi->display);
xfi->gc = XCreateGC(xfi->display, xfi->drawable, GCGraphicsExposures, &gcv);
xfi->primary = XCreatePixmap(xfi->display, xfi->drawable, xfi->width, xfi->height, xfi->depth);
xfi->drawing = xfi->primary;
xfi->bitmap_mono = XCreatePixmap(xfi->display, xfi->drawable, 8, 8, 1);
xfi->gc_mono = XCreateGC(xfi->display, xfi->bitmap_mono, GCGraphicsExposures, &gcv);
XSetForeground(xfi->display, xfi->gc, BlackPixelOfScreen(xfi->screen));
XFillRectangle(xfi->display, xfi->primary, xfi->gc, 0, 0, xfi->width, xfi->height);
xfi->image = XCreateImage(xfi->display, xfi->visual, xfi->depth, ZPixmap, 0,
(char*) xfi->primary_buffer, xfi->width, xfi->height, xfi->scanline_pad, 0);
xfi->bmp_codec_none = (uint8*) xmalloc(64 * 64 * 4);
if (xfi->sw_gdi)
{
instance->update->BeginPaint = xf_sw_begin_paint;
instance->update->EndPaint = xf_sw_end_paint;
instance->update->DesktopResize = xf_sw_desktop_resize;
}
else
{
instance->update->BeginPaint = xf_hw_begin_paint;
instance->update->EndPaint = xf_hw_end_paint;
instance->update->DesktopResize = xf_hw_desktop_resize;
}
2011-08-07 17:52:40 +04:00
pointer_cache_register_callbacks(instance->update);
2011-09-29 08:33:16 +04:00
if (xfi->sw_gdi != true)
{
2011-11-24 22:01:34 +04:00
glyph_cache_register_callbacks(instance->update);
brush_cache_register_callbacks(instance->update);
bitmap_cache_register_callbacks(instance->update);
offscreen_cache_register_callbacks(instance->update);
palette_cache_register_callbacks(instance->update);
}
instance->context->rail = rail_new(instance->settings);
rail_register_update_callbacks(instance->context->rail, instance->update);
xf_rail_register_callbacks(xfi, instance->context->rail);
freerdp_channels_post_connect(channels, instance);
2011-08-07 17:52:40 +04:00
2011-09-20 12:27:59 +04:00
xf_tsmf_init(xfi, xv_port);
xfreerdp: a quick workaround for some issues with TS Remote App. Currently in Remote App mode we have no option to interact with the remote desktop host before the first RAIL window is created. In many situations this interaction possibility is absolutely required. One example is that screen which gets displayed if another user is logged on. It requires clicking a button in pre-RAIL mode so that the currently logged on user gets notified to confirm or deny the connection. Another example is the option to log on graphically (e.g. for hosts that don't support NLA) without predefined credentials. Also if the administrator sets the "User must change password at next logon" option there is currently no way to do this in TS Remote App mode. This change basically lets xfreerdp create the main window in Remote App mode like in a normal session and xfi->remote_app is not set to true initially. As soon as the rail exec result event or the first rail window creation request is received (whatever comes first) the main window gets destroyed and xfi->remote_app is set to true. The second change is to disconnect immediately if the rail exec result event reports an error, e.g. if the specified app cannot be found or if it is not in the list of allowed applications. This fixes FreeRDP github issue #143 and issue #308. I'm aware that this is not the most elegant solution but it is definitely an improvement and probably good enough for 1.0. A nicer solution would be hiding the main window and only displaying it if no rail exec result or rail window creation event is received after a certain timeout ...
2012-01-02 13:27:04 +04:00
xf_cliprdr_init(xfi, channels);
2011-09-20 12:27:59 +04:00
return true;
2011-08-07 17:52:40 +04:00
}
boolean xf_authenticate(freerdp* instance, char** username, char** password, char** domain)
{
*password = xmalloc(password_size * sizeof(char));
if (freerdp_passphrase_read("Password: ", *password, password_size) == NULL)
return false;
return true;
}
boolean xf_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint)
{
printf("Certificate details:\n");
printf("\tSubject: %s\n", subject);
printf("\tIssuer: %s\n", issuer);
printf("\tThumbprint: %s\n", fingerprint);
printf("The above X.509 certificate could not be verified, possibly because you do not have "
"the CA certificate in your certificate store, or the certificate has expired. "
"Please look at the documentation on how to create local certificate store for a private CA.\n");
char answer;
while (1)
{
printf("Do you trust the above certificate? (Y/N) ");
answer = fgetc(stdin);
if (answer == 'y' || answer == 'Y')
{
return true;
}
else if (answer == 'n' || answer == 'N')
{
break;
}
}
return false;
}
int xf_process_client_args(rdpSettings* settings, const char* opt, const char* val, void* user_data)
2011-08-26 06:01:33 +04:00
{
2011-09-20 12:27:59 +04:00
int argc = 0;
xfInfo* xfi = (xfInfo*) user_data;
2011-09-20 12:27:59 +04:00
2011-08-26 06:01:33 +04:00
if (strcmp("--kbd-list", opt) == 0)
{
int i;
rdpKeyboardLayout* layouts;
layouts = freerdp_kbd_get_layouts(RDP_KEYBOARD_LAYOUT_TYPE_STANDARD);
printf("\nKeyboard Layouts\n");
for (i = 0; layouts[i].code; i++)
printf("0x%08X\t%s\n", layouts[i].code, layouts[i].name);
free(layouts);
layouts = freerdp_kbd_get_layouts(RDP_KEYBOARD_LAYOUT_TYPE_VARIANT);
printf("\nKeyboard Layout Variants\n");
for (i = 0; layouts[i].code; i++)
printf("0x%08X\t%s\n", layouts[i].code, layouts[i].name);
free(layouts);
layouts = freerdp_kbd_get_layouts(RDP_KEYBOARD_LAYOUT_TYPE_IME);
printf("\nKeyboard Input Method Editors (IMEs)\n");
for (i = 0; layouts[i].code; i++)
printf("0x%08X\t%s\n", layouts[i].code, layouts[i].name);
free(layouts);
exit(0);
}
2011-09-20 12:27:59 +04:00
else if (strcmp("--xv-port", opt) == 0)
{
xv_port = atoi(val);
argc = 2;
}
else if (strcmp("--dbg-x11", opt) == 0)
{
xfi->debug = true;
argc = 1;
}
2011-08-26 06:01:33 +04:00
2011-09-20 12:27:59 +04:00
return argc;
2011-08-26 06:01:33 +04:00
}
2011-08-18 01:28:26 +04:00
int xf_process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data)
2011-08-07 17:52:40 +04:00
{
rdpChannels* channels = (rdpChannels*) user_data;
2011-08-07 17:52:40 +04:00
printf("loading plugin %s\n", name);
freerdp_channels_load_plugin(channels, settings, name, plugin_data);
2011-08-07 17:52:40 +04:00
return 1;
}
int xf_receive_channel_data(freerdp* instance, int channelId, uint8* data, int size, int flags, int total_size)
2011-08-07 17:52:40 +04:00
{
return freerdp_channels_data(instance, channelId, data, size, flags, total_size);
2011-08-07 17:52:40 +04:00
}
void xf_process_channel_event(rdpChannels* chanman, freerdp* instance)
2011-08-07 17:52:40 +04:00
{
xfInfo* xfi;
2011-08-18 01:28:26 +04:00
RDP_EVENT* event;
2011-08-07 17:52:40 +04:00
xfi = ((xfContext*) instance->context)->xfi;
event = freerdp_channels_pop_event(chanman);
2011-08-07 17:52:40 +04:00
if (event)
{
switch (event->event_class)
{
case RDP_EVENT_CLASS_RAIL:
xf_process_rail_event(xfi, chanman, event);
break;
2011-09-20 12:27:59 +04:00
case RDP_EVENT_CLASS_TSMF:
xf_process_tsmf_event(xfi, event);
break;
2011-09-20 12:27:59 +04:00
case RDP_EVENT_CLASS_CLIPRDR:
2011-09-23 07:37:17 +04:00
xf_process_cliprdr_event(xfi, event);
2011-08-07 17:52:40 +04:00
break;
2011-09-20 12:27:59 +04:00
2011-08-07 17:52:40 +04:00
default:
break;
}
2011-09-20 12:27:59 +04:00
2011-08-07 17:52:40 +04:00
freerdp_event_free(event);
}
}
void xf_window_free(xfInfo* xfi)
{
rdpContext* context = xfi->instance->context;
XFreeModifiermap(xfi->modifier_map);
xfi->modifier_map = 0;
XFreeGC(xfi->display, xfi->gc);
xfi->gc = 0;
xfreerdp: a quick workaround for some issues with TS Remote App. Currently in Remote App mode we have no option to interact with the remote desktop host before the first RAIL window is created. In many situations this interaction possibility is absolutely required. One example is that screen which gets displayed if another user is logged on. It requires clicking a button in pre-RAIL mode so that the currently logged on user gets notified to confirm or deny the connection. Another example is the option to log on graphically (e.g. for hosts that don't support NLA) without predefined credentials. Also if the administrator sets the "User must change password at next logon" option there is currently no way to do this in TS Remote App mode. This change basically lets xfreerdp create the main window in Remote App mode like in a normal session and xfi->remote_app is not set to true initially. As soon as the rail exec result event or the first rail window creation request is received (whatever comes first) the main window gets destroyed and xfi->remote_app is set to true. The second change is to disconnect immediately if the rail exec result event reports an error, e.g. if the specified app cannot be found or if it is not in the list of allowed applications. This fixes FreeRDP github issue #143 and issue #308. I'm aware that this is not the most elegant solution but it is definitely an improvement and probably good enough for 1.0. A nicer solution would be hiding the main window and only displaying it if no rail exec result or rail window creation event is received after a certain timeout ...
2012-01-02 13:27:04 +04:00
if (xfi->window != NULL)
{
xf_DestroyWindow(xfi, xfi->window);
xfi->window = NULL;
}
if (xfi->primary)
{
XFreePixmap(xfi->display, xfi->primary);
xfi->primary = 0;
}
2011-09-07 09:51:29 +04:00
if (xfi->image)
{
xfi->image->data = NULL;
XDestroyImage(xfi->image);
xfi->image = NULL;
}
if (context != NULL)
2011-09-07 09:51:29 +04:00
{
if (context->cache != NULL)
{
cache_free(context->cache);
context->cache = NULL;
}
if (context->rail != NULL)
{
rail_free(context->rail);
context->rail = NULL;
}
2011-09-07 09:51:29 +04:00
}
2011-09-07 10:19:11 +04:00
2011-10-19 00:50:40 +04:00
if (xfi->rfx_context)
{
rfx_context_free(xfi->rfx_context);
xfi->rfx_context = NULL;
}
2011-09-07 10:19:11 +04:00
xfree(xfi->clrconv);
2011-09-20 12:27:59 +04:00
xf_tsmf_uninit(xfi);
2011-09-23 07:37:17 +04:00
xf_cliprdr_uninit(xfi);
}
void xf_free(xfInfo* xfi)
{
xf_window_free(xfi);
XCloseDisplay(xfi->display);
2011-08-13 07:46:00 +04:00
xfree(xfi);
}
2011-08-13 07:46:00 +04:00
int xfreerdp_run(freerdp* instance)
2011-08-07 17:52:40 +04:00
{
int i;
int fds;
xfInfo* xfi;
2011-08-07 17:52:40 +04:00
int max_fds;
int rcount;
int wcount;
2011-12-12 03:05:32 +04:00
int ret = 0;
2011-08-07 17:52:40 +04:00
void* rfds[32];
void* wfds[32];
fd_set rfds_set;
fd_set wfds_set;
2011-12-12 03:05:32 +04:00
int select_status;
rdpChannels* channels;
2011-12-12 03:05:32 +04:00
struct timeval timeout;
2011-08-07 17:52:40 +04:00
memset(rfds, 0, sizeof(rfds));
memset(wfds, 0, sizeof(wfds));
2011-12-12 03:05:32 +04:00
memset(&timeout, 0, sizeof(struct timeval));
2011-08-07 17:52:40 +04:00
if (!freerdp_connect(instance))
return XF_EXIT_CONN_FAILED;
2011-08-13 07:46:00 +04:00
xfi = ((xfContext*) instance->context)->xfi;
channels = instance->context->channels;
2011-08-07 17:52:40 +04:00
xfreerdp: a quick workaround for some issues with TS Remote App. Currently in Remote App mode we have no option to interact with the remote desktop host before the first RAIL window is created. In many situations this interaction possibility is absolutely required. One example is that screen which gets displayed if another user is logged on. It requires clicking a button in pre-RAIL mode so that the currently logged on user gets notified to confirm or deny the connection. Another example is the option to log on graphically (e.g. for hosts that don't support NLA) without predefined credentials. Also if the administrator sets the "User must change password at next logon" option there is currently no way to do this in TS Remote App mode. This change basically lets xfreerdp create the main window in Remote App mode like in a normal session and xfi->remote_app is not set to true initially. As soon as the rail exec result event or the first rail window creation request is received (whatever comes first) the main window gets destroyed and xfi->remote_app is set to true. The second change is to disconnect immediately if the rail exec result event reports an error, e.g. if the specified app cannot be found or if it is not in the list of allowed applications. This fixes FreeRDP github issue #143 and issue #308. I'm aware that this is not the most elegant solution but it is definitely an improvement and probably good enough for 1.0. A nicer solution would be hiding the main window and only displaying it if no rail exec result or rail window creation event is received after a certain timeout ...
2012-01-02 13:27:04 +04:00
while (!xfi->disconnect)
2011-08-07 17:52:40 +04:00
{
rcount = 0;
wcount = 0;
if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != true)
2011-08-07 17:52:40 +04:00
{
printf("Failed to get FreeRDP file descriptor\n");
ret = XF_EXIT_CONN_FAILED;
2011-08-07 17:52:40 +04:00
break;
}
if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != true)
2011-08-07 17:52:40 +04:00
{
printf("Failed to get channel manager file descriptor\n");
ret = XF_EXIT_CONN_FAILED;
2011-08-07 17:52:40 +04:00
break;
}
if (xf_get_fds(instance, rfds, &rcount, wfds, &wcount) != true)
2011-08-07 17:52:40 +04:00
{
printf("Failed to get xfreerdp file descriptor\n");
ret = XF_EXIT_CONN_FAILED;
2011-08-07 17:52:40 +04:00
break;
}
max_fds = 0;
FD_ZERO(&rfds_set);
FD_ZERO(&wfds_set);
2011-08-07 17:52:40 +04:00
for (i = 0; i < rcount; i++)
{
fds = (int)(long)(rfds[i]);
if (fds > max_fds)
max_fds = fds;
FD_SET(fds, &rfds_set);
}
if (max_fds == 0)
break;
2011-12-12 03:05:32 +04:00
timeout.tv_sec = 5;
select_status = select(max_fds + 1, &rfds_set, &wfds_set, NULL, &timeout);
if (select_status == 0)
{
//freerdp_send_keep_alive(instance);
continue;
}
else if (select_status == -1)
2011-08-07 17:52:40 +04:00
{
/* these are not really errors */
if (!((errno == EAGAIN) ||
(errno == EWOULDBLOCK) ||
(errno == EINPROGRESS) ||
(errno == EINTR))) /* signal occurred */
{
printf("xfreerdp_run: select failed\n");
2011-08-07 17:52:40 +04:00
break;
}
}
if (freerdp_check_fds(instance) != true)
2011-08-07 17:52:40 +04:00
{
printf("Failed to check FreeRDP file descriptor\n");
break;
}
if (xf_check_fds(instance, &rfds_set) != true)
2011-08-07 17:52:40 +04:00
{
printf("Failed to check xfreerdp file descriptor\n");
2011-08-07 17:52:40 +04:00
break;
}
if (freerdp_channels_check_fds(channels, instance) != true)
2011-08-07 17:52:40 +04:00
{
printf("Failed to check channel manager file descriptor\n");
break;
}
xf_process_channel_event(channels, instance);
2011-08-07 17:52:40 +04:00
}
if (!ret)
ret = freerdp_error_info(instance);
freerdp_channels_close(channels, instance);
freerdp_channels_free(channels);
freerdp_disconnect(instance);
2011-09-07 09:51:29 +04:00
gdi_free(instance);
xf_free(xfi);
2011-08-07 17:52:40 +04:00
freerdp_free(instance);
return ret;
2011-08-07 17:52:40 +04:00
}
void* thread_func(void* param)
{
struct thread_data* data;
data = (struct thread_data*) param;
g_disconnect_reason = xfreerdp_run(data->instance);
2011-08-07 17:52:40 +04:00
xfree(data);
pthread_detach(pthread_self());
g_thread_count--;
if (g_thread_count < 1)
2011-08-13 07:46:00 +04:00
freerdp_sem_signal(g_sem);
2011-08-07 17:52:40 +04:00
return NULL;
}
static uint8 exit_code_from_disconnect_reason(uint32 reason)
{
if (reason == 0 ||
(reason >= XF_EXIT_PARSE_ARGUMENTS && reason <= XF_EXIT_CONN_FAILED))
return reason;
/* Licence error set */
else if (reason >= 0x100 && reason <= 0x10A)
reason -= 0x100 + XF_EXIT_LICENSE_INTERNAL;
/* RDP protocol error set */
else if (reason >= 0x10c9 && reason <= 0x1193)
reason = XF_EXIT_RDP;
/* There's no need to test protocol-independent codes: they match */
else if (!(reason <= 0xB))
reason = XF_EXIT_UNKNOWN;
return reason;
}
2011-08-07 17:52:40 +04:00
int main(int argc, char* argv[])
{
pthread_t thread;
freerdp* instance;
struct thread_data* data;
2011-08-07 17:52:40 +04:00
2011-09-28 09:27:14 +04:00
freerdp_handle_signals();
2011-08-09 04:31:21 +04:00
setlocale(LC_ALL, "");
freerdp_channels_global_init();
2011-08-07 17:52:40 +04:00
g_sem = freerdp_sem_new(1);
instance = freerdp_new();
instance->PreConnect = xf_pre_connect;
instance->PostConnect = xf_post_connect;
instance->Authenticate = xf_authenticate;
instance->VerifyCertificate = xf_verify_certificate;
2011-08-07 17:52:40 +04:00
instance->ReceiveChannelData = xf_receive_channel_data;
instance->context_size = sizeof(xfContext);
instance->ContextNew = (pContextNew) xf_context_new;
instance->ContextFree = (pContextFree) xf_context_free;
freerdp_context_new(instance);
2011-08-07 17:52:40 +04:00
instance->context->argc = argc;
instance->context->argv = argv;
instance->settings->sw_gdi = false;
2011-08-07 17:52:40 +04:00
data = (struct thread_data*) xzalloc(sizeof(struct thread_data));
data->instance = instance;
g_thread_count++;
pthread_create(&thread, 0, thread_func, data);
while (g_thread_count > 0)
{
freerdp_sem_wait(g_sem);
}
freerdp_channels_global_uninit();
2011-08-07 17:52:40 +04:00
return exit_code_from_disconnect_reason(g_disconnect_reason);
2011-08-07 17:52:40 +04:00
}