Merge pull request #1754 from awakecoding/master

Multimon Fix, xfreerdp extensibility, context-specific error handling, Gateway LAN auto-detect
This commit is contained in:
Marc-André Moreau 2014-03-25 15:26:38 -04:00
commit caecf1823b
35 changed files with 748 additions and 265 deletions

View File

@ -1091,8 +1091,6 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
rdpsnd->log = WLog_Get("com.freerdp.channels.rdpsnd.client"); rdpsnd->log = WLog_Get("com.freerdp.channels.rdpsnd.client");
WLog_SetLogLevel(rdpsnd->log, WLOG_TRACE);
rdpsnd->channelEntryPoints.pVirtualChannelInit(&rdpsnd->InitHandle, rdpsnd->channelEntryPoints.pVirtualChannelInit(&rdpsnd->InitHandle,
&rdpsnd->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, rdpsnd_virtual_channel_init_event); &rdpsnd->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, rdpsnd_virtual_channel_init_event);

View File

@ -868,7 +868,7 @@ BOOL xf_pre_connect(freerdp* instance)
xfc->WM_DELETE_WINDOW = XInternAtom(xfc->display, "WM_DELETE_WINDOW", False); xfc->WM_DELETE_WINDOW = XInternAtom(xfc->display, "WM_DELETE_WINDOW", False);
xfc->WM_STATE = XInternAtom(xfc->display, "WM_STATE", False); xfc->WM_STATE = XInternAtom(xfc->display, "WM_STATE", False);
xf_kbd_init(xfc); xf_keyboard_init(xfc);
xfc->clrconv = freerdp_clrconv_new(CLRCONV_ALPHA); xfc->clrconv = freerdp_clrconv_new(CLRCONV_ALPHA);
@ -972,10 +972,10 @@ BOOL xf_post_connect(freerdp* instance)
ZeroMemory(&gcv, sizeof(gcv)); ZeroMemory(&gcv, sizeof(gcv));
if (xfc->modifier_map) if (xfc->modifierMap)
XFreeModifiermap(xfc->modifier_map); XFreeModifiermap(xfc->modifierMap);
xfc->modifier_map = XGetModifierMapping(xfc->display); xfc->modifierMap = XGetModifierMapping(xfc->display);
xfc->gc = XCreateGC(xfc->display, xfc->drawable, GCGraphicsExposures, &gcv); xfc->gc = XCreateGC(xfc->display, xfc->drawable, GCGraphicsExposures, &gcv);
xfc->primary = XCreatePixmap(xfc->display, xfc->drawable, xfc->width, xfc->height, xfc->depth); xfc->primary = XCreatePixmap(xfc->display, xfc->drawable, xfc->width, xfc->height, xfc->depth);
@ -1161,11 +1161,7 @@ void xf_window_free(xfContext* xfc)
{ {
rdpContext* context = (rdpContext*) xfc; rdpContext* context = (rdpContext*) xfc;
if (xfc->modifier_map) xf_keyboard_free(xfc);
{
XFreeModifiermap(xfc->modifier_map);
xfc->modifier_map = NULL;
}
if (xfc->gc) if (xfc->gc)
{ {
@ -1515,8 +1511,8 @@ void* xf_thread(void* param)
*/ */
if (freerdp_focus_required(instance)) if (freerdp_focus_required(instance))
{ {
xf_kbd_focus_in(xfc); xf_keyboard_focus_in(xfc);
xf_kbd_focus_in(xfc); xf_keyboard_focus_in(xfc);
} }
if (!async_transport) if (!async_transport)

View File

@ -87,6 +87,99 @@ const char* const X11_EVENT_STRINGS[] =
#define DEBUG_X11_LMS(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) #define DEBUG_X11_LMS(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#endif #endif
int xf_event_action_script_init(xfContext* xfc)
{
int exitCode;
char* xevent;
FILE* actionScript;
char buffer[1024] = { 0 };
char command[1024] = { 0 };
xfc->xevents = ArrayList_New(TRUE);
ArrayList_Object(xfc->xevents)->fnObjectFree = free;
sprintf_s(command, sizeof(command), "%s xevent", xfc->actionScript);
actionScript = popen(command, "r");
if (actionScript < 0)
return -1;
while (fgets(buffer, sizeof(buffer), actionScript) != NULL)
{
strtok(buffer, "\n");
xevent = _strdup(buffer);
ArrayList_Add(xfc->xevents, xevent);
}
exitCode = pclose(actionScript);
return 1;
}
void xf_event_action_script_free(xfContext* xfc)
{
if (xfc->xevents)
{
ArrayList_Free(xfc->xevents);
xfc->xevents = NULL;
}
}
int xf_event_execute_action_script(xfContext* xfc, XEvent* event)
{
int index;
int count;
char* name;
int exitCode;
FILE* actionScript;
BOOL match = FALSE;
const char* xeventName;
char buffer[1024] = { 0 };
char command[1024] = { 0 };
if (!xfc->actionScript)
return 1;
if (event->type > (sizeof(X11_EVENT_STRINGS) / sizeof(const char*)))
return 1;
xeventName = X11_EVENT_STRINGS[event->type];
count = ArrayList_Count(xfc->xevents);
for (index = 0; index < count; index++)
{
name = (char*) ArrayList_GetItem(xfc->xevents, index);
if (_stricmp(name, xeventName) == 0)
{
match = TRUE;
break;
}
}
if (!match)
return 1;
sprintf_s(command, sizeof(command), "%s xevent %s %d",
xfc->actionScript, xeventName, (int) xfc->window->handle);
actionScript = popen(command, "r");
if (actionScript < 0)
return -1;
while (fgets(buffer, sizeof(buffer), actionScript) != NULL)
{
strtok(buffer, "\n");
}
exitCode = pclose(actionScript);
return 1;
}
static BOOL xf_event_Expose(xfContext* xfc, XEvent* event, BOOL app) static BOOL xf_event_Expose(xfContext* xfc, XEvent* event, BOOL app)
{ {
int x, y; int x, y;
@ -395,34 +488,28 @@ static BOOL xf_event_KeyPress(xfContext* xfc, XEvent* event, BOOL app)
XLookupString((XKeyEvent*) event, str, sizeof(str), &keysym, NULL); XLookupString((XKeyEvent*) event, str, sizeof(str), &keysym, NULL);
xf_kbd_set_keypress(xfc, event->xkey.keycode, keysym); xf_keyboard_key_press(xfc, event->xkey.keycode, keysym);
if (xfc->fullscreen_toggle && xf_kbd_handle_special_keys(xfc, keysym))
return TRUE;
xf_kbd_send_key(xfc, TRUE, event->xkey.keycode);
return TRUE; return TRUE;
} }
static BOOL xf_event_KeyRelease(xfContext* xfc, XEvent* event, BOOL app) static BOOL xf_event_KeyRelease(xfContext* xfc, XEvent* event, BOOL app)
{ {
XEvent next_event; XEvent nextEvent;
if (XPending(xfc->display)) if (XPending(xfc->display))
{ {
ZeroMemory(&next_event, sizeof(next_event)); ZeroMemory(&nextEvent, sizeof(nextEvent));
XPeekEvent(xfc->display, &next_event); XPeekEvent(xfc->display, &nextEvent);
if (next_event.type == KeyPress) if (nextEvent.type == KeyPress)
{ {
if (next_event.xkey.keycode == event->xkey.keycode) if (nextEvent.xkey.keycode == event->xkey.keycode)
return TRUE; return TRUE;
} }
} }
xf_kbd_unset_keypress(xfc, event->xkey.keycode); xf_keyboard_key_release(xfc, event->xkey.keycode);
xf_kbd_send_key(xfc, FALSE, event->xkey.keycode);
return TRUE; return TRUE;
} }
@ -451,7 +538,7 @@ static BOOL xf_event_FocusIn(xfContext* xfc, XEvent* event, BOOL app)
xf_rail_adjust_position(xfc, window); xf_rail_adjust_position(xfc, window);
} }
xf_kbd_focus_in(xfc); xf_keyboard_focus_in(xfc);
if (!app) if (!app)
xf_cliprdr_check_owner(xfc); xf_cliprdr_check_owner(xfc);
@ -469,7 +556,7 @@ static BOOL xf_event_FocusOut(xfContext* xfc, XEvent* event, BOOL app)
if (event->xfocus.mode == NotifyWhileGrabbed) if (event->xfocus.mode == NotifyWhileGrabbed)
XUngrabKeyboard(xfc->display, CurrentTime); XUngrabKeyboard(xfc->display, CurrentTime);
xf_kbd_clear(xfc); xf_keyboard_clear(xfc);
if (app) if (app)
xf_rail_send_activate(xfc, event->xany.window, FALSE); xf_rail_send_activate(xfc, event->xany.window, FALSE);
@ -481,10 +568,10 @@ static BOOL xf_event_MappingNotify(xfContext* xfc, XEvent* event, BOOL app)
{ {
if (event->xmapping.request == MappingModifier) if (event->xmapping.request == MappingModifier)
{ {
if (xfc->modifier_map) if (xfc->modifierMap)
XFreeModifiermap(xfc->modifier_map); XFreeModifiermap(xfc->modifierMap);
xfc->modifier_map = XGetModifierMapping(xfc->display); xfc->modifierMap = XGetModifierMapping(xfc->display);
} }
return TRUE; return TRUE;
@ -681,7 +768,7 @@ static BOOL xf_event_UnmapNotify(xfContext* xfc, XEvent* event, BOOL app)
rdpUpdate* update = xfc->instance->update; rdpUpdate* update = xfc->instance->update;
rdpRail* rail = ((rdpContext*) xfc)->rail; rdpRail* rail = ((rdpContext*) xfc)->rail;
xf_kbd_release_all_keypress(xfc); xf_keyboard_release_all_keypress(xfc);
if (!app) if (!app)
{ {
@ -941,6 +1028,8 @@ BOOL xf_event_process(freerdp* instance, XEvent* event)
} }
} }
xf_event_execute_action_script(xfc, event);
if (event->type != MotionNotify) if (event->type != MotionNotify)
DEBUG_X11("%s Event(%d): wnd=0x%04X", X11_EVENT_STRINGS[event->type], event->type, (UINT32) event->xany.window); DEBUG_X11("%s Event(%d): wnd=0x%04X", X11_EVENT_STRINGS[event->type], event->type, (UINT32) event->xany.window);

View File

@ -25,6 +25,9 @@
#include "xf_client.h" #include "xf_client.h"
#include "xfreerdp.h" #include "xfreerdp.h"
int xf_event_action_script_init(xfContext* xfc);
void xf_event_action_script_free(xfContext* xfc);
BOOL xf_event_process(freerdp* instance, XEvent* event); BOOL xf_event_process(freerdp* instance, XEvent* event);
void xf_event_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs, ...); void xf_event_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs, ...);

View File

@ -236,7 +236,6 @@ void xf_input_save_last_event(XGenericEventCookie* cookie)
lastEvent.detail = event->detail; lastEvent.detail = event->detail;
lastEvent.event_x = event->event_x; lastEvent.event_x = event->event_x;
lastEvent.event_y = event->event_y; lastEvent.event_y = event->event_y;
} }
void xf_input_detect_pan(xfContext* xfc) void xf_input_detect_pan(xfContext* xfc)
@ -269,13 +268,10 @@ void xf_input_detect_pan(xfContext* xfc)
dist_x = fabs(contacts[0].pos_x - contacts[1].pos_x); dist_x = fabs(contacts[0].pos_x - contacts[1].pos_x);
dist_y = fabs(contacts[0].pos_y - contacts[1].pos_y); dist_y = fabs(contacts[0].pos_y - contacts[1].pos_y);
if (dist_y > MIN_FINGER_DIST)
//only pan in x if dist_y is greater than something
if(dist_y > MIN_FINGER_DIST)
{ {
if (px_vector > PAN_THRESHOLD)
if(px_vector > PAN_THRESHOLD)
{ {
{ {
@ -293,7 +289,7 @@ void xf_input_detect_pan(xfContext* xfc)
py_vector = 0; py_vector = 0;
z_vector = 0; z_vector = 0;
} }
else if(px_vector < -PAN_THRESHOLD) else if (px_vector < -PAN_THRESHOLD)
{ {
{ {
PanningChangeEventArgs e; PanningChangeEventArgs e;
@ -313,10 +309,10 @@ void xf_input_detect_pan(xfContext* xfc)
} }
if(dist_x > MIN_FINGER_DIST) if (dist_x > MIN_FINGER_DIST)
{ {
if(py_vector > PAN_THRESHOLD) if (py_vector > PAN_THRESHOLD)
{ {
{ {
PanningChangeEventArgs e; PanningChangeEventArgs e;
@ -333,7 +329,7 @@ void xf_input_detect_pan(xfContext* xfc)
py_vector = 0; py_vector = 0;
z_vector = 0; z_vector = 0;
} }
else if(py_vector < -PAN_THRESHOLD) else if (py_vector < -PAN_THRESHOLD)
{ {
{ {
PanningChangeEventArgs e; PanningChangeEventArgs e;
@ -351,7 +347,6 @@ void xf_input_detect_pan(xfContext* xfc)
z_vector = 0; z_vector = 0;
} }
} }
} }
void xf_input_detect_pinch(xfContext* xfc) void xf_input_detect_pinch(xfContext* xfc)
@ -368,7 +363,6 @@ void xf_input_detect_pinch(xfContext* xfc)
return; return;
} }
/* first calculate the distance */ /* first calculate the distance */
dist = sqrt(pow(contacts[1].pos_x - contacts[0].last_x, 2.0) + dist = sqrt(pow(contacts[1].pos_x - contacts[0].last_x, 2.0) +
pow(contacts[1].pos_y - contacts[0].last_y, 2.0)); pow(contacts[1].pos_y - contacts[0].last_y, 2.0));
@ -399,7 +393,6 @@ void xf_input_detect_pinch(xfContext* xfc)
z_vector += delta; z_vector += delta;
lastDist = dist; lastDist = dist;
if (z_vector > ZOOM_THRESHOLD) if (z_vector > ZOOM_THRESHOLD)
@ -451,8 +444,6 @@ void xf_input_detect_pinch(xfContext* xfc)
void xf_input_touch_begin(xfContext* xfc, XIDeviceEvent* event) void xf_input_touch_begin(xfContext* xfc, XIDeviceEvent* event)
{ {
int i; int i;
if(active_contacts == MAX_CONTACTS)
printf("Houston, we have a problem!\n\n");
for (i = 0; i < MAX_CONTACTS; i++) for (i = 0; i < MAX_CONTACTS; i++)
{ {
@ -472,6 +463,7 @@ void xf_input_touch_begin(xfContext* xfc, XIDeviceEvent* event)
void xf_input_touch_update(xfContext* xfc, XIDeviceEvent* event) void xf_input_touch_update(xfContext* xfc, XIDeviceEvent* event)
{ {
int i; int i;
for (i = 0; i < MAX_CONTACTS; i++) for (i = 0; i < MAX_CONTACTS; i++)
{ {
if (contacts[i].id == event->detail) if (contacts[i].id == event->detail)
@ -493,14 +485,13 @@ void xf_input_touch_update(xfContext* xfc, XIDeviceEvent* event)
void xf_input_touch_end(xfContext* xfc, XIDeviceEvent* event) void xf_input_touch_end(xfContext* xfc, XIDeviceEvent* event)
{ {
int i; int i;
for (i = 0; i < MAX_CONTACTS; i++) for (i = 0; i < MAX_CONTACTS; i++)
{ {
if (contacts[i].id == event->detail) if (contacts[i].id == event->detail)
{ {
contacts[i].id = 0; contacts[i].id = 0;
contacts[i].count = 0; contacts[i].count = 0;
//contacts[i].pos_x = (int)event->event_x;
//contacts[i].pos_y = (int)event->event_y;
active_contacts--; active_contacts--;
break;printf("TouchBegin\n"); break;printf("TouchBegin\n");
@ -733,15 +724,15 @@ void xf_process_rdpei_event(xfContext* xfc, wMessage* event)
int xf_input_handle_event(xfContext* xfc, XEvent* event) int xf_input_handle_event(xfContext* xfc, XEvent* event)
{ {
#ifdef WITH_XI #ifdef WITH_XI
//printf("m:%d g:%d\n", (xfc->settings->MultiTouchInput), (xfc->settings->MultiTouchGestures) );
if (xfc->settings->MultiTouchInput) if (xfc->settings->MultiTouchInput)
{ {
return xf_input_handle_event_remote(xfc, event); return xf_input_handle_event_remote(xfc, event);
} }
if (xfc->settings->MultiTouchGestures) if (xfc->settings->MultiTouchGestures)
{
return xf_input_handle_event_local(xfc, event); return xf_input_handle_event_local(xfc, event);
}
#endif #endif
return 0; return 0;

View File

@ -26,6 +26,8 @@
#include <string.h> #include <string.h>
#include <winpr/crt.h> #include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/collections.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
@ -33,66 +35,153 @@
#include <freerdp/locale/keyboard.h> #include <freerdp/locale/keyboard.h>
#include "xf_event.h"
#include "xf_keyboard.h" #include "xf_keyboard.h"
void xf_kbd_init(xfContext* xfc) int xf_keyboard_action_script_init(xfContext* xfc)
{ {
xf_kbd_clear(xfc); int exitCode;
FILE* keyScript;
char* keyCombination;
char buffer[1024] = { 0 };
char command[1024] = { 0 };
xfc->keyboard_layout_id = xfc->instance->settings->KeyboardLayout; if (xfc->actionScript)
xfc->keyboard_layout_id = freerdp_keyboard_init(xfc->keyboard_layout_id); {
xfc->instance->settings->KeyboardLayout = xfc->keyboard_layout_id; free(xfc->actionScript);
xfc->actionScript = NULL;
}
if (xfc->modifier_map) if (PathFileExistsA("/usr/share/freerdp/action.sh"))
XFreeModifiermap(xfc->modifier_map); xfc->actionScript = _strdup("/usr/share/freerdp/action.sh");
xfc->modifier_map = XGetModifierMapping(xfc->display); if (!xfc->actionScript)
return 0;
xfc->keyCombinations = ArrayList_New(TRUE);
ArrayList_Object(xfc->keyCombinations)->fnObjectFree = free;
sprintf_s(command, sizeof(command), "%s key", xfc->actionScript);
keyScript = popen(command, "r");
if (keyScript < 0)
{
free(xfc->actionScript);
xfc->actionScript = NULL;
return 0;
}
while (fgets(buffer, sizeof(buffer), keyScript) != NULL)
{
strtok(buffer, "\n");
keyCombination = _strdup(buffer);
ArrayList_Add(xfc->keyCombinations, keyCombination);
}
exitCode = pclose(keyScript);
xf_event_action_script_init(xfc);
return 1;
} }
void xf_kbd_clear(xfContext* xfc) void xf_keyboard_action_script_free(xfContext* xfc)
{ {
ZeroMemory(xfc->pressed_keys, 256 * sizeof(BOOL)); xf_event_action_script_free(xfc);
if (xfc->keyCombinations)
{
ArrayList_Free(xfc->keyCombinations);
xfc->keyCombinations = NULL;
}
if (xfc->actionScript)
{
free(xfc->actionScript);
xfc->actionScript = NULL;
}
} }
void xf_kbd_set_keypress(xfContext* xfc, BYTE keycode, KeySym keysym) void xf_keyboard_init(xfContext* xfc)
{ {
if (keycode >= 8) xf_keyboard_clear(xfc);
xfc->pressed_keys[keycode] = keysym;
else xfc->KeyboardLayout = xfc->instance->settings->KeyboardLayout;
xfc->KeyboardLayout = freerdp_keyboard_init(xfc->KeyboardLayout);
xfc->instance->settings->KeyboardLayout = xfc->KeyboardLayout;
if (xfc->modifierMap)
XFreeModifiermap(xfc->modifierMap);
xfc->modifierMap = XGetModifierMapping(xfc->display);
xf_keyboard_action_script_init(xfc);
}
void xf_keyboard_free(xfContext* xfc)
{
if (xfc->modifierMap)
{
XFreeModifiermap(xfc->modifierMap);
xfc->modifierMap = NULL;
}
xf_keyboard_action_script_free(xfc);
}
void xf_keyboard_clear(xfContext* xfc)
{
ZeroMemory(xfc->KeyboardState, 256 * sizeof(BOOL));
}
void xf_keyboard_key_press(xfContext* xfc, BYTE keycode, KeySym keysym)
{
if (keycode < 8)
return; return;
}
void xf_kbd_unset_keypress(xfContext* xfc, BYTE keycode) xfc->KeyboardState[keycode] = keysym;
{
if (keycode >= 8) if (xf_keyboard_handle_special_keys(xfc, keysym))
xfc->pressed_keys[keycode] = NoSymbol;
else
return; return;
xf_keyboard_send_key(xfc, TRUE, keycode);
} }
void xf_kbd_release_all_keypress(xfContext* xfc) void xf_keyboard_key_release(xfContext* xfc, BYTE keycode)
{
if (keycode < 8)
return;
xfc->KeyboardState[keycode] = NoSymbol;
xf_keyboard_send_key(xfc, FALSE, keycode);
}
void xf_keyboard_release_all_keypress(xfContext* xfc)
{ {
int keycode; int keycode;
DWORD rdp_scancode; DWORD rdp_scancode;
for (keycode = 0; keycode < ARRAYSIZE(xfc->pressed_keys); keycode++) for (keycode = 0; keycode < ARRAYSIZE(xfc->KeyboardState); keycode++)
{ {
if (xfc->pressed_keys[keycode] != NoSymbol) if (xfc->KeyboardState[keycode] != NoSymbol)
{ {
rdp_scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(keycode); rdp_scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(keycode);
freerdp_input_send_keyboard_event_ex(xfc->instance->input, FALSE, rdp_scancode); freerdp_input_send_keyboard_event_ex(xfc->instance->input, FALSE, rdp_scancode);
xfc->pressed_keys[keycode] = NoSymbol; xfc->KeyboardState[keycode] = NoSymbol;
} }
} }
} }
BOOL xf_kbd_key_pressed(xfContext* xfc, KeySym keysym) BOOL xf_keyboard_key_pressed(xfContext* xfc, KeySym keysym)
{ {
KeyCode keycode = XKeysymToKeycode(xfc->display, keysym); KeyCode keycode = XKeysymToKeycode(xfc->display, keysym);
return (xfc->pressed_keys[keycode] == keysym); return (xfc->KeyboardState[keycode] == keysym);
} }
void xf_kbd_send_key(xfContext* xfc, BOOL down, BYTE keycode) void xf_keyboard_send_key(xfContext* xfc, BOOL down, BYTE keycode)
{ {
DWORD rdp_scancode; DWORD rdp_scancode;
rdpInput* input; rdpInput* input;
@ -105,7 +194,7 @@ void xf_kbd_send_key(xfContext* xfc, BOOL down, BYTE keycode)
fprintf(stderr, "Unknown key with X keycode 0x%02x\n", keycode); fprintf(stderr, "Unknown key with X keycode 0x%02x\n", keycode);
} }
else if (rdp_scancode == RDP_SCANCODE_PAUSE && else if (rdp_scancode == RDP_SCANCODE_PAUSE &&
!xf_kbd_key_pressed(xfc, XK_Control_L) && !xf_kbd_key_pressed(xfc, XK_Control_R)) !xf_keyboard_key_pressed(xfc, XK_Control_L) && !xf_keyboard_key_pressed(xfc, XK_Control_R))
{ {
/* Pause without Ctrl has to be sent as Ctrl + NumLock. */ /* Pause without Ctrl has to be sent as Ctrl + NumLock. */
if (down) if (down)
@ -123,13 +212,13 @@ void xf_kbd_send_key(xfContext* xfc, BOOL down, BYTE keycode)
if ((rdp_scancode == RDP_SCANCODE_CAPSLOCK) && (down == FALSE)) if ((rdp_scancode == RDP_SCANCODE_CAPSLOCK) && (down == FALSE))
{ {
UINT32 syncFlags; UINT32 syncFlags;
syncFlags = xf_kbd_get_toggle_keys_state(xfc); syncFlags = xf_keyboard_get_toggle_keys_state(xfc);
input->SynchronizeEvent(input, syncFlags); input->SynchronizeEvent(input, syncFlags);
} }
} }
} }
int xf_kbd_read_keyboard_state(xfContext* xfc) int xf_keyboard_read_keyboard_state(xfContext* xfc)
{ {
int dummy; int dummy;
Window wdummy; Window wdummy;
@ -145,10 +234,11 @@ int xf_kbd_read_keyboard_state(xfContext* xfc)
XQueryPointer(xfc->display, DefaultRootWindow(xfc->display), XQueryPointer(xfc->display, DefaultRootWindow(xfc->display),
&wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state); &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
} }
return state; return state;
} }
BOOL xf_kbd_get_key_state(xfContext* xfc, int state, int keysym) BOOL xf_keyboard_get_key_state(xfContext* xfc, int state, int keysym)
{ {
int offset; int offset;
int modifierpos, key, keysymMask = 0; int modifierpos, key, keysymMask = 0;
@ -159,11 +249,11 @@ BOOL xf_kbd_get_key_state(xfContext* xfc, int state, int keysym)
for (modifierpos = 0; modifierpos < 8; modifierpos++) for (modifierpos = 0; modifierpos < 8; modifierpos++)
{ {
offset = xfc->modifier_map->max_keypermod * modifierpos; offset = xfc->modifierMap->max_keypermod * modifierpos;
for (key = 0; key < xfc->modifier_map->max_keypermod; key++) for (key = 0; key < xfc->modifierMap->max_keypermod; key++)
{ {
if (xfc->modifier_map->modifiermap[offset + key] == keycode) if (xfc->modifierMap->modifiermap[offset + key] == keycode)
{ {
keysymMask |= 1 << modifierpos; keysymMask |= 1 << modifierpos;
} }
@ -173,26 +263,26 @@ BOOL xf_kbd_get_key_state(xfContext* xfc, int state, int keysym)
return (state & keysymMask) ? TRUE : FALSE; return (state & keysymMask) ? TRUE : FALSE;
} }
int xf_kbd_get_toggle_keys_state(xfContext* xfc) UINT32 xf_keyboard_get_toggle_keys_state(xfContext* xfc)
{ {
int state; int state;
int toggle_keys_state = 0; UINT32 toggleKeysState = 0;
state = xf_kbd_read_keyboard_state(xfc); state = xf_keyboard_read_keyboard_state(xfc);
if (xf_kbd_get_key_state(xfc, state, XK_Scroll_Lock)) if (xf_keyboard_get_key_state(xfc, state, XK_Scroll_Lock))
toggle_keys_state |= KBD_SYNC_SCROLL_LOCK; toggleKeysState |= KBD_SYNC_SCROLL_LOCK;
if (xf_kbd_get_key_state(xfc, state, XK_Num_Lock)) if (xf_keyboard_get_key_state(xfc, state, XK_Num_Lock))
toggle_keys_state |= KBD_SYNC_NUM_LOCK; toggleKeysState |= KBD_SYNC_NUM_LOCK;
if (xf_kbd_get_key_state(xfc, state, XK_Caps_Lock)) if (xf_keyboard_get_key_state(xfc, state, XK_Caps_Lock))
toggle_keys_state |= KBD_SYNC_CAPS_LOCK; toggleKeysState |= KBD_SYNC_CAPS_LOCK;
if (xf_kbd_get_key_state(xfc, state, XK_Kana_Lock)) if (xf_keyboard_get_key_state(xfc, state, XK_Kana_Lock))
toggle_keys_state |= KBD_SYNC_KANA_LOCK; toggleKeysState |= KBD_SYNC_KANA_LOCK;
return toggle_keys_state; return toggleKeysState;
} }
void xf_kbd_focus_in(xfContext* xfc) void xf_keyboard_focus_in(xfContext* xfc)
{ {
rdpInput* input; rdpInput* input;
UINT32 syncFlags; UINT32 syncFlags;
@ -200,39 +290,141 @@ void xf_kbd_focus_in(xfContext* xfc)
Window wdummy; Window wdummy;
UINT32 state = 0; UINT32 state = 0;
if (xfc->display && xfc->window) if (xfc->display && xfc->window)
{ {
input = xfc->instance->input; input = xfc->instance->input;
syncFlags = xf_kbd_get_toggle_keys_state(xfc); syncFlags = xf_keyboard_get_toggle_keys_state(xfc);
XQueryPointer(xfc->display, xfc->window->handle, &wdummy, &wdummy, &mouseX, &mouseY, &dummy, &dummy, &state); XQueryPointer(xfc->display, xfc->window->handle, &wdummy, &wdummy, &mouseX, &mouseY, &dummy, &dummy, &state);
input->FocusInEvent(input, syncFlags, mouseX, mouseY); input->FocusInEvent(input, syncFlags, mouseX, mouseY);
} }
} }
BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym) int xf_keyboard_execute_action_script(xfContext* xfc, XF_MODIFIER_KEYS* mod, KeySym keysym)
{ {
int index;
int count;
int exitCode;
int status = 1;
FILE* keyScript;
const char* keyStr;
BOOL match = FALSE;
char* keyCombination;
char buffer[1024] = { 0 };
char command[1024] = { 0 };
char combination[1024] = { 0 };
if (!xfc->actionScript)
return 1;
if ((keysym == XK_Shift_L) || (keysym == XK_Shift_R) ||
(keysym == XK_Alt_L) || (keysym == XK_Alt_R) ||
(keysym == XK_Control_L) || (keysym == XK_Control_R))
{
return 1;
}
keyStr = XKeysymToString(keysym);
if (mod->Shift)
strcat(combination, "Shift+");
if (mod->Ctrl)
strcat(combination, "Ctrl+");
if (mod->Alt)
strcat(combination, "Alt+");
strcat(combination, keyStr);
count = ArrayList_Count(xfc->keyCombinations);
for (index = 0; index < count; index++)
{
keyCombination = (char*) ArrayList_GetItem(xfc->keyCombinations, index);
if (_stricmp(keyCombination, combination) == 0)
{
match = TRUE;
break;
}
}
if (!match)
return 1;
sprintf_s(command, sizeof(command), "%s key %s",
xfc->actionScript, combination);
keyScript = popen(command, "r");
if (keyScript < 0)
return -1;
while (fgets(buffer, sizeof(buffer), keyScript) != NULL)
{
strtok(buffer, "\n");
if (strcmp(buffer, "key-local") == 0)
status = 0;
}
exitCode = pclose(keyScript);
return status;
}
int xk_keyboard_get_modifier_keys(xfContext* xfc, XF_MODIFIER_KEYS* mod)
{
mod->LeftShift = xf_keyboard_key_pressed(xfc, XK_Shift_L);
mod->RightShift = xf_keyboard_key_pressed(xfc, XK_Shift_R);
mod->Shift = mod->LeftShift || mod->RightShift;
mod->LeftAlt = xf_keyboard_key_pressed(xfc, XK_Alt_L);
mod->RightAlt = xf_keyboard_key_pressed(xfc, XK_Alt_R);
mod->Alt = mod->LeftAlt || mod->RightAlt;
mod->LeftCtrl = xf_keyboard_key_pressed(xfc, XK_Control_L);
mod->RightCtrl = xf_keyboard_key_pressed(xfc, XK_Control_R);
mod->Ctrl = mod->LeftCtrl || mod->RightCtrl;
mod->LeftSuper = xf_keyboard_key_pressed(xfc, XK_Super_L);
mod->RightSuper = xf_keyboard_key_pressed(xfc, XK_Super_R);
mod->Super = mod->LeftSuper || mod->RightSuper;
return 0;
}
BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym)
{
XF_MODIFIER_KEYS mod = { 0 };
xk_keyboard_get_modifier_keys(xfc, &mod);
if (!xf_keyboard_execute_action_script(xfc, &mod, keysym))
{
return TRUE;
}
if (keysym == XK_Return) if (keysym == XK_Return)
{ {
if ((xf_kbd_key_pressed(xfc, XK_Alt_L) || xf_kbd_key_pressed(xfc, XK_Alt_R)) if (mod.Ctrl && mod.Alt)
&& (xf_kbd_key_pressed(xfc, XK_Control_L) || xf_kbd_key_pressed(xfc, XK_Control_R)))
{ {
/* Ctrl-Alt-Enter: toggle full screen */ /* Ctrl-Alt-Enter: toggle full screen */
xf_toggle_fullscreen(xfc); xf_toggle_fullscreen(xfc);
return TRUE; return TRUE;
} }
} }
if (keysym == XK_period) if (keysym == XK_period)
{ {
if ((xf_kbd_key_pressed(xfc, XK_Alt_L) if (mod.Ctrl && mod.Alt)
|| xf_kbd_key_pressed(xfc, XK_Alt_R))
&& (xf_kbd_key_pressed(xfc, XK_Control_L)
|| xf_kbd_key_pressed(xfc,
XK_Control_R)))
{ {
//Zoom in (scale larger) /* Zoom In (scale larger) */
double s = xfc->settings->ScalingFactor; double s = xfc->settings->ScalingFactor;
s += 0.1; s += 0.1;
if (s > 2.0) if (s > 2.0)
s = 2.0; s = 2.0;
@ -258,15 +450,14 @@ BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym)
if (keysym == XK_comma) if (keysym == XK_comma)
{ {
if ((xf_kbd_key_pressed(xfc, XK_Alt_L) if (mod.Ctrl && mod.Alt)
|| xf_kbd_key_pressed(xfc, XK_Alt_R))
&& (xf_kbd_key_pressed(xfc, XK_Control_L)
|| xf_kbd_key_pressed(xfc,
XK_Control_R)))
{ {
//Zoom out (scale smaller) /* Zoom Out (scale smaller) */
double s = xfc->settings->ScalingFactor; double s = xfc->settings->ScalingFactor;
s -= 0.1; s -= 0.1;
if (s < 0.5) if (s < 0.5)
s = 0.5; s = 0.5;
@ -293,11 +484,7 @@ BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym)
if (keysym == XK_KP_4) if (keysym == XK_KP_4)
{ {
if ((xf_kbd_key_pressed(xfc, XK_Alt_L) if (mod.Ctrl && mod.Alt)
|| xf_kbd_key_pressed(xfc, XK_Alt_R))
&& (xf_kbd_key_pressed(xfc, XK_Control_L)
|| xf_kbd_key_pressed(xfc,
XK_Control_R)))
{ {
{ {
@ -315,11 +502,7 @@ BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym)
if (keysym == XK_KP_6) if (keysym == XK_KP_6)
{ {
if ((xf_kbd_key_pressed(xfc, XK_Alt_L) if (mod.Ctrl && mod.Alt)
|| xf_kbd_key_pressed(xfc, XK_Alt_R))
&& (xf_kbd_key_pressed(xfc, XK_Control_L)
|| xf_kbd_key_pressed(xfc,
XK_Control_R)))
{ {
{ {
@ -336,11 +519,7 @@ BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym)
if (keysym == XK_KP_8) if (keysym == XK_KP_8)
{ {
if ((xf_kbd_key_pressed(xfc, XK_Alt_L) if (mod.Ctrl && mod.Alt)
|| xf_kbd_key_pressed(xfc, XK_Alt_R))
&& (xf_kbd_key_pressed(xfc, XK_Control_L)
|| xf_kbd_key_pressed(xfc,
XK_Control_R)))
{ {
{ {
PanningChangeEventArgs e; PanningChangeEventArgs e;
@ -356,11 +535,7 @@ BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym)
if (keysym == XK_KP_2) if (keysym == XK_KP_2)
{ {
if ((xf_kbd_key_pressed(xfc, XK_Alt_L) if (mod.Ctrl && mod.Alt)
|| xf_kbd_key_pressed(xfc, XK_Alt_R))
&& (xf_kbd_key_pressed(xfc, XK_Control_L)
|| xf_kbd_key_pressed(xfc,
XK_Control_R)))
{ {
{ {
PanningChangeEventArgs e; PanningChangeEventArgs e;
@ -374,7 +549,6 @@ BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym)
} }
} }
return FALSE; return FALSE;
} }

View File

@ -25,17 +25,37 @@
#include "xf_client.h" #include "xf_client.h"
#include "xfreerdp.h" #include "xfreerdp.h"
void xf_kbd_init(xfContext* xfc); #define XF_ACTION_SCRIPT "~/.config/freerdp/action.sh"
void xf_kbd_clear(xfContext* xfc);
void xf_kbd_set_keypress(xfContext* xfc, BYTE keycode, KeySym keysym); struct _XF_MODIFIER_KEYS
void xf_kbd_unset_keypress(xfContext* xfc, BYTE keycode); {
void xf_kbd_release_all_keypress(xfContext* xfc); BOOL Shift;
BOOL xf_kbd_key_pressed(xfContext* xfc, KeySym keysym); BOOL LeftShift;
void xf_kbd_send_key(xfContext* xfc, BOOL down, BYTE keycode); BOOL RightShift;
int xf_kbd_read_keyboard_state(xfContext* xfc); BOOL Alt;
BOOL xf_kbd_get_key_state(xfContext* xfc, int state, int keysym); BOOL LeftAlt;
int xf_kbd_get_toggle_keys_state(xfContext* xfc); BOOL RightAlt;
void xf_kbd_focus_in(xfContext* xfc); BOOL Ctrl;
BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym); BOOL LeftCtrl;
BOOL RightCtrl;
BOOL Super;
BOOL LeftSuper;
BOOL RightSuper;
};
typedef struct _XF_MODIFIER_KEYS XF_MODIFIER_KEYS;
void xf_keyboard_init(xfContext* xfc);
void xf_keyboard_free(xfContext* xfc);
void xf_keyboard_clear(xfContext* xfc);
void xf_keyboard_key_press(xfContext* xfc, BYTE keycode, KeySym keysym);
void xf_keyboard_key_release(xfContext* xfc, BYTE keycode);
void xf_keyboard_release_all_keypress(xfContext* xfc);
BOOL xf_keyboard_key_pressed(xfContext* xfc, KeySym keysym);
void xf_keyboard_send_key(xfContext* xfc, BOOL down, BYTE keycode);
int xf_keyboard_read_keyboard_state(xfContext* xfc);
BOOL xf_keyboard_get_key_state(xfContext* xfc, int state, int keysym);
UINT32 xf_keyboard_get_toggle_keys_state(xfContext* xfc);
void xf_keyboard_focus_in(xfContext* xfc);
BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym);
#endif /* __XF_KEYBOARD_H */ #endif /* __XF_KEYBOARD_H */

View File

@ -125,9 +125,13 @@ struct xf_context
BOOL mouse_active; BOOL mouse_active;
BOOL suppress_output; BOOL suppress_output;
BOOL fullscreen_toggle; BOOL fullscreen_toggle;
UINT32 keyboard_layout_id; UINT32 KeyboardLayout;
BOOL pressed_keys[256]; BOOL KeyboardState[256];
XModifierKeymap* modifier_map; XModifierKeymap* modifierMap;
wArrayList* keyCombinations;
wArrayList* xevents;
char* actionScript;
XSetWindowAttributes attribs; XSetWindowAttributes attribs;
BOOL complex_regions; BOOL complex_regions;
VIRTUAL_SCREEN vscreen; VIRTUAL_SCREEN vscreen;

View File

@ -56,6 +56,7 @@ COMMAND_LINE_ARGUMENT_A args[] =
{ "pth", COMMAND_LINE_VALUE_REQUIRED, "<password hash>", NULL, NULL, -1, "pass-the-hash", "Pass the hash (restricted admin mode)" }, { "pth", COMMAND_LINE_VALUE_REQUIRED, "<password hash>", NULL, NULL, -1, "pass-the-hash", "Pass the hash (restricted admin mode)" },
{ "client-hostname", COMMAND_LINE_VALUE_REQUIRED, "<name>", NULL, NULL, -1, NULL, "Client Hostname to send to server" }, { "client-hostname", COMMAND_LINE_VALUE_REQUIRED, "<name>", NULL, NULL, -1, NULL, "Client Hostname to send to server" },
{ "multimon", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, NULL, "Use multiple monitors" }, { "multimon", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, NULL, "Use multiple monitors" },
{ "span", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, NULL, "Span screen over multiple monitors" },
{ "workarea", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Use available work area" }, { "workarea", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Use available work area" },
{ "monitors", COMMAND_LINE_VALUE_REQUIRED, "<0,1,2...>", NULL, NULL, -1, NULL, "Select monitors to use" }, { "monitors", COMMAND_LINE_VALUE_REQUIRED, "<0,1,2...>", NULL, NULL, -1, NULL, "Select monitors to use" },
{ "monitor-list", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT, NULL, NULL, NULL, -1, NULL, "List detected monitors" }, { "monitor-list", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT, NULL, NULL, NULL, -1, NULL, "List detected monitors" },
@ -1188,13 +1189,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
{ {
settings->Fullscreen = TRUE; settings->Fullscreen = TRUE;
} }
CommandLineSwitchCase(arg, "span")
{
settings->SpanMonitors = TRUE;
}
CommandLineSwitchCase(arg, "multimon") CommandLineSwitchCase(arg, "multimon")
{ {
settings->UseMultimon = TRUE; settings->UseMultimon = TRUE;
settings->SpanMonitors = FALSE;
settings->Fullscreen = TRUE; settings->Fullscreen = TRUE;
if (arg->Flags & COMMAND_LINE_VALUE_PRESENT) if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
@ -1205,6 +1203,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
} }
} }
} }
CommandLineSwitchCase(arg, "span")
{
settings->UseMultimon = TRUE;
settings->SpanMonitors = TRUE;
settings->Fullscreen = TRUE;
}
CommandLineSwitchCase(arg, "workarea") CommandLineSwitchCase(arg, "workarea")
{ {
settings->Workarea = TRUE; settings->Workarea = TRUE;
@ -1345,9 +1349,11 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
settings->GatewayHostname = _strdup(settings->ServerHostname); settings->GatewayHostname = _strdup(settings->ServerHostname);
} }
settings->GatewayUsageMethod = TSC_PROXY_MODE_DIRECT;
settings->GatewayUseSameCredentials = TRUE; settings->GatewayUseSameCredentials = TRUE;
settings->GatewayUsageMethod = TSC_PROXY_MODE_DETECT;
settings->GatewayEnabled = TRUE; settings->GatewayEnabled = TRUE;
settings->GatewayBypassLocal = TRUE;
} }
CommandLineSwitchCase(arg, "gu") CommandLineSwitchCase(arg, "gu")
{ {

View File

@ -866,14 +866,36 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
{ {
freerdp_set_param_uint32(settings, FreeRDP_GatewayUsageMethod, file->GatewayUsageMethod); freerdp_set_param_uint32(settings, FreeRDP_GatewayUsageMethod, file->GatewayUsageMethod);
if (file->GatewayUsageMethod == TSC_PROXY_MODE_DIRECT) if (file->GatewayUsageMethod == TSC_PROXY_MODE_NONE_DIRECT)
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, TRUE); {
else if (file->GatewayUsageMethod == TSC_PROXY_MODE_DETECT)
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, TRUE);
else if (file->GatewayUsageMethod == TSC_PROXY_MODE_DEFAULT)
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, TRUE);
else if (file->GatewayUsageMethod == TSC_PROXY_MODE_NONE_DETECT)
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, FALSE); freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, FALSE);
freerdp_set_param_bool(settings, FreeRDP_GatewayBypassLocal, FALSE);
}
else if (file->GatewayUsageMethod == TSC_PROXY_MODE_DIRECT)
{
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, TRUE);
freerdp_set_param_bool(settings, FreeRDP_GatewayBypassLocal, FALSE);
}
else if (file->GatewayUsageMethod == TSC_PROXY_MODE_DETECT)
{
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, TRUE);
freerdp_set_param_bool(settings, FreeRDP_GatewayBypassLocal, TRUE);
}
else if (file->GatewayUsageMethod == TSC_PROXY_MODE_DEFAULT)
{
/**
* This corresponds to "Automatically detect RD Gateway server settings",
* which means the client attempts to use gateway group policy settings
* http://technet.microsoft.com/en-us/library/cc770601.aspx
*/
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, FALSE);
freerdp_set_param_bool(settings, FreeRDP_GatewayBypassLocal, FALSE);
}
else if (file->GatewayUsageMethod == TSC_PROXY_MODE_NONE_DETECT)
{
freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, FALSE);
freerdp_set_param_bool(settings, FreeRDP_GatewayBypassLocal, FALSE);
}
} }
if (~file->PromptCredentialOnce) if (~file->PromptCredentialOnce)

View File

@ -176,6 +176,60 @@ FREERDP_API extern int connectErrorCode;
#define INSUFFICIENTPRIVILEGESERROR ERRORSTART + 10 #define INSUFFICIENTPRIVILEGESERROR ERRORSTART + 10
#define CANCELEDBYUSER ERRORSTART + 11 #define CANCELEDBYUSER ERRORSTART + 11
/**
* FreeRDP Context Error Codes
*/
#define MAKE_FREERDP_ERROR(_class, _type) \
(((FREERDP_ERROR_ ## _class ## _CLASS) << 16) | (_type))
#define GET_FREERDP_ERROR_CLASS(_errorCode) \
((_errorCode >> 16) & 0xFFFF)
#define GET_FREERDP_ERROR_TYPE(_errorCode) \
(_errorCode & 0xFFFF)
#define GET_FREERDP_ERROR_SUBCODE
#define FREERDP_ERROR_BASE 0
#define FREERDP_ERROR_SUCCESS ERRINFO_SUCCESS
#define FREERDP_ERROR_NONE ERRINFO_NONE
/* Error Info Codes */
#define FREERDP_ERROR_ERRINFO_CLASS (FREERDP_ERROR_BASE + 1)
#define FREERDP_ERROR_RPC_INITIATED_DISCONNECT MAKE_FREERDP_ERROR(ERRINFO, ERRINFO_RPC_INITIATED_DISCONNECT)
#define FREERDP_ERROR_RPC_INITIATED_LOGOFF MAKE_FREERDP_ERROR(ERRINFO, ERRINFO_RPC_INITIATED_LOGOFF)
#define FREERDP_ERROR_IDLE_TIMEOUT MAKE_FREERDP_ERROR(ERRINFO, ERRINFO_IDLE_TIMEOUT)
#define FREERDP_ERROR_LOGON_TIMEOUT MAKE_FREERDP_ERROR(ERRINFO, ERRINFO_LOGON_TIMEOUT)
#define FREERDP_ERROR_DISCONNECTED_BY_OTHER_CONNECTION MAKE_FREERDP_ERROR(ERRINFO, ERRINFO_DISCONNECTED_BY_OTHER_CONNECTION)
#define FREERDP_ERROR_OUT_OF_MEMORY MAKE_FREERDP_ERROR(ERRINFO, ERRINFO_OUT_OF_MEMORY)
#define FREERDP_ERROR_SERVER_DENIED_CONNECTION MAKE_FREERDP_ERROR(ERRINFO, ERRINFO_SERVER_DENIED_CONNECTION)
#define FREERDP_ERROR_SERVER_INSUFFICIENT_PRIVILEGES MAKE_FREERDP_ERROR(ERRINFO, ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES)
#define FREERDP_ERROR_SERVER_FRESH_CREDENTIALS_REQUIRED MAKE_FREERDP_ERROR(ERRINFO, ERRINFO_SERVER_FRESH_CREDENTIALS_REQUIRED)
#define FREERDP_ERROR_RPC_INITIATED_DISCONNECT_BY_USER MAKE_FREERDP_ERROR(ERRINFO, ERRINFO_RPC_INITIATED_DISCONNECT_BY_USER)
#define FREERDP_ERROR_LOGOFF_BY_USER MAKE_FREERDP_ERROR(ERRINFO, ERRINFO_LOGOFF_BY_USER)
/* Connection Error Codes */
#define FREERDP_ERROR_CONNECT_CLASS (FREERDP_ERROR_BASE + 2)
#define FREERDP_ERROR_PRE_CONNECT_FAILED MAKE_FREERDP_ERROR(CONNECT, 1)
#define FREERDP_ERROR_CONNECT_UNDEFINED MAKE_FREERDP_ERROR(CONNECT, 2)
#define FREERDP_ERROR_POST_CONNECT_FAILED MAKE_FREERDP_ERROR(CONNECT, 3)
#define FREERDP_ERROR_DNS_ERROR MAKE_FREERDP_ERROR(CONNECT, 4)
#define FREERDP_ERROR_DNS_NAME_NOT_FOUND MAKE_FREERDP_ERROR(CONNECT, 5)
#define FREERDP_ERROR_CONNECT_FAILED MAKE_FREERDP_ERROR(CONNECT, 6)
#define FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR MAKE_FREERDP_ERROR(CONNECT, 7)
#define FREERDP_ERROR_TLS_CONNECT_FAILED MAKE_FREERDP_ERROR(CONNECT, 8)
#define FREERDP_ERROR_AUTHENTICATION_FAILED MAKE_FREERDP_ERROR(CONNECT, 9)
#define FREERDP_ERROR_INSUFFICIENT_PRIVILEGES MAKE_FREERDP_ERROR(CONNECT, 10)
#define FREERDP_ERROR_CONNECT_CANCELLED MAKE_FREERDP_ERROR(CONNECT, 11)
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -85,7 +85,9 @@ struct rdp_context
This field is used only on the server side. */ This field is used only on the server side. */
ALIGN64 BOOL ServerMode; /**< (offset 2) true when context is in server mode */ ALIGN64 BOOL ServerMode; /**< (offset 2) true when context is in server mode */
UINT64 paddingA[16 - 3]; /* 3 */ ALIGN64 UINT32 LastError; /* 3 */
UINT64 paddingA[16 - 4]; /* 4 */
ALIGN64 int argc; /**< (offset 16) ALIGN64 int argc; /**< (offset 16)
Number of arguments given to the program at launch time. Number of arguments given to the program at launch time.
@ -247,6 +249,9 @@ FREERDP_API void freerdp_free(freerdp* instance);
FREERDP_API BOOL freerdp_focus_required(freerdp* instance); FREERDP_API BOOL freerdp_focus_required(freerdp* instance);
FREERDP_API UINT32 freerdp_get_last_error(rdpContext* context);
FREERDP_API void freerdp_set_last_error(rdpContext* context, UINT32 lastError);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -669,6 +669,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
#define FreeRDP_GatewayCredentialsSource 1990 #define FreeRDP_GatewayCredentialsSource 1990
#define FreeRDP_GatewayUseSameCredentials 1991 #define FreeRDP_GatewayUseSameCredentials 1991
#define FreeRDP_GatewayEnabled 1992 #define FreeRDP_GatewayEnabled 1992
#define FreeRDP_GatewayBypassLocal 1993
#define FreeRDP_RemoteApplicationMode 2112 #define FreeRDP_RemoteApplicationMode 2112
#define FreeRDP_RemoteApplicationName 2113 #define FreeRDP_RemoteApplicationName 2113
#define FreeRDP_RemoteApplicationIcon 2114 #define FreeRDP_RemoteApplicationIcon 2114
@ -1073,7 +1074,8 @@ struct rdp_settings
ALIGN64 UINT32 GatewayCredentialsSource; /* 1990 */ ALIGN64 UINT32 GatewayCredentialsSource; /* 1990 */
ALIGN64 BOOL GatewayUseSameCredentials; /* 1991 */ ALIGN64 BOOL GatewayUseSameCredentials; /* 1991 */
ALIGN64 BOOL GatewayEnabled; /* 1992 */ ALIGN64 BOOL GatewayEnabled; /* 1992 */
UINT64 padding2048[2048 - 1993]; /* 1993 */ ALIGN64 BOOL GatewayBypassLocal; /* 1993 */
UINT64 padding2048[2048 - 1994]; /* 1994 */
UINT64 padding2112[2112 - 2048]; /* 2048 */ UINT64 padding2112[2112 - 2048]; /* 2048 */
/** /**

View File

@ -110,13 +110,8 @@ int mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** p
if (!(flags & PACKET_COMPRESSED)) if (!(flags & PACKET_COMPRESSED))
{ {
CopyMemory(HistoryPtr, pSrcData, SrcSize);
HistoryPtr += SrcSize;
HistoryOffset += SrcSize;
mppc->HistoryPtr = HistoryPtr;
mppc->HistoryOffset = HistoryOffset;
*ppDstData = HistoryPtr;
*pDstSize = SrcSize; *pDstSize = SrcSize;
*ppDstData = pSrcData;
return 1; return 1;
} }
@ -532,6 +527,7 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE* pDst
*pFlags |= PACKET_FLUSHED; *pFlags |= PACKET_FLUSHED;
ZeroMemory(HistoryBuffer, HistoryBufferSize); ZeroMemory(HistoryBuffer, HistoryBufferSize);
ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer)); ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer));
*pDstSize = SrcSize;
return 1; return 1;
} }
@ -582,6 +578,7 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE* pDst
*pFlags = PACKET_FLUSHED; *pFlags = PACKET_FLUSHED;
ZeroMemory(HistoryBuffer, HistoryBufferSize); ZeroMemory(HistoryBuffer, HistoryBufferSize);
ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer)); ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer));
*pDstSize = SrcSize;
return 1; return 1;
} }
@ -737,6 +734,7 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE* pDst
*pFlags |= PACKET_FLUSHED; *pFlags |= PACKET_FLUSHED;
ZeroMemory(HistoryBuffer, HistoryBufferSize); ZeroMemory(HistoryBuffer, HistoryBufferSize);
ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer)); ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer));
*pDstSize = SrcSize;
return 1; return 1;
} }

View File

@ -1167,10 +1167,7 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY
if (!(flags & PACKET_COMPRESSED)) if (!(flags & PACKET_COMPRESSED))
{ {
CopyMemory(HistoryPtr, pSrcData, SrcSize); *ppDstData = pSrcData;
HistoryPtr += SrcSize;
ncrush->HistoryPtr = HistoryPtr;
*ppDstData = HistoryPtr;
*pDstSize = SrcSize; *pDstSize = SrcSize;
return 1; return 1;
} }

View File

@ -746,6 +746,10 @@ BOOL freerdp_get_param_bool(rdpSettings* settings, int id)
return settings->GatewayEnabled; return settings->GatewayEnabled;
break; break;
case FreeRDP_GatewayBypassLocal:
return settings->GatewayBypassLocal;
break;
case FreeRDP_RemoteApplicationMode: case FreeRDP_RemoteApplicationMode:
return settings->RemoteApplicationMode; return settings->RemoteApplicationMode;
break; break;
@ -1218,6 +1222,10 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param)
settings->GatewayEnabled = param; settings->GatewayEnabled = param;
break; break;
case FreeRDP_GatewayBypassLocal:
settings->GatewayBypassLocal = param;
break;
case FreeRDP_RemoteApplicationMode: case FreeRDP_RemoteApplicationMode:
settings->RemoteApplicationMode = param; settings->RemoteApplicationMode = param;
break; break;

View File

@ -46,29 +46,38 @@ int bulk_decompress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstD
UINT32 UncompressedBytes; UINT32 UncompressedBytes;
UINT32 type = flags & 0x0F; UINT32 type = flags & 0x0F;
switch (type) if (flags & PACKET_COMPRESSED)
{ {
case PACKET_COMPR_TYPE_8K: switch (type)
mppc_set_compression_level(bulk->mppcRecv, 0); {
status = mppc_decompress(bulk->mppcRecv, pSrcData, SrcSize, ppDstData, pDstSize, flags); case PACKET_COMPR_TYPE_8K:
break; mppc_set_compression_level(bulk->mppcRecv, 0);
status = mppc_decompress(bulk->mppcRecv, pSrcData, SrcSize, ppDstData, pDstSize, flags);
break;
case PACKET_COMPR_TYPE_64K: case PACKET_COMPR_TYPE_64K:
mppc_set_compression_level(bulk->mppcRecv, 1); mppc_set_compression_level(bulk->mppcRecv, 1);
status = mppc_decompress(bulk->mppcRecv, pSrcData, SrcSize, ppDstData, pDstSize, flags); status = mppc_decompress(bulk->mppcRecv, pSrcData, SrcSize, ppDstData, pDstSize, flags);
break; break;
case PACKET_COMPR_TYPE_RDP6: case PACKET_COMPR_TYPE_RDP6:
status = ncrush_decompress(bulk->ncrushRecv, pSrcData, SrcSize, ppDstData, pDstSize, flags); status = ncrush_decompress(bulk->ncrushRecv, pSrcData, SrcSize, ppDstData, pDstSize, flags);
break; break;
case PACKET_COMPR_TYPE_RDP61: case PACKET_COMPR_TYPE_RDP61:
status = -1; status = -1;
break; break;
case PACKET_COMPR_TYPE_RDP8: case PACKET_COMPR_TYPE_RDP8:
status = -1; status = -1;
break; break;
}
}
else
{
*ppDstData = pSrcData;
*pDstSize = SrcSize;
status = 1;
} }
if (status >= 0) if (status >= 0)
@ -87,8 +96,8 @@ int bulk_decompress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstD
CompressionRatio = ((double) CompressedBytes) / ((double) UncompressedBytes); CompressionRatio = ((double) CompressedBytes) / ((double) UncompressedBytes);
TotalCompressionRatio = ((double) bulk->TotalCompressedBytes) / ((double) bulk->TotalUncompressedBytes); TotalCompressionRatio = ((double) bulk->TotalCompressedBytes) / ((double) bulk->TotalUncompressedBytes);
printf("Type: %d Compression Ratio: %f Total: %f %d / %d\n", printf("Type: %d Flags: 0x%04X Compression Ratio: %f Total: %f %d / %d\n",
type, CompressionRatio, TotalCompressionRatio, CompressedBytes, UncompressedBytes); type, flags, CompressionRatio, TotalCompressionRatio, CompressedBytes, UncompressedBytes);
} }
#endif #endif
} }
@ -113,7 +122,7 @@ int bulk_compress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstDat
mppc_set_compression_level(bulk->mppcSend, bulk->CompressionLevel); mppc_set_compression_level(bulk->mppcSend, bulk->CompressionLevel);
status = mppc_compress(bulk->mppcSend, pSrcData, SrcSize, *ppDstData, pDstSize, pFlags); status = mppc_compress(bulk->mppcSend, pSrcData, SrcSize, *ppDstData, pDstSize, pFlags);
if ((status >= 0) && (*pFlags & PACKET_COMPRESSED)) if (status >= 0)
{ {
CompressedBytes = *pDstSize; CompressedBytes = *pDstSize;
UncompressedBytes = SrcSize; UncompressedBytes = SrcSize;
@ -123,13 +132,17 @@ int bulk_compress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstDat
#ifdef WITH_BULK_DEBUG #ifdef WITH_BULK_DEBUG
{ {
UINT32 type;
double CompressionRatio; double CompressionRatio;
double TotalCompressionRatio; double TotalCompressionRatio;
type = bulk->CompressionLevel;
CompressionRatio = ((double) CompressedBytes) / ((double) UncompressedBytes); CompressionRatio = ((double) CompressedBytes) / ((double) UncompressedBytes);
TotalCompressionRatio = ((double) bulk->TotalCompressedBytes) / ((double) bulk->TotalUncompressedBytes); TotalCompressionRatio = ((double) bulk->TotalCompressedBytes) / ((double) bulk->TotalUncompressedBytes);
printf("Compression Ratio: %f Total: %f\n", CompressionRatio, TotalCompressionRatio); printf("Type: %d Flags: 0x%04X Compression Ratio: %f Total: %f %d / %d\n",
type, *pFlags, CompressionRatio, TotalCompressionRatio, CompressedBytes, UncompressedBytes);
} }
#endif #endif
} }

View File

@ -231,6 +231,9 @@ BOOL rdp_client_connect(rdpRdp* rdp)
nego_set_negotiation_enabled(rdp->nego, settings->NegotiateSecurityLayer); nego_set_negotiation_enabled(rdp->nego, settings->NegotiateSecurityLayer);
nego_set_restricted_admin_mode_required(rdp->nego, settings->RestrictedAdminModeRequired); nego_set_restricted_admin_mode_required(rdp->nego, settings->RestrictedAdminModeRequired);
nego_set_gateway_enabled(rdp->nego, settings->GatewayEnabled);
nego_set_gateway_bypass_local(rdp->nego, settings->GatewayBypassLocal);
nego_enable_rdp(rdp->nego, settings->RdpSecurity); nego_enable_rdp(rdp->nego, settings->RdpSecurity);
nego_enable_tls(rdp->nego, settings->TlsSecurity); nego_enable_tls(rdp->nego, settings->TlsSecurity);
nego_enable_nla(rdp->nego, settings->NlaSecurity); nego_enable_nla(rdp->nego, settings->NlaSecurity);
@ -268,6 +271,12 @@ BOOL rdp_client_connect(rdpRdp* rdp)
{ {
connectErrorCode = MCSCONNECTINITIALERROR; connectErrorCode = MCSCONNECTINITIALERROR;
} }
if (!freerdp_get_last_error(rdp->context))
{
freerdp_set_last_error(rdp->context, FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR);
}
fprintf(stderr, "Error: unable to send MCS Connect Initial\n"); fprintf(stderr, "Error: unable to send MCS Connect Initial\n");
return FALSE; return FALSE;
} }

View File

@ -342,6 +342,8 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s)
BYTE fragmentation; BYTE fragmentation;
BYTE compression; BYTE compression;
BYTE compressionFlags; BYTE compressionFlags;
UINT32 DstSize = 0;
BYTE* pDstData = NULL;
rdpTransport* transport; rdpTransport* transport;
status = 0; status = 0;
@ -363,26 +365,20 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s)
cs = s; cs = s;
next_pos = Stream_GetPosition(s) + size; next_pos = Stream_GetPosition(s) + size;
if (compressionFlags & PACKET_COMPRESSED) if (bulk_decompress(rdp->bulk, Stream_Pointer(s), size, &pDstData, &DstSize, compressionFlags))
{ {
UINT32 DstSize = 0; size = DstSize;
BYTE* pDstData = NULL; cs = StreamPool_Take(transport->ReceivePool, DstSize);
if (bulk_decompress(rdp->bulk, Stream_Pointer(s), size, &pDstData, &DstSize, compressionFlags)) Stream_SetPosition(cs, 0);
{ Stream_Write(cs, pDstData, DstSize);
size = DstSize; Stream_SealLength(cs);
cs = StreamPool_Take(transport->ReceivePool, DstSize); Stream_SetPosition(cs, 0);
}
Stream_SetPosition(cs, 0); else
Stream_Write(cs, pDstData, DstSize); {
Stream_SealLength(cs); fprintf(stderr, "bulk_decompress() failed\n");
Stream_SetPosition(cs, 0); Stream_Seek(s, size);
}
else
{
fprintf(stderr, "bulk_decompress() failed\n");
Stream_Seek(s, size);
}
} }
if (fragmentation == FASTPATH_FRAGMENT_SINGLE) if (fragmentation == FASTPATH_FRAGMENT_SINGLE)
@ -855,6 +851,7 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s
{ {
CompressionMaxSize = bulk_compression_max_size(rdp->bulk); CompressionMaxSize = bulk_compression_max_size(rdp->bulk);
maxLength = (maxLength < CompressionMaxSize) ? maxLength : CompressionMaxSize; maxLength = (maxLength < CompressionMaxSize) ? maxLength : CompressionMaxSize;
maxLength -= 20;
} }
totalLength = Stream_GetPosition(s); totalLength = Stream_GetPosition(s);

View File

@ -65,6 +65,7 @@ BOOL freerdp_connect(freerdp* instance)
/* We always set the return code to 0 before we start the connect sequence*/ /* We always set the return code to 0 before we start the connect sequence*/
connectErrorCode = 0; connectErrorCode = 0;
freerdp_set_last_error(instance->context, FREERDP_ERROR_SUCCESS);
rdp = instance->context->rdp; rdp = instance->context->rdp;
settings = instance->settings; settings = instance->settings;
@ -87,6 +88,12 @@ BOOL freerdp_connect(freerdp* instance)
{ {
connectErrorCode = PREECONNECTERROR; connectErrorCode = PREECONNECTERROR;
} }
if (!freerdp_get_last_error(rdp->context))
{
freerdp_set_last_error(instance->context, FREERDP_ERROR_PRE_CONNECT_FAILED);
}
fprintf(stderr, "%s:%d: freerdp_pre_connect failed\n", __FILE__, __LINE__); fprintf(stderr, "%s:%d: freerdp_pre_connect failed\n", __FILE__, __LINE__);
goto freerdp_connect_finally; goto freerdp_connect_finally;
@ -124,6 +131,11 @@ BOOL freerdp_connect(freerdp* instance)
connectErrorCode = POSTCONNECTERROR; connectErrorCode = POSTCONNECTERROR;
} }
if (!freerdp_get_last_error(rdp->context))
{
freerdp_set_last_error(instance->context, FREERDP_ERROR_POST_CONNECT_FAILED);
}
goto freerdp_connect_finally; goto freerdp_connect_finally;
} }
@ -177,6 +189,7 @@ BOOL freerdp_connect(freerdp* instance)
if (rdp->errorInfo == ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES) if (rdp->errorInfo == ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES)
{ {
connectErrorCode = INSUFFICIENTPRIVILEGESERROR; connectErrorCode = INSUFFICIENTPRIVILEGESERROR;
freerdp_set_last_error(instance->context, FREERDP_ERROR_INSUFFICIENT_PRIVILEGES);
} }
if (!connectErrorCode) if (!connectErrorCode)
@ -465,6 +478,19 @@ UINT32 freerdp_error_info(freerdp* instance)
return instance->context->rdp->errorInfo; return instance->context->rdp->errorInfo;
} }
UINT32 freerdp_get_last_error(rdpContext* context)
{
return context->LastError;
}
void freerdp_set_last_error(rdpContext* context, UINT32 lastError)
{
if (lastError)
fprintf(stderr, "freerdp_set_last_error 0x%04X\n", lastError);
context->LastError = lastError;
}
/** Allocator function for the rdp_freerdp structure. /** Allocator function for the rdp_freerdp structure.
* @return an allocated structure filled with 0s. Need to be deallocated using freerdp_free() * @return an allocated structure filled with 0s. Need to be deallocated using freerdp_free()
*/ */

View File

@ -142,6 +142,7 @@ int rpc_ncacn_http_ntlm_init(rdpRpc* rpc, TSG_CHANNEL channel)
if (!proceed) if (!proceed)
{ {
connectErrorCode = CANCELEDBYUSER; connectErrorCode = CANCELEDBYUSER;
freerdp_set_last_error(instance->context, FREERDP_ERROR_CONNECT_CANCELLED);
return 0; return 0;
} }

View File

@ -120,6 +120,7 @@ int rpc_send_bind_pdu(rdpRpc* rpc)
if (!proceed) if (!proceed)
{ {
connectErrorCode = CANCELEDBYUSER; connectErrorCode = CANCELEDBYUSER;
freerdp_set_last_error(instance->context, FREERDP_ERROR_CONNECT_CANCELLED);
return 0; return 0;
} }

View File

@ -154,9 +154,17 @@ BOOL rts_connect(rdpRpc* rpc)
http_response_print(http_response); http_response_print(http_response);
http_response_free(http_response); http_response_free(http_response);
if (!connectErrorCode && http_response->StatusCode == HTTP_STATUS_DENIED) if (http_response->StatusCode == HTTP_STATUS_DENIED)
{ {
connectErrorCode = AUTHENTICATIONERROR; if (!connectErrorCode)
{
connectErrorCode = AUTHENTICATIONERROR;
}
if (!freerdp_get_last_error(((freerdp*)(rpc->settings->instance))->context))
{
freerdp_set_last_error(((freerdp*)(rpc->settings->instance))->context, FREERDP_ERROR_AUTHENTICATION_FAILED);
}
} }
return FALSE; return FALSE;

View File

@ -407,16 +407,17 @@ void gcc_write_client_data_blocks(wStream* s, rdpMcs* mcs)
if (settings->NegotiationFlags & EXTENDED_CLIENT_DATA_SUPPORTED) if (settings->NegotiationFlags & EXTENDED_CLIENT_DATA_SUPPORTED)
{ {
if (settings->SpanMonitors) if (settings->UseMultimon && !settings->SpanMonitors)
{ {
gcc_write_client_monitor_data(s, mcs); gcc_write_client_monitor_data(s, mcs);
} }
gcc_write_client_message_channel_data(s, mcs); gcc_write_client_message_channel_data(s, mcs);
gcc_write_client_multitransport_channel_data(s, mcs); gcc_write_client_multitransport_channel_data(s, mcs);
} }
else else
{ {
if (settings->UseMultimon) if (settings->UseMultimon && !settings->SpanMonitors)
{ {
fprintf(stderr, "WARNING: true multi monitor support was not advertised by server!\n"); fprintf(stderr, "WARNING: true multi monitor support was not advertised by server!\n");

View File

@ -212,7 +212,25 @@ BOOL nego_security_connect(rdpNego* nego)
BOOL nego_tcp_connect(rdpNego* nego) BOOL nego_tcp_connect(rdpNego* nego)
{ {
if (!nego->tcp_connected) if (!nego->tcp_connected)
nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port); {
if (nego->GatewayEnabled && nego->GatewayBypassLocal)
{
/* Attempt a direct connection first, and then fallback to using the gateway */
transport_set_gateway_enabled(nego->transport, FALSE);
nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port);
if (!nego->tcp_connected)
{
transport_set_gateway_enabled(nego->transport, TRUE);
nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port);
}
}
else
{
nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port);
}
}
return nego->tcp_connected; return nego->tcp_connected;
} }
@ -1034,6 +1052,16 @@ void nego_set_restricted_admin_mode_required(rdpNego* nego, BOOL RestrictedAdmin
nego->RestrictedAdminModeRequired = RestrictedAdminModeRequired; nego->RestrictedAdminModeRequired = RestrictedAdminModeRequired;
} }
void nego_set_gateway_enabled(rdpNego* nego, BOOL GatewayEnabled)
{
nego->GatewayEnabled = GatewayEnabled;
}
void nego_set_gateway_bypass_local(rdpNego* nego, BOOL GatewayBypassLocal)
{
nego->GatewayBypassLocal = GatewayBypassLocal;
}
/** /**
* Enable RDP security protocol. * Enable RDP security protocol.
* @param nego pointer to the negotiation structure * @param nego pointer to the negotiation structure

View File

@ -110,6 +110,8 @@ struct rdp_nego
BOOL NegotiateSecurityLayer; BOOL NegotiateSecurityLayer;
BYTE enabled_protocols[16]; BYTE enabled_protocols[16];
BOOL RestrictedAdminModeRequired; BOOL RestrictedAdminModeRequired;
BOOL GatewayEnabled;
BOOL GatewayBypassLocal;
rdpTransport* transport; rdpTransport* transport;
}; };
@ -142,6 +144,8 @@ void nego_init(rdpNego* nego);
void nego_set_target(rdpNego* nego, char* hostname, int port); void nego_set_target(rdpNego* nego, char* hostname, int port);
void nego_set_negotiation_enabled(rdpNego* nego, BOOL NegotiateSecurityLayer_enabled); void nego_set_negotiation_enabled(rdpNego* nego, BOOL NegotiateSecurityLayer_enabled);
void nego_set_restricted_admin_mode_required(rdpNego* nego, BOOL RestrictedAdminModeRequired); void nego_set_restricted_admin_mode_required(rdpNego* nego, BOOL RestrictedAdminModeRequired);
void nego_set_gateway_enabled(rdpNego* nego, BOOL GatewayEnabled);
void nego_set_gateway_bypass_local(rdpNego* nego, BOOL GatewayBypassLocal);
void nego_enable_rdp(rdpNego* nego, BOOL enable_rdp); void nego_enable_rdp(rdpNego* nego, BOOL enable_rdp);
void nego_enable_tls(rdpNego* nego, BOOL enable_tls); void nego_enable_tls(rdpNego* nego, BOOL enable_tls);
void nego_enable_nla(rdpNego* nego, BOOL enable_nla); void nego_enable_nla(rdpNego* nego, BOOL enable_nla);

View File

@ -153,6 +153,7 @@ int credssp_ntlm_client_init(rdpCredssp* credssp)
if (!proceed) if (!proceed)
{ {
connectErrorCode = CANCELEDBYUSER; connectErrorCode = CANCELEDBYUSER;
freerdp_set_last_error(instance->context, FREERDP_ERROR_CONNECT_CANCELLED);
return 0; return 0;
} }

View File

@ -238,12 +238,17 @@ BOOL rdp_set_error_info(rdpRdp* rdp, UINT32 errorInfo)
ErrorInfoEventArgs e; ErrorInfoEventArgs e;
rdpContext* context = rdp->instance->context; rdpContext* context = rdp->instance->context;
rdp->context->LastError = MAKE_FREERDP_ERROR(ERRINFO, errorInfo);
rdp_print_errinfo(rdp->errorInfo); rdp_print_errinfo(rdp->errorInfo);
EventArgsInit(&e, "freerdp"); EventArgsInit(&e, "freerdp");
e.code = rdp->errorInfo; e.code = rdp->errorInfo;
PubSub_OnErrorInfo(context->pubSub, context, &e); PubSub_OnErrorInfo(context->pubSub, context, &e);
} }
else
{
rdp->context->LastError = FREERDP_ERROR_SUCCESS;
}
return TRUE; return TRUE;
} }

View File

@ -651,6 +651,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
_settings->PlayRemoteFx = settings->PlayRemoteFx; /* 1857 */ _settings->PlayRemoteFx = settings->PlayRemoteFx; /* 1857 */
_settings->GatewayUseSameCredentials = settings->GatewayUseSameCredentials; /* 1991 */ _settings->GatewayUseSameCredentials = settings->GatewayUseSameCredentials; /* 1991 */
_settings->GatewayEnabled = settings->GatewayEnabled; /* 1992 */ _settings->GatewayEnabled = settings->GatewayEnabled; /* 1992 */
_settings->GatewayBypassLocal = settings->GatewayBypassLocal; /* 1993 */
_settings->RemoteApplicationMode = settings->RemoteApplicationMode; /* 2112 */ _settings->RemoteApplicationMode = settings->RemoteApplicationMode; /* 2112 */
_settings->DisableRemoteAppCapsCheck = settings->DisableRemoteAppCapsCheck; /* 2121 */ _settings->DisableRemoteAppCapsCheck = settings->DisableRemoteAppCapsCheck; /* 2121 */
_settings->RemoteAppLanguageBarSupported = settings->RemoteAppLanguageBarSupported; /* 2124 */ _settings->RemoteAppLanguageBarSupported = settings->RemoteAppLanguageBarSupported; /* 2124 */

View File

@ -71,25 +71,8 @@ void transport_attach(rdpTransport* transport, int sockfd)
transport->TcpOut = transport->TcpIn; transport->TcpOut = transport->TcpIn;
} }
BOOL transport_disconnect(rdpTransport* transport) void transport_stop(rdpTransport* transport)
{ {
BOOL status = TRUE;
if (!transport)
return FALSE;
if (transport->layer == TRANSPORT_LAYER_TLS)
status &= tls_disconnect(transport->TlsIn);
if ((transport->layer == TRANSPORT_LAYER_TSG) || (transport->layer == TRANSPORT_LAYER_TSG_TLS))
{
status &= tsg_disconnect(transport->tsg);
}
else
{
status &= tcp_disconnect(transport->TcpIn);
}
if (transport->async) if (transport->async)
{ {
if (transport->stopEvent) if (transport->stopEvent)
@ -104,6 +87,28 @@ BOOL transport_disconnect(rdpTransport* transport)
transport->stopEvent = NULL; transport->stopEvent = NULL;
} }
} }
}
BOOL transport_disconnect(rdpTransport* transport)
{
BOOL status = TRUE;
if (!transport)
return FALSE;
transport_stop(transport);
if (transport->layer == TRANSPORT_LAYER_TLS)
status &= tls_disconnect(transport->TlsIn);
if ((transport->layer == TRANSPORT_LAYER_TSG) || (transport->layer == TRANSPORT_LAYER_TSG_TLS))
{
status &= tsg_disconnect(transport->tsg);
}
else
{
status &= tcp_disconnect(transport->TcpIn);
}
return status; return status;
} }
@ -219,6 +224,12 @@ BIO_METHOD* BIO_s_tsg(void)
BOOL transport_connect_tls(rdpTransport* transport) BOOL transport_connect_tls(rdpTransport* transport)
{ {
freerdp* instance;
rdpContext* context;
instance = (freerdp*) transport->settings->instance;
context = instance->context;
if (transport->layer == TRANSPORT_LAYER_TSG) if (transport->layer == TRANSPORT_LAYER_TSG)
{ {
transport->TsgTls = tls_new(transport->settings); transport->TsgTls = tls_new(transport->settings);
@ -239,6 +250,9 @@ BOOL transport_connect_tls(rdpTransport* transport)
if (!connectErrorCode) if (!connectErrorCode)
connectErrorCode = TLSCONNECTERROR; connectErrorCode = TLSCONNECTERROR;
if (!freerdp_get_last_error(context))
freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
tls_free(transport->TsgTls); tls_free(transport->TsgTls);
transport->TsgTls = NULL; transport->TsgTls = NULL;
@ -268,6 +282,9 @@ BOOL transport_connect_tls(rdpTransport* transport)
if (!connectErrorCode) if (!connectErrorCode)
connectErrorCode = TLSCONNECTERROR; connectErrorCode = TLSCONNECTERROR;
if (!freerdp_get_last_error(context))
freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
tls_free(transport->TlsIn); tls_free(transport->TlsIn);
if (transport->TlsIn == transport->TlsOut) if (transport->TlsIn == transport->TlsOut)
@ -313,6 +330,11 @@ BOOL transport_connect_nla(rdpTransport* transport)
if (!connectErrorCode) if (!connectErrorCode)
connectErrorCode = AUTHENTICATIONERROR; connectErrorCode = AUTHENTICATIONERROR;
if (!freerdp_get_last_error(instance->context))
{
freerdp_set_last_error(instance->context, FREERDP_ERROR_AUTHENTICATION_FAILED);
}
fprintf(stderr, "Authentication failure, check credentials.\n" fprintf(stderr, "Authentication failure, check credentials.\n"
"If credentials are valid, the NTLMSSP implementation may be to blame.\n"); "If credentials are valid, the NTLMSSP implementation may be to blame.\n");
@ -374,7 +396,7 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 por
transport->async = settings->AsyncTransport; transport->async = settings->AsyncTransport;
if (transport->settings->GatewayEnabled) if (transport->GatewayEnabled)
{ {
transport->layer = TRANSPORT_LAYER_TSG; transport->layer = TRANSPORT_LAYER_TSG;
transport->TcpOut = tcp_new(settings); transport->TcpOut = tcp_new(settings);
@ -1012,6 +1034,11 @@ BOOL transport_set_blocking_mode(rdpTransport* transport, BOOL blocking)
return status; return status;
} }
void transport_set_gateway_enabled(rdpTransport* transport, BOOL GatewayEnabled)
{
transport->GatewayEnabled = GatewayEnabled;
}
static void* transport_client_thread(void* arg) static void* transport_client_thread(void* arg)
{ {
DWORD status; DWORD status;
@ -1055,7 +1082,7 @@ static void* transport_client_thread(void* arg)
transport_get_read_handles(transport, (HANDLE*) &handles, &nCount); transport_get_read_handles(transport, (HANDLE*) &handles, &nCount);
status = WaitForMultipleObjects(nCount, handles, FALSE, 100); status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
if (transport->layer == TRANSPORT_LAYER_CLOSED) if (transport->layer == TRANSPORT_LAYER_CLOSED)
{ {
rdpRdp* rdp = (rdpRdp*) transport->rdp; rdpRdp* rdp = (rdpRdp*) transport->rdp;
@ -1107,6 +1134,7 @@ rdpTransport* transport_new(rdpSettings* settings)
transport->connectedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); transport->connectedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
transport->blocking = TRUE; transport->blocking = TRUE;
transport->GatewayEnabled = FALSE;
InitializeCriticalSectionAndSpinCount(&(transport->ReadLock), 4000); InitializeCriticalSectionAndSpinCount(&(transport->ReadLock), 4000);
InitializeCriticalSectionAndSpinCount(&(transport->WriteLock), 4000); InitializeCriticalSectionAndSpinCount(&(transport->WriteLock), 4000);
@ -1121,20 +1149,7 @@ void transport_free(rdpTransport* transport)
{ {
if (transport) if (transport)
{ {
if (transport->async) transport_stop(transport);
{
if (transport->stopEvent)
{
SetEvent(transport->stopEvent);
WaitForSingleObject(transport->thread, INFINITE);
CloseHandle(transport->thread);
CloseHandle(transport->stopEvent);
transport->thread = NULL;
transport->stopEvent = NULL;
}
}
if (transport->ReceiveBuffer) if (transport->ReceiveBuffer)
Stream_Release(transport->ReceiveBuffer); Stream_Release(transport->ReceiveBuffer);

View File

@ -75,6 +75,7 @@ struct rdp_transport
HANDLE stopEvent; HANDLE stopEvent;
HANDLE thread; HANDLE thread;
BOOL async; BOOL async;
BOOL GatewayEnabled;
CRITICAL_SECTION ReadLock; CRITICAL_SECTION ReadLock;
CRITICAL_SECTION WriteLock; CRITICAL_SECTION WriteLock;
wLog* log; wLog* log;
@ -88,15 +89,16 @@ BOOL transport_disconnect(rdpTransport* transport);
BOOL transport_connect_rdp(rdpTransport* transport); BOOL transport_connect_rdp(rdpTransport* transport);
BOOL transport_connect_tls(rdpTransport* transport); BOOL transport_connect_tls(rdpTransport* transport);
BOOL transport_connect_nla(rdpTransport* transport); BOOL transport_connect_nla(rdpTransport* transport);
BOOL transport_connect_tsg(rdpTransport* transport);
BOOL transport_accept_rdp(rdpTransport* transport); BOOL transport_accept_rdp(rdpTransport* transport);
BOOL transport_accept_tls(rdpTransport* transport); BOOL transport_accept_tls(rdpTransport* transport);
BOOL transport_accept_nla(rdpTransport* transport); BOOL transport_accept_nla(rdpTransport* transport);
void transport_stop(rdpTransport* transport);
int transport_read(rdpTransport* transport, wStream* s); int transport_read(rdpTransport* transport, wStream* s);
int transport_write(rdpTransport* transport, wStream* s); int transport_write(rdpTransport* transport, wStream* s);
void transport_get_fds(rdpTransport* transport, void** rfds, int* rcount); void transport_get_fds(rdpTransport* transport, void** rfds, int* rcount);
int transport_check_fds(rdpTransport* transport); int transport_check_fds(rdpTransport* transport);
BOOL transport_set_blocking_mode(rdpTransport* transport, BOOL blocking); BOOL transport_set_blocking_mode(rdpTransport* transport, BOOL blocking);
void transport_set_gateway_enabled(rdpTransport* transport, BOOL GatewayEnabled);
void transport_get_read_handles(rdpTransport* transport, HANDLE* events, DWORD* count); void transport_get_read_handles(rdpTransport* transport, HANDLE* events, DWORD* count);
wStream* transport_receive_pool_take(rdpTransport* transport); wStream* transport_receive_pool_take(rdpTransport* transport);

View File

@ -787,7 +787,9 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po
tls_print_certificate_name_mismatch_error(hostname, common_name, alt_names, alt_names_count); tls_print_certificate_name_mismatch_error(hostname, common_name, alt_names, alt_names_count);
if (instance->VerifyCertificate) if (instance->VerifyCertificate)
{
accept_certificate = instance->VerifyCertificate(instance, subject, issuer, fingerprint); accept_certificate = instance->VerifyCertificate(instance, subject, issuer, fingerprint);
}
if (!accept_certificate) if (!accept_certificate)
{ {
@ -807,7 +809,9 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po
tls_print_certificate_error(hostname, fingerprint, tls->certificate_store->file); tls_print_certificate_error(hostname, fingerprint, tls->certificate_store->file);
if (instance->VerifyChangedCertificate) if (instance->VerifyChangedCertificate)
{
accept_certificate = instance->VerifyChangedCertificate(instance, subject, issuer, fingerprint, ""); accept_certificate = instance->VerifyChangedCertificate(instance, subject, issuer, fingerprint, "");
}
if (!accept_certificate) if (!accept_certificate)
{ {

View File

@ -90,7 +90,7 @@ int freerdp_tcp_connect(const char* hostname, int port)
if (status != 0) if (status != 0)
{ {
fprintf(stderr, "tcp_connect: getaddrinfo (%s)\n", gai_strerror(status)); //fprintf(stderr, "tcp_connect: getaddrinfo (%s)\n", gai_strerror(status));
return -1; return -1;
} }

View File

@ -328,14 +328,14 @@ BOOL CancelWaitableTimer(HANDLE hTimer)
* http://www.cs.wustl.edu/~schmidt/Timer_Queue.html * http://www.cs.wustl.edu/~schmidt/Timer_Queue.html
*/ */
static void timespec_add_ms(struct timespec* tspec, UINT32 ms) void timespec_add_ms(struct timespec* tspec, UINT32 ms)
{ {
UINT64 ns = tspec->tv_nsec + (ms * 1000000); UINT64 ns = tspec->tv_nsec + (ms * 1000000);
tspec->tv_sec += (ns / 1000000000); tspec->tv_sec += (ns / 1000000000);
tspec->tv_nsec = (ns % 1000000000); tspec->tv_nsec = (ns % 1000000000);
} }
static UINT64 timespec_to_ms(struct timespec* tspec) UINT64 timespec_to_ms(struct timespec* tspec)
{ {
UINT64 ms; UINT64 ms;
ms = tspec->tv_sec * 1000; ms = tspec->tv_sec * 1000;

View File

@ -408,7 +408,7 @@ void InitializeWtsApiStubs(void)
if (!g_WtsApiModule) if (!g_WtsApiModule)
return; return;
pInitWtsApi = GetProcAddress(g_WtsApiModule, "InitWtsApi"); pInitWtsApi = (INIT_WTSAPI_FN) GetProcAddress(g_WtsApiModule, "InitWtsApi");
if (pInitWtsApi) if (pInitWtsApi)
{ {