set most of trunk svn property eol-style:native
[reactos.git] / reactos / base / applications / tsclient / porting-tools / rdesktop-core-tester / rdesktop-core-tester.cpp
index 4230475..2999276 100644 (file)
-#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