-#include "stdafx.h"\r
-\r
-#include <zmouse.h>\r
-\r
-#include "rdesktop/rdesktop.h"\r
-#include "rdesktop/proto.h"\r
-\r
-extern "C"\r
-{\r
- /* ==== BEGIN POOP ==== */\r
- // Temporary implementations of stuff we totally positively need to make the Real Thing happy\r
- /* produce a hex dump */\r
- void\r
- hexdump(unsigned char *p, unsigned int len)\r
- {\r
- unsigned char *line = p;\r
- int i, thisline;\r
- unsigned int offset = 0;\r
-\r
- while (offset < len)\r
- {\r
- printf("%04x ", offset);\r
- thisline = len - offset;\r
- if (thisline > 16)\r
- thisline = 16;\r
-\r
- for (i = 0; i < thisline; i++)\r
- printf("%02x ", line[i]);\r
-\r
- for (; i < 16; i++)\r
- printf(" ");\r
-\r
- for (i = 0; i < thisline; i++)\r
- printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');\r
-\r
- printf("\n");\r
- offset += thisline;\r
- line += thisline;\r
- }\r
- }\r
-\r
- void generate_random(uint8 * random)\r
- {\r
- memcpy(random, "12345678901234567890123456789012", 32);\r
- }\r
-\r
- /* report an error */\r
- void\r
- error(char *format, ...)\r
- {\r
- va_list ap;\r
-\r
- fprintf(stderr, "ERROR: ");\r
-\r
- va_start(ap, format);\r
- vfprintf(stderr, format, ap);\r
- va_end(ap);\r
- }\r
-\r
- /* report a warning */\r
- void\r
- warning(char *format, ...)\r
- {\r
- va_list ap;\r
-\r
- fprintf(stderr, "WARNING: ");\r
-\r
- va_start(ap, format);\r
- vfprintf(stderr, format, ap);\r
- va_end(ap);\r
- }\r
-\r
- /* report an unimplemented protocol feature */\r
- void\r
- unimpl(char *format, ...)\r
- {\r
- va_list ap;\r
-\r
- fprintf(stderr, "NOT IMPLEMENTED: ");\r
-\r
- va_start(ap, format);\r
- vfprintf(stderr, format, ap);\r
- va_end(ap);\r
- }\r
-\r
- /* Create the bitmap cache directory */\r
- BOOL\r
- rd_pstcache_mkdir(void)\r
- {\r
- char *home;\r
- char bmpcache_dir[256];\r
-\r
- home = getenv("HOME");\r
-\r
- if (home == NULL)\r
- return False;\r
-\r
- sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop");\r
-\r
- if ((_mkdir(bmpcache_dir) == -1) && errno != EEXIST)\r
- {\r
- perror(bmpcache_dir);\r
- return False;\r
- }\r
-\r
- sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop/cache");\r
-\r
- if ((_mkdir(bmpcache_dir) == -1) && errno != EEXIST)\r
- {\r
- perror(bmpcache_dir);\r
- return False;\r
- }\r
-\r
- return True;\r
- }\r
-\r
- /* open a file in the .rdesktop directory */\r
- int\r
- rd_open_file(char *filename)\r
- {\r
- char *home;\r
- char fn[256];\r
- int fd;\r
-\r
- home = getenv("HOME");\r
- if (home == NULL)\r
- return -1;\r
- sprintf(fn, "%s/.rdesktop/%s", home, filename);\r
- fd = _open(fn, _O_RDWR | _O_CREAT, 0);\r
- if (fd == -1)\r
- perror(fn);\r
- return fd;\r
- }\r
-\r
- /* close file */\r
- void\r
- rd_close_file(int fd)\r
- {\r
- _close(fd);\r
- }\r
-\r
- /* read from file*/\r
- int\r
- rd_read_file(int fd, void *ptr, int len)\r
- {\r
- return _read(fd, ptr, len);\r
- }\r
-\r
- /* write to file */\r
- int\r
- rd_write_file(int fd, void *ptr, int len)\r
- {\r
- return _write(fd, ptr, len);\r
- }\r
-\r
- /* move file pointer */\r
- int\r
- rd_lseek_file(int fd, int offset)\r
- {\r
- return _lseek(fd, offset, SEEK_SET);\r
- }\r
-\r
- /* do a write lock on a file */\r
- BOOL\r
- rd_lock_file(int fd, int start, int len)\r
- {\r
- // TODOOO...\r
- return False;\r
- }\r
-\r
- int\r
- load_licence(RDPCLIENT * This, unsigned char **data)\r
- {\r
- return -1;\r
- }\r
-\r
- void\r
- save_licence(RDPCLIENT * This, unsigned char *data, int length)\r
- {\r
- }\r
-\r
- /* ==== END POOP ==== */\r
-\r
- /* ==== UI ==== */\r
- // Globals are totally teh evil, but cut me some slack here\r
- HWND hwnd;\r
- HBITMAP hbmBuffer;\r
- PVOID pBuffer;\r
- HDC hdcBuffer;\r
- UINT wmZMouseWheel;\r
-\r
-};\r
-\r
-static\r
-void\r
-mstsc_mousewheel(RDPCLIENT * This, int value, LPARAM lparam)\r
-{\r
- uint16 button;\r
-\r
- if(value < 0)\r
- button = MOUSE_FLAG_BUTTON5;\r
- else\r
- button = MOUSE_FLAG_BUTTON4;\r
-\r
- if(value < 0)\r
- value = - value;\r
-\r
- for(int click = 0; click < value; click += WHEEL_DELTA)\r
- rdp_send_input(This, GetTickCount(), RDP_INPUT_MOUSE, button | MOUSE_FLAG_DOWN, LOWORD(lparam), HIWORD(lparam));\r
-}\r
-\r
-static\r
-LRESULT\r
-CALLBACK\r
-mstsc_WndProc(HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lparam)\r
-{\r
- // BUGBUG: LongToPtr & PtrToLong will break on Win64\r
-\r
- RDPCLIENT * This = reinterpret_cast<RDPCLIENT *>(LongToPtr(GetWindowLongPtr(hwnd, GWLP_USERDATA)));\r
-\r
- switch(uMsg)\r
- {\r
- case WM_CLOSE:\r
- DestroyWindow(hwnd);\r
- break;\r
-\r
- // FIXME: temporary\r
- case WM_DESTROY:\r
- PostQuitMessage(0);\r
- break;\r
-\r
- /* Initialization */\r
- case WM_CREATE:\r
- This = static_cast<RDPCLIENT *>(reinterpret_cast<LPCREATESTRUCT>(lparam)->lpCreateParams);\r
- SetWindowLongPtr(hwnd, GWLP_USERDATA, PtrToLong(This));\r
- break;\r
-\r
- /* Painting */\r
- case WM_PRINTCLIENT:\r
- if(wparam == 0)\r
- break;\r
-\r
- case WM_PAINT:\r
- {\r
- HDC hdc = (HDC)wparam;\r
-\r
- // A DC was provided: print the whole client area into it\r
- if(hdc)\r
- {\r
- RECT rc;\r
- GetClientRect(hwnd, &rc);\r
- BitBlt(hdc, 0, 0, rc.right, rc.bottom, hdcBuffer, 0, 0, SRCCOPY);\r
- }\r
- // Otherwise, we're refreshing to screen\r
- else\r
- {\r
- PAINTSTRUCT ps;\r
- hdc = BeginPaint(hwnd, &ps);\r
-\r
- BitBlt\r
- (\r
- hdc,\r
- ps.rcPaint.left,\r
- ps.rcPaint.top,\r
- ps.rcPaint.right - ps.rcPaint.left,\r
- ps.rcPaint.bottom - ps.rcPaint.top,\r
- hdcBuffer,\r
- ps.rcPaint.left,\r
- ps.rcPaint.top,\r
- SRCCOPY\r
- );\r
-\r
- EndPaint(hwnd, &ps);\r
- }\r
- }\r
-\r
- break;\r
-\r
- /* Keyboard stuff */\r
- case WM_SYSKEYDOWN:\r
- case WM_KEYDOWN:\r
- rdp_send_input(This, GetMessageTime(), RDP_INPUT_SCANCODE, RDP_KEYPRESS | (lparam & 0x1000000 ? KBD_FLAG_EXT : 0), LOBYTE(HIWORD(lparam)), 0);\r
- break;\r
-\r
- case WM_SYSKEYUP:\r
- case WM_KEYUP:\r
- rdp_send_input(This, GetMessageTime(), RDP_INPUT_SCANCODE, RDP_KEYRELEASE | (lparam & 0x1000000 ? KBD_FLAG_EXT : 0), LOBYTE(HIWORD(lparam)), 0);\r
- break;\r
-\r
- /* Mouse stuff */\r
- // Cursor shape\r
- case WM_SETCURSOR:\r
- if(LOWORD(lparam) == HTCLIENT)\r
- {\r
- //SetCursor(hcursor);\r
- return TRUE;\r
- }\r
-\r
- break;\r
-\r
- // Movement\r
- case WM_MOUSEMOVE:\r
- //if(This->sendmotion || wparam & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON | MK_XBUTTON1 | MK_XBUTTON2))\r
- rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, LOWORD(lparam), HIWORD(lparam));\r
-\r
- break;\r
-\r
- // Buttons\r
- // TODO: X buttons\r
- case WM_LBUTTONDOWN:\r
- rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1 | MOUSE_FLAG_DOWN, LOWORD(lparam), HIWORD(lparam));\r
- break;\r
-\r
- case WM_RBUTTONDOWN:\r
- rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2 | MOUSE_FLAG_DOWN, LOWORD(lparam), HIWORD(lparam));\r
- break;\r
-\r
- case WM_MBUTTONDOWN:\r
- rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON3 | MOUSE_FLAG_DOWN, LOWORD(lparam), HIWORD(lparam));\r
- break;\r
-\r
- case WM_LBUTTONUP:\r
- rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, LOWORD(lparam), HIWORD(lparam));\r
- break;\r
-\r
- case WM_RBUTTONUP:\r
- rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2, LOWORD(lparam), HIWORD(lparam));\r
- break;\r
-\r
- case WM_MBUTTONUP:\r
- rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON3, LOWORD(lparam), HIWORD(lparam));\r
- break;\r
-\r
- // Wheel\r
- case WM_MOUSEWHEEL:\r
- mstsc_mousewheel(This, (SHORT)HIWORD(wparam), lparam);\r
- break;\r
-\r
- default:\r
- /* Registered messages */\r
- // Z-Mouse wheel support - you know, just in case\r
- if(uMsg == wmZMouseWheel)\r
- {\r
- mstsc_mousewheel(This, (int)wparam, lparam);\r
- break;\r
- }\r
-\r
- /* Unhandled messages */\r
- return DefWindowProc(hwnd, uMsg, wparam, lparam);\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-static\r
-DWORD\r
-WINAPI\r
-mstsc_ProtocolIOThread\r
-(\r
- LPVOID lpArgument\r
-)\r
-{\r
- RDPCLIENT * This = static_cast<RDPCLIENT *>(lpArgument);\r
-\r
- WCHAR hostname[MAX_COMPUTERNAME_LENGTH + 1];\r
- DWORD dw = ARRAYSIZE(hostname);\r
- GetComputerNameW(hostname, &dw);\r
-\r
- uint32 flags = RDP_LOGON_NORMAL | RDP_LOGON_COMPRESSION | RDP_LOGON_COMPRESSION2;\r
-\r
- rdp_connect(This, "10.0.0.3", flags, L"Administrator", L"", L"", L"", L"", hostname, "");\r
- //rdp_connect(This, "192.168.7.232", flags, "", "", "", "");\r
-\r
- hdcBuffer = CreateCompatibleDC(NULL);\r
-\r
- BITMAPINFO bmi;\r
- bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);\r
- bmi.bmiHeader.biWidth = This->width;\r
- bmi.bmiHeader.biHeight = This->height;\r
- bmi.bmiHeader.biPlanes = 1;\r
- bmi.bmiHeader.biBitCount = This->server_depth;\r
- bmi.bmiHeader.biCompression = BI_RGB;\r
- bmi.bmiHeader.biSizeImage = 0;\r
- bmi.bmiHeader.biXPelsPerMeter = 0;\r
- bmi.bmiHeader.biYPelsPerMeter = 0;\r
- bmi.bmiHeader.biClrUsed = 0; // TODO! palette displays\r
- bmi.bmiHeader.biClrImportant = 0; // TODO! palette displays\r
-\r
- hbmBuffer = CreateDIBSection(hdcBuffer, &bmi, DIB_RGB_COLORS, &pBuffer, NULL, 0);\r
-\r
- SelectObject(hdcBuffer, hbmBuffer);\r
-\r
-#if 0\r
- rcClip.left = 0;\r
- rcClip.top = 0;\r
- rcClip.right = This->width + 1;\r
- rcClip.bottom = This->height + 1;\r
-#endif\r
-\r
- BOOL deactivated;\r
- uint32 ext_disc_reason;\r
-\r
- rdp_main_loop(This, &deactivated, &ext_disc_reason);\r
- // TODO: handle redirection\r
- // EVENT: OnDisconnect\r
-\r
- SendMessage(hwnd, WM_CLOSE, 0, 0);\r
-\r
- return 0;\r
-}\r
-\r
-/* Virtual channel stuff */\r
-extern "C" void channel_process(RDPCLIENT * This, STREAM s, uint16 mcs_channel)\r
-{\r
-}\r
-\r
-DWORD tlsIndex;\r
-\r
-typedef struct CHANNEL_HANDLE_\r
-{\r
- RDPCLIENT * client;\r
- int channel;\r
-}\r
-CHANNEL_HANDLE;\r
-\r
-static\r
-UINT\r
-VCAPITYPE\r
-VirtualChannelInit\r
-(\r
- LPVOID * ppInitHandle,\r
- PCHANNEL_DEF pChannel,\r
- INT channelCount,\r
- ULONG versionRequested,\r
- PCHANNEL_INIT_EVENT_FN pChannelInitEventProc\r
-)\r
-{\r
- if(channelCount <= 0)\r
- return CHANNEL_RC_BAD_CHANNEL;\r
-\r
- if(ppInitHandle == NULL)\r
- return CHANNEL_RC_BAD_INIT_HANDLE;\r
-\r
- if(pChannel == NULL)\r
- return CHANNEL_RC_BAD_CHANNEL;\r
-\r
- if(pChannelInitEventProc == NULL)\r
- return CHANNEL_RC_BAD_PROC;\r
-\r
- RDPCLIENT * This = (RDPCLIENT *)TlsGetValue(tlsIndex);\r
-\r
- if(This == NULL)\r
- return CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY;\r
-\r
- if(This->num_channels + channelCount > CHANNEL_MAX_COUNT)\r
- return CHANNEL_RC_TOO_MANY_CHANNELS;\r
-\r
- for(INT i = 0; i < channelCount; ++ i)\r
- {\r
- if(strlen(pChannel[i].name) > CHANNEL_NAME_LEN)\r
- return CHANNEL_RC_BAD_CHANNEL;\r
- }\r
-\r
- memcpy(This->channel_defs + This->num_channels, pChannel, sizeof(*pChannel) * channelCount);\r
-\r
-#if 0 // TODO\r
- for(INT i = 0; i < channelCount; ++ i)\r
- {\r
- pChannel[i].options |= CHANNEL_OPTION_INITIALIZED;\r
-\r
- int j = This->num_channels + i;\r
- This->channel_data[j].opened = 0;\r
- This->channel_data[j].pChannelInitEventProc = pChannelInitEventProc;\r
- This->channel_data[j].pChannelOpenEventProc = NULL;\r
- }\r
-#endif\r
-\r
- This->num_channels += channelCount;\r
-\r
- *ppInitHandle = This;\r
-\r
- return CHANNEL_RC_OK;\r
-}\r
-\r
-UINT\r
-VCAPITYPE\r
-VirtualChannelOpen\r
-(\r
- LPVOID pInitHandle,\r
- LPDWORD pOpenHandle,\r
- PCHAR pChannelName,\r
- PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc\r
-)\r
-{\r
- if(pInitHandle == NULL)\r
- return CHANNEL_RC_BAD_INIT_HANDLE;\r
-\r
- if(pOpenHandle == NULL)\r
- return CHANNEL_RC_BAD_CHANNEL_HANDLE;\r
-\r
- if(pChannelName == NULL)\r
- return CHANNEL_RC_UNKNOWN_CHANNEL_NAME;\r
-\r
- if(pChannelOpenEventProc == NULL)\r
- return CHANNEL_RC_BAD_PROC;\r
-\r
- RDPCLIENT * This = (RDPCLIENT *)pInitHandle;\r
-\r
-#if 0 // TODO\r
- for(unsigned i = 0; i < This->num_channels; ++ i)\r
- {\r
- if(strcmp(pChannelName, This->channel_defs[i].name) == 0)\r
- {\r
- if(This->channel_data[i].opened)\r
- return CHANNEL_RC_ALREADY_OPEN;\r
-\r
- This->channel_data[i].opened = 1;\r
- This->channel_data[i].pChannelOpenEventProc = pChannelOpenEventProc;\r
-\r
- // TODO: allocate a handle here\r
- *pOpenHandle = 0;\r
-\r
- break;\r
- }\r
- }\r
-#endif\r
-\r
- return CHANNEL_RC_OK;\r
-}\r
-\r
-UINT VCAPITYPE VirtualChannelClose\r
-(\r
- DWORD openHandle\r
-)\r
-{\r
- // TODO: channel handle management\r
- return CHANNEL_RC_BAD_CHANNEL_HANDLE;\r
-}\r
-\r
-UINT VCAPITYPE VirtualChannelWrite\r
-(\r
- DWORD openHandle,\r
- LPVOID pData,\r
- ULONG dataLength,\r
- LPVOID pUserData\r
-)\r
-{\r
- // TODO\r
- return CHANNEL_RC_BAD_CHANNEL_HANDLE;\r
-}\r
-\r
-int wmain()\r
-{\r
- WSADATA wsd;\r
- WSAStartup(MAKEWORD(2, 2), &wsd);\r
-\r
- static RDPCLIENT This_; // NOTE: this is HUGE and would overflow the stack!\r
- ZeroMemory(&This_, sizeof(This_));\r
-\r
- RDPCLIENT * This = &This_;\r
-\r
- /*\r
- Threading model for MissTosca:\r
- - main thread is the GUI thread. Message loop maintained by caller\r
- - protocol I/O is handled in an I/O thread (or thread pool)\r
- - extra threads maintained by virtual channel handlers. Virtual channel writes are thread-neutral\r
-\r
- How we handle drawing: at the moment just an off-screen buffer we dump on-screen when asked to.\r
- Still considering how to draw on-screen directly and *then* buffering off-screen (for example,\r
- when running inside another remote session)\r
- */\r
-\r
- // FIXME: keyboard mess\r
- This->keylayout = 0x409;\r
- This->keyboard_type = 0x4;\r
- This->keyboard_subtype = 0x0;\r
- This->keyboard_functionkeys = 0xc;\r
- This->width = 800;\r
- This->height = 600;\r
- This->server_depth = 24;\r
- This->bitmap_compression = True;\r
- //This->sendmotion = True;\r
- This->bitmap_cache = True;\r
- This->bitmap_cache_persist_enable = False;\r
- This->bitmap_cache_precache = True;\r
- This->encryption = True;\r
- This->packet_encryption = True;\r
- This->desktop_save = True;\r
- This->polygon_ellipse_orders = False; // = True;\r
- //This->fullscreen = False;\r
- //This->grab_keyboard = True;\r
- //This->hide_decorations = False;\r
- This->use_rdp5 = True;\r
- //This->rdpclip = True;\r
- This->console_session = False;\r
- //This->numlock_sync = False;\r
- //This->seamless_rdp = False;\r
- This->rdp5_performanceflags = RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS;\r
- This->tcp_port_rdp = TCP_PORT_RDP;\r
-\r
-#define NOT_SET -1\r
- This->cache.bmpcache_lru[0] = NOT_SET;\r
- This->cache.bmpcache_lru[1] = NOT_SET;\r
- This->cache.bmpcache_lru[2] = NOT_SET;\r
- This->cache.bmpcache_mru[0] = NOT_SET;\r
- This->cache.bmpcache_mru[1] = NOT_SET;\r
- This->cache.bmpcache_mru[2] = NOT_SET;\r
-\r
- This->rdp.current_status = 1;\r
-\r
- //hcursor = NULL;\r
-\r
- WNDCLASS wc;\r
- ZeroMemory(&wc, sizeof(wc));\r
-\r
- wc.lpfnWndProc = mstsc_WndProc;\r
- wc.hbrBackground = static_cast<HBRUSH>(GetStockObject(HOLLOW_BRUSH));\r
- wc.lpszClassName = TEXT("MissTosca_Desktop");\r
-\r
- wmZMouseWheel = RegisterWindowMessage(MSH_MOUSEWHEEL);\r
-\r
- ATOM a = RegisterClass(&wc);\r
-\r
- hwnd = CreateWindow\r
- (\r
- MAKEINTATOM(a),\r
- NULL,\r
- WS_POPUP | WS_VISIBLE,\r
- CW_USEDEFAULT,\r
- CW_USEDEFAULT,\r
- This->width,\r
- This->height,\r
- NULL,\r
- NULL,\r
- NULL,\r
- This\r
- );\r
-\r
- // The righ time to start the protocol thread\r
- DWORD dwThreadId;\r
- HANDLE hThread = CreateThread(NULL, 0, mstsc_ProtocolIOThread, This, 0, &dwThreadId);\r
-\r
- // Your standard, garden variety message loop\r
- MSG msg;\r
-\r
- while(GetMessage(&msg, NULL, 0, 0))\r
- {\r
- TranslateMessage(&msg);\r
- DispatchMessage(&msg);\r
- }\r
-}\r
-\r
-// EOF\r
+#include "stdafx.h"
+
+#include <zmouse.h>
+
+#include "rdesktop/rdesktop.h"
+#include "rdesktop/proto.h"
+
+extern "C"
+{
+ /* ==== BEGIN POOP ==== */
+ // Temporary implementations of stuff we totally positively need to make the Real Thing happy
+ /* produce a hex dump */
+ void
+ hexdump(unsigned char *p, unsigned int len)
+ {
+ unsigned char *line = p;
+ int i, thisline;
+ unsigned int offset = 0;
+
+ while (offset < len)
+ {
+ printf("%04x ", offset);
+ thisline = len - offset;
+ if (thisline > 16)
+ thisline = 16;
+
+ for (i = 0; i < thisline; i++)
+ printf("%02x ", line[i]);
+
+ for (; i < 16; i++)
+ printf(" ");
+
+ for (i = 0; i < thisline; i++)
+ printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
+
+ printf("\n");
+ offset += thisline;
+ line += thisline;
+ }
+ }
+
+ void generate_random(uint8 * random)
+ {
+ memcpy(random, "12345678901234567890123456789012", 32);
+ }
+
+ /* report an error */
+ void
+ error(char *format, ...)
+ {
+ va_list ap;
+
+ fprintf(stderr, "ERROR: ");
+
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ }
+
+ /* report a warning */
+ void
+ warning(char *format, ...)
+ {
+ va_list ap;
+
+ fprintf(stderr, "WARNING: ");
+
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ }
+
+ /* report an unimplemented protocol feature */
+ void
+ unimpl(char *format, ...)
+ {
+ va_list ap;
+
+ fprintf(stderr, "NOT IMPLEMENTED: ");
+
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ }
+
+ /* Create the bitmap cache directory */
+ BOOL
+ rd_pstcache_mkdir(void)
+ {
+ char *home;
+ char bmpcache_dir[256];
+
+ home = getenv("HOME");
+
+ if (home == NULL)
+ return False;
+
+ sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop");
+
+ if ((_mkdir(bmpcache_dir) == -1) && errno != EEXIST)
+ {
+ perror(bmpcache_dir);
+ return False;
+ }
+
+ sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop/cache");
+
+ if ((_mkdir(bmpcache_dir) == -1) && errno != EEXIST)
+ {
+ perror(bmpcache_dir);
+ return False;
+ }
+
+ return True;
+ }
+
+ /* open a file in the .rdesktop directory */
+ int
+ rd_open_file(char *filename)
+ {
+ char *home;
+ char fn[256];
+ int fd;
+
+ home = getenv("HOME");
+ if (home == NULL)
+ return -1;
+ sprintf(fn, "%s/.rdesktop/%s", home, filename);
+ fd = _open(fn, _O_RDWR | _O_CREAT, 0);
+ if (fd == -1)
+ perror(fn);
+ return fd;
+ }
+
+ /* close file */
+ void
+ rd_close_file(int fd)
+ {
+ _close(fd);
+ }
+
+ /* read from file*/
+ int
+ rd_read_file(int fd, void *ptr, int len)
+ {
+ return _read(fd, ptr, len);
+ }
+
+ /* write to file */
+ int
+ rd_write_file(int fd, void *ptr, int len)
+ {
+ return _write(fd, ptr, len);
+ }
+
+ /* move file pointer */
+ int
+ rd_lseek_file(int fd, int offset)
+ {
+ return _lseek(fd, offset, SEEK_SET);
+ }
+
+ /* do a write lock on a file */
+ BOOL
+ rd_lock_file(int fd, int start, int len)
+ {
+ // TODOOO...
+ return False;
+ }
+
+ int
+ load_licence(RDPCLIENT * This, unsigned char **data)
+ {
+ return -1;
+ }
+
+ void
+ save_licence(RDPCLIENT * This, unsigned char *data, int length)
+ {
+ }
+
+ /* ==== END POOP ==== */
+
+ /* ==== UI ==== */
+ // Globals are totally teh evil, but cut me some slack here
+ HWND hwnd;
+ HBITMAP hbmBuffer;
+ PVOID pBuffer;
+ HDC hdcBuffer;
+ UINT wmZMouseWheel;
+
+};
+
+static
+void
+mstsc_mousewheel(RDPCLIENT * This, int value, LPARAM lparam)
+{
+ uint16 button;
+
+ if(value < 0)
+ button = MOUSE_FLAG_BUTTON5;
+ else
+ button = MOUSE_FLAG_BUTTON4;
+
+ if(value < 0)
+ value = - value;
+
+ for(int click = 0; click < value; click += WHEEL_DELTA)
+ rdp_send_input(This, GetTickCount(), RDP_INPUT_MOUSE, button | MOUSE_FLAG_DOWN, LOWORD(lparam), HIWORD(lparam));
+}
+
+static
+LRESULT
+CALLBACK
+mstsc_WndProc(HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lparam)
+{
+ // BUGBUG: LongToPtr & PtrToLong will break on Win64
+
+ RDPCLIENT * This = reinterpret_cast<RDPCLIENT *>(LongToPtr(GetWindowLongPtr(hwnd, GWLP_USERDATA)));
+
+ switch(uMsg)
+ {
+ case WM_CLOSE:
+ DestroyWindow(hwnd);
+ break;
+
+ // FIXME: temporary
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+
+ /* Initialization */
+ case WM_CREATE:
+ This = static_cast<RDPCLIENT *>(reinterpret_cast<LPCREATESTRUCT>(lparam)->lpCreateParams);
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, PtrToLong(This));
+ break;
+
+ /* Painting */
+ case WM_PRINTCLIENT:
+ if(wparam == 0)
+ break;
+
+ case WM_PAINT:
+ {
+ HDC hdc = (HDC)wparam;
+
+ // A DC was provided: print the whole client area into it
+ if(hdc)
+ {
+ RECT rc;
+ GetClientRect(hwnd, &rc);
+ BitBlt(hdc, 0, 0, rc.right, rc.bottom, hdcBuffer, 0, 0, SRCCOPY);
+ }
+ // Otherwise, we're refreshing to screen
+ else
+ {
+ PAINTSTRUCT ps;
+ hdc = BeginPaint(hwnd, &ps);
+
+ BitBlt
+ (
+ hdc,
+ ps.rcPaint.left,
+ ps.rcPaint.top,
+ ps.rcPaint.right - ps.rcPaint.left,
+ ps.rcPaint.bottom - ps.rcPaint.top,
+ hdcBuffer,
+ ps.rcPaint.left,
+ ps.rcPaint.top,
+ SRCCOPY
+ );
+
+ EndPaint(hwnd, &ps);
+ }
+ }
+
+ break;
+
+ /* Keyboard stuff */
+ case WM_SYSKEYDOWN:
+ case WM_KEYDOWN:
+ rdp_send_input(This, GetMessageTime(), RDP_INPUT_SCANCODE, RDP_KEYPRESS | (lparam & 0x1000000 ? KBD_FLAG_EXT : 0), LOBYTE(HIWORD(lparam)), 0);
+ break;
+
+ case WM_SYSKEYUP:
+ case WM_KEYUP:
+ rdp_send_input(This, GetMessageTime(), RDP_INPUT_SCANCODE, RDP_KEYRELEASE | (lparam & 0x1000000 ? KBD_FLAG_EXT : 0), LOBYTE(HIWORD(lparam)), 0);
+ break;
+
+ /* Mouse stuff */
+ // Cursor shape
+ case WM_SETCURSOR:
+ if(LOWORD(lparam) == HTCLIENT)
+ {
+ //SetCursor(hcursor);
+ return TRUE;
+ }
+
+ break;
+
+ // Movement
+ case WM_MOUSEMOVE:
+ //if(This->sendmotion || wparam & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON | MK_XBUTTON1 | MK_XBUTTON2))
+ rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, LOWORD(lparam), HIWORD(lparam));
+
+ break;
+
+ // Buttons
+ // TODO: X buttons
+ case WM_LBUTTONDOWN:
+ rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1 | MOUSE_FLAG_DOWN, LOWORD(lparam), HIWORD(lparam));
+ break;
+
+ case WM_RBUTTONDOWN:
+ rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2 | MOUSE_FLAG_DOWN, LOWORD(lparam), HIWORD(lparam));
+ break;
+
+ case WM_MBUTTONDOWN:
+ rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON3 | MOUSE_FLAG_DOWN, LOWORD(lparam), HIWORD(lparam));
+ break;
+
+ case WM_LBUTTONUP:
+ rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, LOWORD(lparam), HIWORD(lparam));
+ break;
+
+ case WM_RBUTTONUP:
+ rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2, LOWORD(lparam), HIWORD(lparam));
+ break;
+
+ case WM_MBUTTONUP:
+ rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON3, LOWORD(lparam), HIWORD(lparam));
+ break;
+
+ // Wheel
+ case WM_MOUSEWHEEL:
+ mstsc_mousewheel(This, (SHORT)HIWORD(wparam), lparam);
+ break;
+
+ default:
+ /* Registered messages */
+ // Z-Mouse wheel support - you know, just in case
+ if(uMsg == wmZMouseWheel)
+ {
+ mstsc_mousewheel(This, (int)wparam, lparam);
+ break;
+ }
+
+ /* Unhandled messages */
+ return DefWindowProc(hwnd, uMsg, wparam, lparam);
+ }
+
+ return 0;
+}
+
+static
+DWORD
+WINAPI
+mstsc_ProtocolIOThread
+(
+ LPVOID lpArgument
+)
+{
+ RDPCLIENT * This = static_cast<RDPCLIENT *>(lpArgument);
+
+ WCHAR hostname[MAX_COMPUTERNAME_LENGTH + 1];
+ DWORD dw = ARRAYSIZE(hostname);
+ GetComputerNameW(hostname, &dw);
+
+ uint32 flags = RDP_LOGON_NORMAL | RDP_LOGON_COMPRESSION | RDP_LOGON_COMPRESSION2;
+
+ rdp_connect(This, "10.0.0.3", flags, L"Administrator", L"", L"", L"", L"", hostname, "");
+ //rdp_connect(This, "192.168.7.232", flags, "", "", "", "");
+
+ hdcBuffer = CreateCompatibleDC(NULL);
+
+ BITMAPINFO bmi;
+ bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
+ bmi.bmiHeader.biWidth = This->width;
+ bmi.bmiHeader.biHeight = This->height;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = This->server_depth;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = 0;
+ bmi.bmiHeader.biXPelsPerMeter = 0;
+ bmi.bmiHeader.biYPelsPerMeter = 0;
+ bmi.bmiHeader.biClrUsed = 0; // TODO! palette displays
+ bmi.bmiHeader.biClrImportant = 0; // TODO! palette displays
+
+ hbmBuffer = CreateDIBSection(hdcBuffer, &bmi, DIB_RGB_COLORS, &pBuffer, NULL, 0);
+
+ SelectObject(hdcBuffer, hbmBuffer);
+
+#if 0
+ rcClip.left = 0;
+ rcClip.top = 0;
+ rcClip.right = This->width + 1;
+ rcClip.bottom = This->height + 1;
+#endif
+
+ BOOL deactivated;
+ uint32 ext_disc_reason;
+
+ rdp_main_loop(This, &deactivated, &ext_disc_reason);
+ // TODO: handle redirection
+ // EVENT: OnDisconnect
+
+ SendMessage(hwnd, WM_CLOSE, 0, 0);
+
+ return 0;
+}
+
+/* Virtual channel stuff */
+extern "C" void channel_process(RDPCLIENT * This, STREAM s, uint16 mcs_channel)
+{
+}
+
+DWORD tlsIndex;
+
+typedef struct CHANNEL_HANDLE_
+{
+ RDPCLIENT * client;
+ int channel;
+}
+CHANNEL_HANDLE;
+
+static
+UINT
+VCAPITYPE
+VirtualChannelInit
+(
+ LPVOID * ppInitHandle,
+ PCHANNEL_DEF pChannel,
+ INT channelCount,
+ ULONG versionRequested,
+ PCHANNEL_INIT_EVENT_FN pChannelInitEventProc
+)
+{
+ if(channelCount <= 0)
+ return CHANNEL_RC_BAD_CHANNEL;
+
+ if(ppInitHandle == NULL)
+ return CHANNEL_RC_BAD_INIT_HANDLE;
+
+ if(pChannel == NULL)
+ return CHANNEL_RC_BAD_CHANNEL;
+
+ if(pChannelInitEventProc == NULL)
+ return CHANNEL_RC_BAD_PROC;
+
+ RDPCLIENT * This = (RDPCLIENT *)TlsGetValue(tlsIndex);
+
+ if(This == NULL)
+ return CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY;
+
+ if(This->num_channels + channelCount > CHANNEL_MAX_COUNT)
+ return CHANNEL_RC_TOO_MANY_CHANNELS;
+
+ for(INT i = 0; i < channelCount; ++ i)
+ {
+ if(strlen(pChannel[i].name) > CHANNEL_NAME_LEN)
+ return CHANNEL_RC_BAD_CHANNEL;
+ }
+
+ memcpy(This->channel_defs + This->num_channels, pChannel, sizeof(*pChannel) * channelCount);
+
+#if 0 // TODO
+ for(INT i = 0; i < channelCount; ++ i)
+ {
+ pChannel[i].options |= CHANNEL_OPTION_INITIALIZED;
+
+ int j = This->num_channels + i;
+ This->channel_data[j].opened = 0;
+ This->channel_data[j].pChannelInitEventProc = pChannelInitEventProc;
+ This->channel_data[j].pChannelOpenEventProc = NULL;
+ }
+#endif
+
+ This->num_channels += channelCount;
+
+ *ppInitHandle = This;
+
+ return CHANNEL_RC_OK;
+}
+
+UINT
+VCAPITYPE
+VirtualChannelOpen
+(
+ LPVOID pInitHandle,
+ LPDWORD pOpenHandle,
+ PCHAR pChannelName,
+ PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc
+)
+{
+ if(pInitHandle == NULL)
+ return CHANNEL_RC_BAD_INIT_HANDLE;
+
+ if(pOpenHandle == NULL)
+ return CHANNEL_RC_BAD_CHANNEL_HANDLE;
+
+ if(pChannelName == NULL)
+ return CHANNEL_RC_UNKNOWN_CHANNEL_NAME;
+
+ if(pChannelOpenEventProc == NULL)
+ return CHANNEL_RC_BAD_PROC;
+
+ RDPCLIENT * This = (RDPCLIENT *)pInitHandle;
+
+#if 0 // TODO
+ for(unsigned i = 0; i < This->num_channels; ++ i)
+ {
+ if(strcmp(pChannelName, This->channel_defs[i].name) == 0)
+ {
+ if(This->channel_data[i].opened)
+ return CHANNEL_RC_ALREADY_OPEN;
+
+ This->channel_data[i].opened = 1;
+ This->channel_data[i].pChannelOpenEventProc = pChannelOpenEventProc;
+
+ // TODO: allocate a handle here
+ *pOpenHandle = 0;
+
+ break;
+ }
+ }
+#endif
+
+ return CHANNEL_RC_OK;
+}
+
+UINT VCAPITYPE VirtualChannelClose
+(
+ DWORD openHandle
+)
+{
+ // TODO: channel handle management
+ return CHANNEL_RC_BAD_CHANNEL_HANDLE;
+}
+
+UINT VCAPITYPE VirtualChannelWrite
+(
+ DWORD openHandle,
+ LPVOID pData,
+ ULONG dataLength,
+ LPVOID pUserData
+)
+{
+ // TODO
+ return CHANNEL_RC_BAD_CHANNEL_HANDLE;
+}
+
+int wmain()
+{
+ WSADATA wsd;
+ WSAStartup(MAKEWORD(2, 2), &wsd);
+
+ static RDPCLIENT This_; // NOTE: this is HUGE and would overflow the stack!
+ ZeroMemory(&This_, sizeof(This_));
+
+ RDPCLIENT * This = &This_;
+
+ /*
+ Threading model for MissTosca:
+ - main thread is the GUI thread. Message loop maintained by caller
+ - protocol I/O is handled in an I/O thread (or thread pool)
+ - extra threads maintained by virtual channel handlers. Virtual channel writes are thread-neutral
+
+ How we handle drawing: at the moment just an off-screen buffer we dump on-screen when asked to.
+ Still considering how to draw on-screen directly and *then* buffering off-screen (for example,
+ when running inside another remote session)
+ */
+
+ // FIXME: keyboard mess
+ This->keylayout = 0x409;
+ This->keyboard_type = 0x4;
+ This->keyboard_subtype = 0x0;
+ This->keyboard_functionkeys = 0xc;
+ This->width = 800;
+ This->height = 600;
+ This->server_depth = 24;
+ This->bitmap_compression = True;
+ //This->sendmotion = True;
+ This->bitmap_cache = True;
+ This->bitmap_cache_persist_enable = False;
+ This->bitmap_cache_precache = True;
+ This->encryption = True;
+ This->packet_encryption = True;
+ This->desktop_save = True;
+ This->polygon_ellipse_orders = False; // = True;
+ //This->fullscreen = False;
+ //This->grab_keyboard = True;
+ //This->hide_decorations = False;
+ This->use_rdp5 = True;
+ //This->rdpclip = True;
+ This->console_session = False;
+ //This->numlock_sync = False;
+ //This->seamless_rdp = False;
+ This->rdp5_performanceflags = RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS;
+ This->tcp_port_rdp = TCP_PORT_RDP;
+
+#define NOT_SET -1
+ This->cache.bmpcache_lru[0] = NOT_SET;
+ This->cache.bmpcache_lru[1] = NOT_SET;
+ This->cache.bmpcache_lru[2] = NOT_SET;
+ This->cache.bmpcache_mru[0] = NOT_SET;
+ This->cache.bmpcache_mru[1] = NOT_SET;
+ This->cache.bmpcache_mru[2] = NOT_SET;
+
+ This->rdp.current_status = 1;
+
+ //hcursor = NULL;
+
+ WNDCLASS wc;
+ ZeroMemory(&wc, sizeof(wc));
+
+ wc.lpfnWndProc = mstsc_WndProc;
+ wc.hbrBackground = static_cast<HBRUSH>(GetStockObject(HOLLOW_BRUSH));
+ wc.lpszClassName = TEXT("MissTosca_Desktop");
+
+ wmZMouseWheel = RegisterWindowMessage(MSH_MOUSEWHEEL);
+
+ ATOM a = RegisterClass(&wc);
+
+ hwnd = CreateWindow
+ (
+ MAKEINTATOM(a),
+ NULL,
+ WS_POPUP | WS_VISIBLE,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ This->width,
+ This->height,
+ NULL,
+ NULL,
+ NULL,
+ This
+ );
+
+ // The righ time to start the protocol thread
+ DWORD dwThreadId;
+ HANDLE hThread = CreateThread(NULL, 0, mstsc_ProtocolIOThread, This, 0, &dwThreadId);
+
+ // Your standard, garden variety message loop
+ MSG msg;
+
+ while(GetMessage(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+}
+
+// EOF