diff --git a/CMakeLists.txt b/CMakeLists.txt index e8268be12..718f9ff70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -776,8 +776,8 @@ if(WITH_CHANNELS) add_subdirectory(channels) endif() -if(WITH_CLIENT) - add_subdirectory(client) +if(WITH_CLIENT_COMMON OR WITH_CLIENT) +add_subdirectory(client) endif() if(WITH_SERVER) diff --git a/channels/cliprdr/server/cliprdr_main.c b/channels/cliprdr/server/cliprdr_main.c index 96d0dc79d..b082c830e 100644 --- a/channels/cliprdr/server/cliprdr_main.c +++ b/channels/cliprdr/server/cliprdr_main.c @@ -1004,9 +1004,9 @@ static UINT cliprdr_server_receive_filecontents_response(CliprdrServerContext* c response.cbRequested = header->dataLen - 4; response.requestedData = Stream_Pointer(s); /* requestedFileContentsData */ - IFCALLRET(context->ServerFileContentsResponse, error, context, &response); + IFCALLRET(context->ClientFileContentsResponse, error, context, &response); if (error) - WLog_ERR(TAG, "ServerFileContentsResponse failed with error %lu!", error); + WLog_ERR(TAG, "ClientFileContentsResponse failed with error %lu!", error); return error; } diff --git a/client/Android/FreeRDPCore/res/values-zh/strings.xml b/client/Android/FreeRDPCore/res/values-zh/strings.xml new file mode 100644 index 000000000..b4514265c --- /dev/null +++ b/client/Android/FreeRDPCore/res/values-zh/strings.xml @@ -0,0 +1,199 @@ + + + + + + 取消 + 继续 + 登录 + 断开 + + 退出 + 关于 + 帮助 + 新建连接 + 设置 + + 操作 + 连接 + 编辑 + 删除 + + 键盘 + 功能键 + 触控鼠标 + 主目录 + 断开连接 + + 手动连接 + 活动会话数 + + 搜索 + + 登录 + 没有服务 + 连接中 … + 正在断开连接 … + 连接丢失 + 密码错误 + 用户名错误 + 新建连接 + + 主机信息 + 标签* + 远程主机ip或域名 + 端口 + 登录信息 + 登录信息 + 用户名 + 密码 + + 设置 + 显示 + 显示设置 + 颜色深度 + + High Color (16 Bit) + True Color (24 Bit) + Highest Quality (32 Bit) + + + 16 + 24 + 32 + + 分辨率 + 自动 + 全屏 + 自定义 + + 自动 + 全屏 + 自定义 + 640x480 + 720x480 + 800x600 + 1024x768 + 1280x1024 + 1440x900 + 1920x1080 + 1920x1200 + + + 自动 + 全屏 + 自定义 + 640x480 + 720x480 + 800x600 + 1024x768 + 1280x1024 + 1440x900 + 1920x1080 + 1920x1200 + + 宽度 + 高度 + 连接性能 + 性能设置 + RemoteFX + 桌面背景 + 字体平滑 + 桌面拼合 + 拖动是显示窗口内容 + 菜单动画效果 + 视觉样式 + 高级 + 高级设置 + 3G设置 + 使用3G网络时的显示设置 + 使用3G网络时的连接性能 + 路由 + 使用路由 + 路由设置 + SDCard 重定向 + 音频重定向 + + 不要播放 + 在远程主机播放 + 在此设备上播放 + + + 0 + 1 + 2 + + 麦克风重定向 + 连接协议 + + 自动 + RDP + TLS + NLA + + + 0 + 1 + 2 + 3 + + 远程程序 + 工作目录 + Async channel + Async transport + Async input + Async update + 控制台模式 + + ******* + 未设置 + 用户界面 + 隐藏状态栏 + 隐藏缩放控件 + 交换鼠标左右键 + 翻转滚动 + 触摸指针自动滚屏 + 退出时确认是否退出 + 省电设计 + 关闭空闲连接 + 安全 + 接受所有证书 + 清除证书缓存 + %1$d 秒后 + Disabled + + 连接设置 + 设置 + aFreeRDP - FreeRDP for Android + RDP Connections + 帮助 + 关于 + + 不保存即退出? + 点击 “继续” 继续编辑,点击 "取消" 放弃当前更改 + 建立连接失败! + + 由于主机不支持您的设置所以显示设置已经修改为适应主机的设置! + 清除证书缓存成功! + 清楚证书缓存失败! + + 证书验证 + 未能验证远程主机证书的安全性,是否连接? + 请输入您的证书 + 创建快捷方式 + 快捷方式名称: + 连接中 … + 正在登录 … + 关于aFreeRDP + 是否保存连接设置? + 连接设置还没保存! 是否保存? + 保存? + 是否保存更改? + 不再提示 + 退出? + 是否退出? + 清除证书缓存? + 是否清除所有的证书缓存? + Debug Level + Debug Settings + diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index b8b769922..37a811db2 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -19,7 +19,7 @@ add_subdirectory(common) -if(FREERDP_VENDOR) +if(FREERDP_VENDOR AND WITH_CLIENT) if(WIN32) add_subdirectory(Windows) else() @@ -58,28 +58,28 @@ if(FREERDP_VENDOR) endif() # Pick up other clients +if(WITH_CLIENT) + set(FILENAME "ModuleOptions.cmake") + file(GLOB FILEPATHS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*/${FILENAME}") -set(FILENAME "ModuleOptions.cmake") -file(GLOB FILEPATHS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*/${FILENAME}") - -foreach(FILEPATH ${FILEPATHS}) - if(${FILEPATH} MATCHES "^([^/]*)/+${FILENAME}") - string(REGEX REPLACE "^([^/]*)/+${FILENAME}" "\\1" FREERDP_CLIENT ${FILEPATH}) - set(FREERDP_CLIENT_ENABLED 0) - include(${FILEPATH}) - if(FREERDP_CLIENT_ENABLED) - if(NOT (${FREERDP_CLIENT_VENDOR} MATCHES "FreeRDP")) - list(APPEND FREERDP_EXTRA_CLIENTS ${FREERDP_CLIENT}) - if(${FREERDP_CLIENT_VENDOR} MATCHES "${VENDOR}") - set(CLIENT_VENDOR_PATH "client/${FREERDP_CLIENT}" PARENT_SCOPE) + foreach(FILEPATH ${FILEPATHS}) + if(${FILEPATH} MATCHES "^([^/]*)/+${FILENAME}") + string(REGEX REPLACE "^([^/]*)/+${FILENAME}" "\\1" FREERDP_CLIENT ${FILEPATH}) + set(FREERDP_CLIENT_ENABLED 0) + include(${FILEPATH}) + if(FREERDP_CLIENT_ENABLED) + if(NOT (${FREERDP_CLIENT_VENDOR} MATCHES "FreeRDP")) + list(APPEND FREERDP_EXTRA_CLIENTS ${FREERDP_CLIENT}) + if(${FREERDP_CLIENT_VENDOR} MATCHES "${VENDOR}") + set(CLIENT_VENDOR_PATH "client/${FREERDP_CLIENT}" PARENT_SCOPE) + endif() endif() endif() endif() - endif() -endforeach() - -foreach(FREERDP_CLIENT ${FREERDP_EXTRA_CLIENTS}) - add_subdirectory(${FREERDP_CLIENT}) -endforeach() + endforeach() + foreach(FREERDP_CLIENT ${FREERDP_EXTRA_CLIENTS}) + add_subdirectory(${FREERDP_CLIENT}) + endforeach() +endif() diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index b45f18c35..3f056210e 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -342,7 +342,7 @@ BOOL xf_sw_end_paint(rdpContext* context) xf_lock_x11(xfc, FALSE); - xf_rail_paint(xfc, x, y, x + w - 1, y + h - 1); + xf_rail_paint(xfc, x, y, x + w, y + h); xf_unlock_x11(xfc, FALSE); } @@ -455,7 +455,7 @@ BOOL xf_hw_end_paint(rdpContext* context) xf_lock_x11(xfc, FALSE); - xf_rail_paint(xfc, x, y, x + w - 1, y + h - 1); + xf_rail_paint(xfc, x, y, x + w, y + h); xf_unlock_x11(xfc, FALSE); } @@ -1852,7 +1852,11 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context) xfc->_NET_WORKAREA = XInternAtom(xfc->display, "_NET_WORKAREA", False); xfc->_NET_WM_STATE = XInternAtom(xfc->display, "_NET_WM_STATE", False); xfc->_NET_WM_STATE_FULLSCREEN = XInternAtom(xfc->display, "_NET_WM_STATE_FULLSCREEN", False); + xfc->_NET_WM_STATE_MAXIMIZED_HORZ = XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); + xfc->_NET_WM_STATE_MAXIMIZED_VERT = XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_VERT", False); xfc->_NET_WM_FULLSCREEN_MONITORS = XInternAtom(xfc->display, "_NET_WM_FULLSCREEN_MONITORS", False); + xfc->_NET_WM_NAME = XInternAtom(xfc->display, "_NET_WM_NAME", False); + xfc->_NET_WM_PID = XInternAtom(xfc->display, "_NET_WM_PID", False); xfc->_NET_WM_WINDOW_TYPE = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE", False); xfc->_NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE_NORMAL", False); xfc->_NET_WM_WINDOW_TYPE_DIALOG = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE_DIALOG", False); @@ -1863,6 +1867,8 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context) xfc->_NET_WM_STATE_SKIP_PAGER = XInternAtom(xfc->display, "_NET_WM_STATE_SKIP_PAGER", False); xfc->_NET_WM_MOVERESIZE = XInternAtom(xfc->display, "_NET_WM_MOVERESIZE", False); xfc->_NET_MOVERESIZE_WINDOW = XInternAtom(xfc->display, "_NET_MOVERESIZE_WINDOW", False); + + xfc->UTF8_STRING = XInternAtom(xfc->display, "UTF8_STRING", FALSE); xfc->WM_PROTOCOLS = XInternAtom(xfc->display, "WM_PROTOCOLS", False); xfc->WM_DELETE_WINDOW = XInternAtom(xfc->display, "WM_DELETE_WINDOW", False); xfc->WM_STATE = XInternAtom(xfc->display, "WM_STATE", False); diff --git a/client/X11/xf_keyboard.c b/client/X11/xf_keyboard.c index 1d6d9c06d..243e920d2 100644 --- a/client/X11/xf_keyboard.c +++ b/client/X11/xf_keyboard.c @@ -466,7 +466,7 @@ BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym) return TRUE; } - if(xfc->fullscreen_toggle) + if(!xfc->remote_app && xfc->fullscreen_toggle) { if (keysym == XK_Return) { diff --git a/client/X11/xf_monitor.c b/client/X11/xf_monitor.c index 920323ade..346bcd9c4 100644 --- a/client/X11/xf_monitor.c +++ b/client/X11/xf_monitor.c @@ -120,7 +120,6 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) int i; int nmonitors = 0; int primaryMonitorFound = FALSE; - int vX, vY, vWidth, vHeight; VIRTUAL_SCREEN* vscreen; rdpSettings* settings = xfc->settings; @@ -270,10 +269,10 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) if (settings->MonitorCount) { /* Initialize bounding rectangle for all monitors */ - vWidth = settings->MonitorDefArray[0].width; - vHeight = settings->MonitorDefArray[0].height; - vX = settings->MonitorDefArray[0].x; - vY = settings->MonitorDefArray[0].y; + int vX = settings->MonitorDefArray[0].x; + int vY = settings->MonitorDefArray[0].y; + int vR = vX + settings->MonitorDefArray[0].width; + int vB = vY + settings->MonitorDefArray[0].height; xfc->fullscreenMonitors.top = xfc->fullscreenMonitors.bottom = xfc->fullscreenMonitors.left = xfc->fullscreenMonitors.right = settings->MonitorDefArray[0].orig_screen; @@ -285,36 +284,36 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) /* does the same as gdk_rectangle_union */ int destX = MIN(vX, settings->MonitorDefArray[i].x); int destY = MIN(vY, settings->MonitorDefArray[i].y); - int destWidth = MAX(vX + vWidth, settings->MonitorDefArray[i].x + settings->MonitorDefArray[i].width) - destX; - int destHeight = MAX(vY + vHeight, settings->MonitorDefArray[i].y + settings->MonitorDefArray[i].height) - destY; + int destR = MAX(vR, settings->MonitorDefArray[i].x + settings->MonitorDefArray[i].width); + int destB = MAX(vB, settings->MonitorDefArray[i].y + settings->MonitorDefArray[i].height); if (vX != destX) xfc->fullscreenMonitors.left = settings->MonitorDefArray[i].orig_screen; if (vY != destY) xfc->fullscreenMonitors.top = settings->MonitorDefArray[i].orig_screen; - if (vWidth != destWidth) + if (vR != destR) xfc->fullscreenMonitors.right = settings->MonitorDefArray[i].orig_screen; - if (vHeight != destHeight) + if (vB != destB) xfc->fullscreenMonitors.bottom = settings->MonitorDefArray[i].orig_screen; vX = destX; vY = destY; - vWidth = destWidth; - vHeight = destHeight; + vR = destR; + vB = destB; } settings->DesktopPosX = vX; settings->DesktopPosY = vY; vscreen->area.left = 0; - vscreen->area.right = vWidth - 1; + vscreen->area.right = vR - vX - 1; vscreen->area.top = 0; - vscreen->area.bottom = vHeight - 1; + vscreen->area.bottom = vB - vY - 1; if (settings->Workarea) { vscreen->area.top = xfc->workArea.y; - vscreen->area.bottom = (vHeight - (vHeight - (xfc->workArea.height + xfc->workArea.y))) - 1; + vscreen->area.bottom = xfc->workArea.height + xfc->workArea.y - 1; } /* If there are multiple monitors and we have not selected a primary */ diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c index a4617a228..22a941c53 100644 --- a/client/X11/xf_rail.c +++ b/client/X11/xf_rail.c @@ -119,25 +119,17 @@ void xf_rail_adjust_position(xfContext* xfc, xfAppWindow* appWindow) return; /* If current window position disagrees with RDP window position, send update to RDP server */ - if (appWindow->x != (appWindow->windowOffsetX - appWindow->localWindowOffsetCorrX) || - appWindow->y != (appWindow->windowOffsetY - appWindow->localWindowOffsetCorrY) || + if (appWindow->x != appWindow->windowOffsetX || + appWindow->y != appWindow->windowOffsetY || appWindow->width != appWindow->windowWidth || appWindow->height != appWindow->windowHeight) { - /* - * windowOffset corresponds to the window location on the rail server - * but our local window is based uses a local offset since the windowOffset - * can be negative and but X does not support negative values. Not using an - * offset can result in blank areas for a maximized window - */ windowMove.windowId = appWindow->windowId; /* * Calculate new size/position for the rail window(new values for windowOffsetX/windowOffsetY/windowWidth/windowHeight) on the server - * New position is based on: Current local rail window offset + - * Local offset correction(current correction value to translate the local window offset to the server rail window offset) */ - windowMove.left = appWindow->x + appWindow->localWindowOffsetCorrX; - windowMove.top = appWindow->y + appWindow->localWindowOffsetCorrY; + windowMove.left = appWindow->x; + windowMove.top = appWindow->y; windowMove.right = windowMove.left + appWindow->width; windowMove.bottom = windowMove.top + appWindow->height; @@ -163,12 +155,10 @@ void xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow) /* * Calculate new size/position for the rail window(new values for windowOffsetX/windowOffsetY/windowWidth/windowHeight) on the server - * New position is based on: Current local rail window offset + - * Local offset correction(current correction value to translate the local window offset to the server rail window offset) * */ - windowMove.left = appWindow->x + appWindow->localWindowOffsetCorrX; - windowMove.top = appWindow->y + appWindow->localWindowOffsetCorrY; + windowMove.left = appWindow->x; + windowMove.top = appWindow->y; windowMove.right = windowMove.left + appWindow->width; /* In the update to RDP the position is one past the window */ windowMove.bottom = windowMove.top + appWindow->height; @@ -180,8 +170,6 @@ void xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow) XQueryPointer(xfc->display, appWindow->handle, &root_window, &child_window, &x, &y, &child_x, &child_y, &mask); - input->MouseEvent(input, PTR_FLAGS_BUTTON1, x, y); - /* only send the mouse coordinates if not a keyboard move or size */ if ((appWindow->local_move.direction != _NET_WM_MOVERESIZE_MOVE_KEYBOARD) && (appWindow->local_move.direction != _NET_WM_MOVERESIZE_SIZE_KEYBOARD)) @@ -194,8 +182,8 @@ void xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow) * we can start to receive GDI orders for the new window dimensions before we * receive the RAIL ORDER for the new window size. This avoids that race condition. */ - appWindow->windowOffsetX = windowMove.left; - appWindow->windowOffsetY = windowMove.top; + appWindow->windowOffsetX = appWindow->x; + appWindow->windowOffsetY = appWindow->y; appWindow->windowWidth = appWindow->width; appWindow->windowHeight = appWindow->height; appWindow->local_move.state = LMS_TERMINATING; @@ -277,6 +265,7 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI xfAppWindow* appWindow = NULL; xfContext* xfc = (xfContext*) context; UINT32 fieldFlags = orderInfo->fieldFlags; + BOOL position_or_size_updated = FALSE; if (fieldFlags & WINDOW_ORDER_STATE_NEW) { @@ -296,9 +285,7 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI appWindow->width = appWindow->windowWidth = windowState->windowWidth; appWindow->height = appWindow->windowHeight = windowState->windowHeight; - appWindow->localWindowOffsetCorrX = 0; - appWindow->localWindowOffsetCorrY = 0; - + /* Ensure window always gets a window title */ if (fieldFlags & WINDOW_ORDER_FIELD_TITLE) { char* title = NULL; @@ -321,8 +308,6 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI HashTable_Add(xfc->railWindows, (void*) (UINT_PTR) orderInfo->windowId, (void*) appWindow); xf_AppWindowInit(xfc, appWindow); - - return TRUE; } else { @@ -333,37 +318,31 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI if (!appWindow) return FALSE; + /* Keep track of any position/size update so that we can force a refresh of the window */ + if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) || + (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) || + (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) || + (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) || + (fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) || + (fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET) || + (fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY)) + { + position_or_size_updated = TRUE; + } + + /* Update Parameters */ - if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) || - (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)) + if (fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) { - if (fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) - { - appWindow->windowOffsetX = windowState->windowOffsetX; - appWindow->windowOffsetY = windowState->windowOffsetY; + appWindow->windowOffsetX = windowState->windowOffsetX; + appWindow->windowOffsetY = windowState->windowOffsetY; + } - /* - * The rail server can give negative window coordinates when updating windowOffsetX and windowOffsetY, - * but we can only send unsigned integers to the rail server. Therefore, we maintain a local offset. - */ - - if (appWindow->windowOffsetX < 0) - appWindow->localWindowOffsetCorrX = 0 - appWindow->windowOffsetX; - else - appWindow->localWindowOffsetCorrX = 0; - - if (appWindow->windowOffsetY < 0) - appWindow->localWindowOffsetCorrY = 0 - appWindow->windowOffsetY; - else - appWindow->localWindowOffsetCorrY = 0; - } - - if (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) - { - appWindow->windowWidth = windowState->windowWidth; - appWindow->windowHeight = windowState->windowHeight; - } + if (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) + { + appWindow->windowWidth = windowState->windowWidth; + appWindow->windowHeight = windowState->windowHeight; } if (fieldFlags & WINDOW_ORDER_FIELD_OWNER) @@ -479,41 +458,43 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI xf_SetWindowText(xfc, appWindow, appWindow->title); } - if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) || - (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)) + if (position_or_size_updated) { + UINT32 visibilityRectsOffsetX = (appWindow->visibleOffsetX - (appWindow->clientOffsetX - appWindow->windowClientDeltaX)); + UINT32 visibilityRectsOffsetY = (appWindow->visibleOffsetY - (appWindow->clientOffsetY - appWindow->windowClientDeltaY)); + /* * The rail server like to set the window to a small size when it is minimized even though it is hidden * in some cases this can cause the window not to restore back to its original size. Therefore we don't * update our local window when that rail window state is minimized */ - if (appWindow->rail_state == WINDOW_SHOW_MINIMIZED) - return TRUE; + if (appWindow->rail_state != WINDOW_SHOW_MINIMIZED) + { - /* Do nothing if window is already in the correct position */ - if (appWindow->x == (appWindow->windowOffsetX - appWindow->localWindowOffsetCorrX) && - appWindow->y == (appWindow->windowOffsetY - appWindow->localWindowOffsetCorrY) && + /* Redraw window area if already in the correct position */ + if (appWindow->x == appWindow->windowOffsetX && + appWindow->y == appWindow->windowOffsetY && appWindow->width == appWindow->windowWidth && appWindow->height == appWindow->windowHeight) - { - xf_UpdateWindowArea(xfc, appWindow, 0, 0, appWindow->windowWidth, appWindow->windowHeight); - } - else - { - xf_MoveWindow(xfc, appWindow, appWindow->windowOffsetX - appWindow->localWindowOffsetCorrX, appWindow->windowOffsetY - appWindow->localWindowOffsetCorrY, - appWindow->windowWidth, appWindow->windowHeight); + { + xf_UpdateWindowArea(xfc, appWindow, 0, 0, appWindow->windowWidth, appWindow->windowHeight); + } + else + { + xf_MoveWindow(xfc, appWindow, appWindow->windowOffsetX, appWindow->windowOffsetY, + appWindow->windowWidth, appWindow->windowHeight); + } + + xf_SetWindowVisibilityRects(xfc, appWindow, visibilityRectsOffsetX, visibilityRectsOffsetY, appWindow->visibilityRects, appWindow->numVisibilityRects); } } - if (fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS) + /* We should only be using the visibility rects for shaping the window */ + /*if (fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS) { xf_SetWindowRects(xfc, appWindow, appWindow->windowRects, appWindow->numWindowRects); - } + }*/ - if (fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY) - { - xf_SetWindowVisibilityRects(xfc, appWindow, appWindow->visibilityRects, appWindow->numVisibilityRects); - } return TRUE; } diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c index b7a4663e2..28f8bc8f1 100644 --- a/client/X11/xf_window.c +++ b/client/X11/xf_window.c @@ -185,30 +185,37 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen) */ startX = startX + xfc->instance->settings->MonitorLocalShiftX; startY = startY + xfc->instance->settings->MonitorLocalShiftY; + + /* Set monitor bounds */ + if (settings->MonitorCount > 1) + { + xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_FULLSCREEN_MONITORS, 5, + xfc->fullscreenMonitors.top, + xfc->fullscreenMonitors.bottom, + xfc->fullscreenMonitors.left, + xfc->fullscreenMonitors.right, + 1); + } } xf_ResizeDesktopWindow(xfc, window, width, height); + if (fullscreen) + { + /* enter full screen: move the window before adding NET_WM_STATE_FULLSCREEN */ + XMoveWindow(xfc->display, window->handle, startX, startY); + } + /* Set the fullscreen state */ xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4, fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE, xfc->_NET_WM_STATE_FULLSCREEN, 0, 0); - /* Only send monitor bounds if they are valid */ - if ((xfc->fullscreenMonitors.top >= 0) && - (xfc->fullscreenMonitors.bottom >= 0) && - (xfc->fullscreenMonitors.left >= 0) && - (xfc->fullscreenMonitors.right >= 0)) + if (!fullscreen) { - xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_FULLSCREEN_MONITORS, 5, - xfc->fullscreenMonitors.top, - xfc->fullscreenMonitors.bottom, - xfc->fullscreenMonitors.left, - xfc->fullscreenMonitors.right, - 1); + /* leave full screen: move the window after removing NET_WM_STATE_FULLSCREEN */ + XMoveWindow(xfc->display, window->handle, startX, startY); } - - XMoveWindow(xfc->display, window->handle, startX, startY); } /* http://tronche.com/gui/x/xlib/window-information/XGetWindowProperty.html */ @@ -327,7 +334,7 @@ static void xf_SetWindowPID(xfContext* xfc, Window window, pid_t pid) if (!pid) pid = getpid(); - am_wm_pid = XInternAtom(xfc->display, "_NET_WM_PID", False); + am_wm_pid = xfc->_NET_WM_PID; XChangeProperty(xfc->display, window, am_wm_pid, XA_CARDINAL, 32, PropModeReplace, (BYTE*) &pid, 1); @@ -567,9 +574,11 @@ void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, UIN } else { - XChangeProperty(xfc->display, appWindow->handle, xfc->_NET_WM_WINDOW_TYPE, - XA_ATOM, 32, PropModeReplace, (BYTE*) &window_type, 1); + window_type = xfc->_NET_WM_WINDOW_TYPE_NORMAL; } + + XChangeProperty(xfc->display, appWindow->handle, xfc->_NET_WM_WINDOW_TYPE, + XA_ATOM, 32, PropModeReplace, (BYTE*) &window_type, 1); } void xf_SetWindowText(xfContext* xfc, xfAppWindow* appWindow, char* name) @@ -577,8 +586,8 @@ void xf_SetWindowText(xfContext* xfc, xfAppWindow* appWindow, char* name) const size_t i = strlen(name); XStoreName(xfc->display, appWindow->handle, name); - Atom wm_Name = XInternAtom(xfc->display, "_NET_WM_NAME", FALSE); - Atom utf8Str = XInternAtom(xfc->display, "UTF8_STRING", FALSE); + Atom wm_Name = xfc->_NET_WM_NAME; + Atom utf8Str = xfc->UTF8_STRING; XChangeProperty(xfc->display, appWindow->handle, wm_Name, utf8Str, 8, PropModeReplace, (unsigned char *)name, i); @@ -821,9 +830,10 @@ void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state) case WINDOW_SHOW_MAXIMIZED: /* Set the window as maximized */ - xf_SendClientEvent(xfc, appWindow->handle, xfc->_NET_WM_STATE, 4, 1, - XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_VERT", False), - XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False), 0); + xf_SendClientEvent(xfc, appWindow->handle, xfc->_NET_WM_STATE, 4, + _NET_WM_STATE_ADD, + xfc->_NET_WM_STATE_MAXIMIZED_VERT, + xfc->_NET_WM_STATE_MAXIMIZED_HORZ, 0); /* * This is a workaround for the case where the window is maximized locally before the rail server is told to maximize * the window, this appears to be a race condition where the local window with incomplete data and once the window is @@ -838,9 +848,10 @@ void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state) case WINDOW_SHOW: /* Ensure the window is not maximized */ - xf_SendClientEvent(xfc, appWindow->handle, xfc->_NET_WM_STATE, 4, 0, - XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_VERT", False), - XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False), 0); + xf_SendClientEvent(xfc, appWindow->handle, xfc->_NET_WM_STATE, 4, + _NET_WM_STATE_REMOVE, + xfc->_NET_WM_STATE_MAXIMIZED_VERT, + xfc->_NET_WM_STATE_MAXIMIZED_HORZ, 0); /* * Ignore configure requests until both the Maximized properties have been processed * to prevent condition where WM overrides size of request due to one or both of these properties @@ -923,7 +934,7 @@ void xf_SetWindowRects(xfContext* xfc, xfAppWindow* appWindow, RECTANGLE_16* rec } -void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, RECTANGLE_16* rects, int nrects) +void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, UINT32 rectsOffsetX, UINT32 rectsOffsetY, RECTANGLE_16* rects, int nrects) { int i; XRectangle* xrects; @@ -942,7 +953,7 @@ void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, RECTANG xrects[i].height = rects[i].bottom - rects[i].top; } - XShapeCombineRectangles(xfc->display, appWindow->handle, ShapeBounding, 0, 0, xrects, nrects, ShapeSet, 0); + XShapeCombineRectangles(xfc->display, appWindow->handle, ShapeBounding, rectsOffsetX, rectsOffsetY, xrects, nrects, ShapeSet, 0); free(xrects); #endif @@ -951,20 +962,14 @@ void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, RECTANG void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int width, int height) { int ax, ay; - UINT32 translatedWindowOffsetX; - UINT32 translatedWindowOffsetY; - /* Translate the server rail window offset to a local offset */ - translatedWindowOffsetX = (appWindow->windowOffsetX - appWindow->localWindowOffsetCorrX); - translatedWindowOffsetY = (appWindow->windowOffsetY - appWindow->localWindowOffsetCorrY); + ax = x + appWindow->windowOffsetX; + ay = y + appWindow->windowOffsetY; - ax = x + translatedWindowOffsetX; - ay = y + translatedWindowOffsetY; - - if (ax + width > translatedWindowOffsetX + appWindow->width) - width = (translatedWindowOffsetX + appWindow->width - 1) - ax; - if (ay + height > translatedWindowOffsetY + appWindow->height) - height = (translatedWindowOffsetY + appWindow->height - 1) - ay; + if (ax + width > appWindow->windowOffsetX + appWindow->width) + width = (appWindow->windowOffsetX + appWindow->width - 1) - ax; + if (ay + height > appWindow->windowOffsetY + appWindow->height) + height = (appWindow->windowOffsetY + appWindow->height - 1) - ay; xf_lock_x11(xfc, TRUE); diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h index 9120fd1df..0a41c798a 100644 --- a/client/X11/xf_window.h +++ b/client/X11/xf_window.h @@ -102,22 +102,22 @@ struct xf_app_window UINT32 dwExStyle; UINT32 showState; - UINT32 clientOffsetX; - UINT32 clientOffsetY; + INT32 clientOffsetX; + INT32 clientOffsetY; UINT32 clientAreaWidth; UINT32 clientAreaHeight; - UINT32 windowOffsetX; - UINT32 windowOffsetY; - UINT32 windowClientDeltaX; - UINT32 windowClientDeltaY; + INT32 windowOffsetX; + INT32 windowOffsetY; + INT32 windowClientDeltaX; + INT32 windowClientDeltaY; UINT32 windowWidth; UINT32 windowHeight; UINT32 numWindowRects; RECTANGLE_16* windowRects; - UINT32 visibleOffsetX; - UINT32 visibleOffsetY; + INT32 visibleOffsetX; + INT32 visibleOffsetY; UINT32 numVisibilityRects; RECTANGLE_16* visibilityRects; @@ -160,7 +160,7 @@ void xf_MoveWindow(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int wid void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state); //void xf_SetWindowIcon(xfContext* xfc, xfAppWindow* appWindow, rdpIcon* icon); void xf_SetWindowRects(xfContext* xfc, xfAppWindow* appWindow, RECTANGLE_16* rects, int nrects); -void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, RECTANGLE_16* rects, int nrects); +void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, UINT32 rectsOffsetX, UINT32 rectsOffsetY, RECTANGLE_16* rects, int nrects); void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, UINT32 ex_style); void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int width, int height); void xf_DestroyWindow(xfContext* xfc, xfAppWindow* appWindow); diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index 5e1bdfab1..a885536c7 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -185,6 +185,8 @@ struct xf_context xfClipboard* clipboard; CliprdrClientContext* cliprdr; + Atom UTF8_STRING; + Atom _NET_WM_ICON; Atom _MOTIF_WM_HINTS; Atom _NET_CURRENT_DESKTOP; @@ -192,11 +194,16 @@ struct xf_context Atom _NET_WM_STATE; Atom _NET_WM_STATE_FULLSCREEN; + Atom _NET_WM_STATE_MAXIMIZED_HORZ; + Atom _NET_WM_STATE_MAXIMIZED_VERT; Atom _NET_WM_STATE_SKIP_TASKBAR; Atom _NET_WM_STATE_SKIP_PAGER; Atom _NET_WM_FULLSCREEN_MONITORS; + Atom _NET_WM_NAME; + Atom _NET_WM_PID; + Atom _NET_WM_WINDOW_TYPE; Atom _NET_WM_WINDOW_TYPE_NORMAL; Atom _NET_WM_WINDOW_TYPE_DIALOG; diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake index 244fdcf6e..9d501c164 100644 --- a/cmake/ConfigOptions.cmake +++ b/cmake/ConfigOptions.cmake @@ -60,16 +60,17 @@ CMAKE_DEPENDENT_OPTION(TESTS_WTSAPI_EXTRA "Build extra WTSAPI tests (interactive option(WITH_SAMPLE "Build sample code" OFF) -option(WITH_CLIENT "Build client binaries" ON) +option(WITH_CLIENT_COMMON "Build client common library" ON) +cmake_dependent_option(WITH_CLIENT "Build client binaries" ON WITH_CLIENT_COMMON ON) + option(WITH_SERVER "Build server binaries" OFF) option(STATIC_CHANNELS "Build channels statically" ON) option(WITH_CHANNELS "Build virtual channel plugins" ON) -if(WITH_CLIENT AND WITH_CHANNELS) - option(WITH_CLIENT_CHANNELS "Build virtual channel plugins" ON) -endif() +cmake_dependent_option(WITH_CLIENT_CHANNELS "Build virtual channel plugins" ON + "WITH_CLIENT_COMMON;WITH_CHANNELS" ON) if(WITH_SERVER AND WITH_CHANNELS) option(WITH_SERVER_CHANNELS "Build virtual channel plugins" ON) diff --git a/include/freerdp/window.h b/include/freerdp/window.h index c52c35c72..4a5b2b84f 100644 --- a/include/freerdp/window.h +++ b/include/freerdp/window.h @@ -174,22 +174,22 @@ struct _WINDOW_STATE_ORDER UINT32 extendedStyle; UINT32 showState; RAIL_UNICODE_STRING titleInfo; - UINT32 clientOffsetX; - UINT32 clientOffsetY; + INT32 clientOffsetX; + INT32 clientOffsetY; UINT32 clientAreaWidth; UINT32 clientAreaHeight; UINT32 RPContent; UINT32 rootParentHandle; - UINT32 windowOffsetX; - UINT32 windowOffsetY; - UINT32 windowClientDeltaX; - UINT32 windowClientDeltaY; + INT32 windowOffsetX; + INT32 windowOffsetY; + INT32 windowClientDeltaX; + INT32 windowClientDeltaY; UINT32 windowWidth; UINT32 windowHeight; UINT32 numWindowRects; RECTANGLE_16* windowRects; - UINT32 visibleOffsetX; - UINT32 visibleOffsetY; + INT32 visibleOffsetX; + INT32 visibleOffsetY; UINT32 numVisibilityRects; RECTANGLE_16* visibilityRects; }; diff --git a/libfreerdp/cache/glyph.c b/libfreerdp/cache/glyph.c index 037c5a5d9..0157d40bc 100644 --- a/libfreerdp/cache/glyph.c +++ b/libfreerdp/cache/glyph.c @@ -260,6 +260,12 @@ BOOL update_gdi_fast_index(rdpContext* context, FAST_INDEX_ORDER* fastIndex) if (opRight == 0) opRight = fastIndex->bkRight; + /* Server can send a massive number (32766) which appears to be + * undocumented special behavior for "Erase all the way right". + * X11 has nondeterministic results asking for a draw that wide. */ + if (opRight > context->instance->settings->DesktopWidth) + opRight = context->instance->settings->DesktopWidth; + if (x == -32768) x = fastIndex->bkLeft; @@ -313,6 +319,10 @@ BOOL update_gdi_fast_glyph(rdpContext* context, FAST_GLYPH_ORDER* fastGlyph) if (opRight == 0) opRight = fastGlyph->bkRight; + /* See update_gdi_fast_index opRight comment. */ + if (opRight > context->instance->settings->DesktopWidth) + opRight = context->instance->settings->DesktopWidth; + if (x == -32768) x = fastGlyph->bkLeft; diff --git a/libfreerdp/codec/color.c b/libfreerdp/codec/color.c index 7e4235cb8..08c5c4284 100644 --- a/libfreerdp/codec/color.c +++ b/libfreerdp/codec/color.c @@ -3444,8 +3444,8 @@ int freerdp_image32_copy(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDs pSrcPixel++; } - pSrcPixel = (UINT32*) &((BYTE*) pSrcPixel)[nSrcStep]; - pDstPixel = (BYTE*) &((BYTE*) pDstPixel)[nDstStep]; + pSrcPixel = (UINT32*) &((BYTE*) pSrcPixel)[nSrcPad]; + pDstPixel = (BYTE*) &((BYTE*) pDstPixel)[nDstPad]; } return 1; diff --git a/winpr/include/winpr/wlog.h b/winpr/include/winpr/wlog.h index 7ac9dd002..f7c0efd17 100644 --- a/winpr/include/winpr/wlog.h +++ b/winpr/include/winpr/wlog.h @@ -32,6 +32,7 @@ extern "C" { #include #include +#include typedef struct _wLog wLog; typedef struct _wLogMessage wLogMessage; @@ -115,6 +116,7 @@ struct _wLogLayout #define WLOG_APPENDER_CALLBACK 3 #define WLOG_APPENDER_SYSLOG 4 #define WLOG_APPENDER_JOURNALD 5 +#define WLOG_APPENDER_UDP 6 #define WLOG_PACKET_INBOUND 1 #define WLOG_PACKET_OUTBOUND 2 @@ -213,6 +215,16 @@ struct _wLogJournaldAppender }; typedef struct _wLogJournaldAppender wLogJournaldAppender; +struct _wLogUdpAppender +{ + WLOG_APPENDER_COMMON(); + char *host; + struct sockaddr targetAddr; + int targetAddrLen; + SOCKET sock; +}; +typedef struct _wLogUdpAppender wLogUdpAppender; + /** * Filter diff --git a/winpr/libwinpr/path/path.c b/winpr/libwinpr/path/path.c index de7b2aaeb..2f853aad0 100644 --- a/winpr/libwinpr/path/path.c +++ b/winpr/libwinpr/path/path.c @@ -596,13 +596,13 @@ HRESULT PathCchRemoveExtensionW(PWSTR pszPath, size_t cchPath) BOOL PathCchIsRootA(PCSTR pszPath) { WLog_ERR(TAG, "%s: not implemented", __FUNCTION__); - return E_NOTIMPL; + return FALSE; } BOOL PathCchIsRootW(PCWSTR pszPath) { WLog_ERR(TAG, "%s: not implemented", __FUNCTION__); - return E_NOTIMPL; + return FALSE; } /** diff --git a/winpr/libwinpr/thread/argv.c b/winpr/libwinpr/thread/argv.c index 2bd7dc4fb..ad96da236 100644 --- a/winpr/libwinpr/thread/argv.c +++ b/winpr/libwinpr/thread/argv.c @@ -101,7 +101,6 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) LPSTR* pArgs; int maxNumArgs; int maxBufferSize; - int currentIndex; int cmdLineLength; BOOL* lpEscapedChars; LPSTR lpEscapedCmdLine; @@ -167,36 +166,29 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) p += length; for (i = 0; i < (n / 2); i++) - { - *pOutput = '\\'; - pOutput++; - } + *pOutput++ = '\\'; p += n + 1; if ((n % 2) != 0) lpEscapedChars[pOutput - lpEscapedCmdLine] = TRUE; - *pOutput = '"'; - pOutput++; + *pOutput++ = '"'; pLastEnd = p; } - *pOutput = '\0'; - pOutput++; + *pOutput++ = '\0'; lpCmdLine = (LPCSTR) lpEscapedCmdLine; cmdLineLength = strlen(lpCmdLine); } maxNumArgs = 2; - currentIndex = 0; p = (char*) lpCmdLine; - while (currentIndex < cmdLineLength - 1) + while (p < lpCmdLine + cmdLineLength) { - index = strcspn(p, " \t"); - currentIndex += (index + 1); - p = (char*) &lpCmdLine[currentIndex]; + p += strcspn(p, " \t"); + p += strspn(p, " \t"); maxNumArgs++; } @@ -209,32 +201,24 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) pArgs = (LPSTR*) buffer; pOutput = (char*) &buffer[maxNumArgs * (sizeof(char*))]; numArgs = 0; - currentIndex = 0; p = (char*) lpCmdLine; - while (currentIndex < cmdLineLength) + while (p < lpCmdLine + cmdLineLength) { - pBeg = pEnd = p; + pBeg = p; while (1) { - index = strcspn(p, " \t\"\0"); - - if ((p[index] == '"') && (lpEscapedChars[&p[index] - lpCmdLine])) - { - p = &p[index + 1]; - continue; - } - - break; + p += strcspn(p, " \t\"\0"); + if ((*p != '"') || !lpEscapedChars[p - lpCmdLine]) + break; + p++; } - if (p[index] != '"') + if (*p != '"') { /* no whitespace escaped with double quotes */ - p = &p[index + 1]; - pEnd = p - 1; - length = (pEnd - pBeg); + length = p - pBeg; CopyMemory(pOutput, pBeg, length); pOutput[length] = '\0'; pArgs[numArgs++] = pOutput; @@ -242,62 +226,35 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) } else { - p = &p[index + 1]; + p++; while (1) { - index = strcspn(p, "\"\0"); - - if ((p[index] == '"') && (lpEscapedChars[&p[index] - lpCmdLine])) - { - p = &p[index + 1]; - continue; - } - - break; + p += strcspn(p, "\"\0"); + if ((*p != '"') || !lpEscapedChars[p - lpCmdLine]) + break; + p++; } - if (p[index] != '"') - { + if (*p != '"') WLog_ERR(TAG, "parsing error: uneven number of unescaped double quotes!"); - } - if (p[index] == '\0') - { - p = &p[index + 1]; - pEnd = p - 1; - } - else - { - p = &p[index + 1]; - index = strcspn(p, " \t\0"); - p = &p[index + 1]; - pEnd = p - 1; - } + if (*p && *(++p)) + p += strcspn(p, " \t\0"); - length = 0; pArgs[numArgs++] = pOutput; - while (pBeg < pEnd) + while (pBeg < p) { if (*pBeg != '"') - { - *pOutput = *pBeg; - pOutput++; - length++; - } - + *pOutput++ = *pBeg; pBeg++; } - *pOutput = '\0'; - pOutput++; + *pOutput++ = '\0'; } - while ((*p == ' ') || (*p == '\t')) - p++; - - currentIndex = (p - lpCmdLine); + p += strspn(p, " \t"); } free(lpEscapedCmdLine); diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt index a84d180f8..2a8411966 100644 --- a/winpr/libwinpr/utils/CMakeLists.txt +++ b/winpr/libwinpr/utils/CMakeLists.txt @@ -94,6 +94,8 @@ set(${MODULE_PREFIX}_WLOG_SRCS wlog/CallbackAppender.h wlog/ConsoleAppender.c wlog/ConsoleAppender.h + wlog/UdpAppender.c + wlog/UdpAppender.h ${SYSLOG_SRCS} ${JOURNALD_SRCS} ) diff --git a/winpr/libwinpr/utils/wlog/Appender.c b/winpr/libwinpr/utils/wlog/Appender.c index 8008f6df3..a9c4d566f 100644 --- a/winpr/libwinpr/utils/wlog/Appender.c +++ b/winpr/libwinpr/utils/wlog/Appender.c @@ -58,6 +58,9 @@ wLogAppender* WLog_Appender_New(wLog* log, DWORD logAppenderType) appender = (wLogAppender*) WLog_JournaldAppender_New(log); break; #endif + case WLOG_APPENDER_UDP: + appender = (wLogAppender*) WLog_UdpAppender_New(log); + break; default: fprintf(stderr, "%s: unknown handler type %d\n", __FUNCTION__, logAppenderType); appender = NULL; @@ -118,6 +121,9 @@ void WLog_Appender_Free(wLog* log, wLogAppender* appender) WLog_JournaldAppender_Free(log, (wLogJournaldAppender *) appender); break; #endif + case WLOG_APPENDER_UDP: + WLog_UdpAppender_Free(log, (wLogUdpAppender *) appender); + break; default: fprintf(stderr, "%s: don't know how to free appender type %d\n", __FUNCTION__, appender->Type); break; diff --git a/winpr/libwinpr/utils/wlog/Appender.h b/winpr/libwinpr/utils/wlog/Appender.h index ccb57085a..6b9b8ee21 100644 --- a/winpr/libwinpr/utils/wlog/Appender.h +++ b/winpr/libwinpr/utils/wlog/Appender.h @@ -26,6 +26,7 @@ #include "wlog/BinaryAppender.h" #include "wlog/ConsoleAppender.h" #include "wlog/CallbackAppender.h" +#include "wlog/UdpAppender.h" #ifdef HAVE_SYSLOG_H #include "wlog/SyslogAppender.h" diff --git a/winpr/libwinpr/utils/wlog/UdpAppender.c b/winpr/libwinpr/utils/wlog/UdpAppender.c new file mode 100644 index 000000000..bc161d37b --- /dev/null +++ b/winpr/libwinpr/utils/wlog/UdpAppender.c @@ -0,0 +1,209 @@ +/** + * WinPR: Windows Portable Runtime + * WinPR Logger + * + * Copyright © 2015 Thincast Technologies GmbH + * Copyright © 2015 David FORT + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#include +#include +#include + +#include + +#include "wlog/Message.h" +#include "wlog/UdpAppender.h" + +#ifndef _WIN32 +#include +#include +#include +#endif + +static BOOL WLog_UdpAppender_Open(wLog* log, wLogUdpAppender* appender) +{ + char addressString[256]; + struct addrinfo hints; + struct addrinfo* result; + int status, addrLen; + char *colonPos; + + + if (!appender) + return FALSE; + + if (appender->targetAddrLen) /* already opened */ + return TRUE; + + colonPos = strchr(appender->host, ':'); + if (!colonPos) + return FALSE; + addrLen = colonPos - appender->host; + memcpy(addressString, appender->host, addrLen); + addressString[addrLen] = '\0'; + + ZeroMemory(&hints, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + + status = getaddrinfo(addressString, colonPos+1, &hints, &result); + if (status != 0) + return FALSE; + + if (result->ai_addrlen > sizeof(appender->targetAddr)) + { + freeaddrinfo(result); + return FALSE; + } + + memcpy(&appender->targetAddr, result->ai_addr, result->ai_addrlen); + appender->targetAddrLen = result->ai_addrlen; + + + return TRUE; +} + +BOOL Wlog_UdpAppender_SetTarget(wLogUdpAppender* appender, const char *host) +{ + + appender->targetAddrLen = 0; + if (appender->host) + free(appender->host); + + appender->host = _strdup(host); + return (appender->host != NULL) && WLog_UdpAppender_Open(NULL, appender); +} + +static BOOL WLog_UdpAppender_Close(wLog* log, wLogUdpAppender* appender) +{ + if (!log || !appender) + return FALSE; + + return TRUE; +} + +static BOOL WLog_UdpAppender_WriteMessage(wLog* log, wLogUdpAppender* appender, wLogMessage* message) +{ + char prefix[WLOG_MAX_PREFIX_SIZE]; + + if (!log || !appender || !message) + return FALSE; + + message->PrefixString = prefix; + WLog_Layout_GetMessagePrefix(log, appender->Layout, message); + + _sendto(appender->sock, message->PrefixString, strlen(message->PrefixString), + 0, &appender->targetAddr, appender->targetAddrLen); + + _sendto(appender->sock, message->TextString, strlen(message->TextString), + 0, &appender->targetAddr, appender->targetAddrLen); + + _sendto(appender->sock, "\n", 1, 0, &appender->targetAddr, appender->targetAddrLen); + + return TRUE; +} + +static BOOL WLog_UdpAppender_WriteDataMessage(wLog* log, wLogUdpAppender* appender, wLogMessage* message) +{ + if (!log || !appender || !message) + return FALSE; + + return TRUE; +} + +static BOOL WLog_UdpAppender_WriteImageMessage(wLog* log, wLogUdpAppender* appender, wLogMessage* message) +{ + if (!log || !appender || !message) + return FALSE; + + + return TRUE; +} + +wLogUdpAppender* WLog_UdpAppender_New(wLog* log) +{ + wLogUdpAppender* appender; + DWORD nSize; + LPCSTR name; + + appender = (wLogUdpAppender*) calloc(1, sizeof(wLogUdpAppender)); + if (!appender) + return NULL; + + appender->Type = WLOG_APPENDER_UDP; + + appender->Open = (WLOG_APPENDER_OPEN_FN) WLog_UdpAppender_Open; + appender->Close = (WLOG_APPENDER_OPEN_FN) WLog_UdpAppender_Close; + appender->WriteMessage = + (WLOG_APPENDER_WRITE_MESSAGE_FN) WLog_UdpAppender_WriteMessage; + appender->WriteDataMessage = + (WLOG_APPENDER_WRITE_DATA_MESSAGE_FN) WLog_UdpAppender_WriteDataMessage; + appender->WriteImageMessage = + (WLOG_APPENDER_WRITE_IMAGE_MESSAGE_FN) WLog_UdpAppender_WriteImageMessage; + + appender->sock = _socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (appender->sock == INVALID_SOCKET) + goto error_sock; + + name = "WLOG_UDP_TARGET"; + nSize = GetEnvironmentVariableA(name, NULL, 0); + if (nSize) + { + appender->host = (LPSTR) malloc(nSize); + if (!appender->host) + goto error_host_alloc; + + GetEnvironmentVariableA(name, appender->host, nSize); + + if (!WLog_UdpAppender_Open(log, appender)) + goto error_open; + } + else + { + appender->host = _strdup("127.0.0.1:20000"); + if (!appender->host) + goto error_host_alloc; + } + + return appender; + +error_open: + free(appender->host); +error_host_alloc: + closesocket(appender->sock); +error_sock: + free(appender); + return NULL; +} + +void WLog_UdpAppender_Free(wLog* log, wLogUdpAppender* appender) +{ + if (appender) + { + if (appender->sock != INVALID_SOCKET) + { + closesocket(appender->sock); + appender->sock = INVALID_SOCKET; + } + free(appender->host); + free(appender); + } +} diff --git a/winpr/libwinpr/utils/wlog/UdpAppender.h b/winpr/libwinpr/utils/wlog/UdpAppender.h new file mode 100644 index 000000000..cd25345f4 --- /dev/null +++ b/winpr/libwinpr/utils/wlog/UdpAppender.h @@ -0,0 +1,35 @@ +/** + * Copyright © 2015 Thincast Technologies GmbH + * Copyright © 2015 David FORT + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WINPR_LIBWINPR_UTILS_WLOG_UDPAPPENDER_H_ +#define WINPR_LIBWINPR_UTILS_WLOG_UDPAPPENDER_H_ + +#include + +#include "wlog/wlog.h" + +WINPR_API wLogUdpAppender* WLog_UdpAppender_New(wLog* log); +WINPR_API void WLog_UdpAppender_Free(wLog* log, wLogUdpAppender* appender); +WINPR_API BOOL Wlog_UdpAppender_SetTarget(wLogUdpAppender* appender, const char *host); + +#endif /* WINPR_LIBWINPR_UTILS_WLOG_UDPAPPENDER_H_ */ diff --git a/winpr/libwinpr/utils/wlog/wlog.c b/winpr/libwinpr/utils/wlog/wlog.c index 7dc6208e8..123fe6384 100644 --- a/winpr/libwinpr/utils/wlog/wlog.c +++ b/winpr/libwinpr/utils/wlog/wlog.c @@ -706,6 +706,8 @@ wLog* WLog_GetRoot() else if (_stricmp(env, "JOURNALD") == 0) logAppenderType = WLOG_APPENDER_JOURNALD; #endif + else if (_stricmp(env, "UDP") == 0) + logAppenderType = WLOG_APPENDER_UDP; free(env); }