5 #include "rdesktop/rdesktop.h"
6 #include "rdesktop/proto.h"
10 /* ==== BEGIN POOP ==== */
11 // Temporary implementations of stuff we totally positively need to make the Real Thing happy
12 /* produce a hex dump */
14 hexdump(unsigned char *p
, unsigned int len
)
16 unsigned char *line
= p
;
18 unsigned int offset
= 0;
22 printf("%04x ", offset
);
23 thisline
= len
- offset
;
27 for (i
= 0; i
< thisline
; i
++)
28 printf("%02x ", line
[i
]);
33 for (i
= 0; i
< thisline
; i
++)
34 printf("%c", (line
[i
] >= 0x20 && line
[i
] < 0x7f) ? line
[i
] : '.');
42 void generate_random(uint8
* random
)
44 memcpy(random
, "12345678901234567890123456789012", 32);
49 error(char *format
, ...)
53 fprintf(stderr
, "ERROR: ");
56 vfprintf(stderr
, format
, ap
);
60 /* report a warning */
62 warning(char *format
, ...)
66 fprintf(stderr
, "WARNING: ");
69 vfprintf(stderr
, format
, ap
);
73 /* report an unimplemented protocol feature */
75 unimpl(char *format
, ...)
79 fprintf(stderr
, "NOT IMPLEMENTED: ");
82 vfprintf(stderr
, format
, ap
);
86 /* Create the bitmap cache directory */
88 rd_pstcache_mkdir(void)
91 char bmpcache_dir
[256];
93 home
= getenv("HOME");
98 sprintf(bmpcache_dir
, "%s/%s", home
, ".rdesktop");
100 if ((_mkdir(bmpcache_dir
) == -1) && errno
!= EEXIST
)
102 perror(bmpcache_dir
);
106 sprintf(bmpcache_dir
, "%s/%s", home
, ".rdesktop/cache");
108 if ((_mkdir(bmpcache_dir
) == -1) && errno
!= EEXIST
)
110 perror(bmpcache_dir
);
117 /* open a file in the .rdesktop directory */
119 rd_open_file(char *filename
)
125 home
= getenv("HOME");
128 sprintf(fn
, "%s/.rdesktop/%s", home
, filename
);
129 fd
= _open(fn
, _O_RDWR
| _O_CREAT
, 0);
137 rd_close_file(int fd
)
144 rd_read_file(int fd
, void *ptr
, int len
)
146 return _read(fd
, ptr
, len
);
151 rd_write_file(int fd
, void *ptr
, int len
)
153 return _write(fd
, ptr
, len
);
156 /* move file pointer */
158 rd_lseek_file(int fd
, int offset
)
160 return _lseek(fd
, offset
, SEEK_SET
);
163 /* do a write lock on a file */
165 rd_lock_file(int fd
, int start
, int len
)
172 load_licence(RDPCLIENT
* This
, unsigned char **data
)
178 save_licence(RDPCLIENT
* This
, unsigned char *data
, int length
)
182 /* ==== END POOP ==== */
185 // Globals are totally teh evil, but cut me some slack here
196 mstsc_mousewheel(RDPCLIENT
* This
, int value
, LPARAM lparam
)
201 button
= MOUSE_FLAG_BUTTON5
;
203 button
= MOUSE_FLAG_BUTTON4
;
208 for(int click
= 0; click
< value
; click
+= WHEEL_DELTA
)
209 rdp_send_input(This
, GetTickCount(), RDP_INPUT_MOUSE
, button
| MOUSE_FLAG_DOWN
, LOWORD(lparam
), HIWORD(lparam
));
215 mstsc_WndProc(HWND hwnd
, UINT uMsg
, WPARAM wparam
, LPARAM lparam
)
217 // BUGBUG: LongToPtr & PtrToLong will break on Win64
219 RDPCLIENT
* This
= reinterpret_cast<RDPCLIENT
*>(LongToPtr(GetWindowLongPtr(hwnd
, GWLP_USERDATA
)));
234 This
= static_cast<RDPCLIENT
*>(reinterpret_cast<LPCREATESTRUCT
>(lparam
)->lpCreateParams
);
235 SetWindowLongPtr(hwnd
, GWLP_USERDATA
, PtrToLong(This
));
245 HDC hdc
= (HDC
)wparam
;
247 // A DC was provided: print the whole client area into it
251 GetClientRect(hwnd
, &rc
);
252 BitBlt(hdc
, 0, 0, rc
.right
, rc
.bottom
, hdcBuffer
, 0, 0, SRCCOPY
);
254 // Otherwise, we're refreshing to screen
258 hdc
= BeginPaint(hwnd
, &ps
);
265 ps
.rcPaint
.right
- ps
.rcPaint
.left
,
266 ps
.rcPaint
.bottom
- ps
.rcPaint
.top
,
282 rdp_send_input(This
, GetMessageTime(), RDP_INPUT_SCANCODE
, RDP_KEYPRESS
| (lparam
& 0x1000000 ? KBD_FLAG_EXT
: 0), LOBYTE(HIWORD(lparam
)), 0);
287 rdp_send_input(This
, GetMessageTime(), RDP_INPUT_SCANCODE
, RDP_KEYRELEASE
| (lparam
& 0x1000000 ? KBD_FLAG_EXT
: 0), LOBYTE(HIWORD(lparam
)), 0);
293 if(LOWORD(lparam
) == HTCLIENT
)
295 //SetCursor(hcursor);
303 //if(This->sendmotion || wparam & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON | MK_XBUTTON1 | MK_XBUTTON2))
304 rdp_send_input(This
, GetMessageTime(), RDP_INPUT_MOUSE
, MOUSE_FLAG_MOVE
, LOWORD(lparam
), HIWORD(lparam
));
311 rdp_send_input(This
, GetMessageTime(), RDP_INPUT_MOUSE
, MOUSE_FLAG_BUTTON1
| MOUSE_FLAG_DOWN
, LOWORD(lparam
), HIWORD(lparam
));
315 rdp_send_input(This
, GetMessageTime(), RDP_INPUT_MOUSE
, MOUSE_FLAG_BUTTON2
| MOUSE_FLAG_DOWN
, LOWORD(lparam
), HIWORD(lparam
));
319 rdp_send_input(This
, GetMessageTime(), RDP_INPUT_MOUSE
, MOUSE_FLAG_BUTTON3
| MOUSE_FLAG_DOWN
, LOWORD(lparam
), HIWORD(lparam
));
323 rdp_send_input(This
, GetMessageTime(), RDP_INPUT_MOUSE
, MOUSE_FLAG_BUTTON1
, LOWORD(lparam
), HIWORD(lparam
));
327 rdp_send_input(This
, GetMessageTime(), RDP_INPUT_MOUSE
, MOUSE_FLAG_BUTTON2
, LOWORD(lparam
), HIWORD(lparam
));
331 rdp_send_input(This
, GetMessageTime(), RDP_INPUT_MOUSE
, MOUSE_FLAG_BUTTON3
, LOWORD(lparam
), HIWORD(lparam
));
336 mstsc_mousewheel(This
, (SHORT
)HIWORD(wparam
), lparam
);
340 /* Registered messages */
341 // Z-Mouse wheel support - you know, just in case
342 if(uMsg
== wmZMouseWheel
)
344 mstsc_mousewheel(This
, (int)wparam
, lparam
);
348 /* Unhandled messages */
349 return DefWindowProc(hwnd
, uMsg
, wparam
, lparam
);
358 mstsc_ProtocolIOThread
363 RDPCLIENT
* This
= static_cast<RDPCLIENT
*>(lpArgument
);
365 WCHAR hostname
[MAX_COMPUTERNAME_LENGTH
+ 1];
366 DWORD dw
= ARRAYSIZE(hostname
);
367 GetComputerNameW(hostname
, &dw
);
369 uint32 flags
= RDP_LOGON_NORMAL
| RDP_LOGON_COMPRESSION
| RDP_LOGON_COMPRESSION2
;
371 rdp_connect(This
, "10.0.0.3", flags
, L
"Administrator", L
"", L
"", L
"", L
"", hostname
, "");
372 //rdp_connect(This, "192.168.7.232", flags, "", "", "", "");
374 hdcBuffer
= CreateCompatibleDC(NULL
);
377 bmi
.bmiHeader
.biSize
= sizeof(bmi
.bmiHeader
);
378 bmi
.bmiHeader
.biWidth
= This
->width
;
379 bmi
.bmiHeader
.biHeight
= This
->height
;
380 bmi
.bmiHeader
.biPlanes
= 1;
381 bmi
.bmiHeader
.biBitCount
= This
->server_depth
;
382 bmi
.bmiHeader
.biCompression
= BI_RGB
;
383 bmi
.bmiHeader
.biSizeImage
= 0;
384 bmi
.bmiHeader
.biXPelsPerMeter
= 0;
385 bmi
.bmiHeader
.biYPelsPerMeter
= 0;
386 bmi
.bmiHeader
.biClrUsed
= 0; // TODO! palette displays
387 bmi
.bmiHeader
.biClrImportant
= 0; // TODO! palette displays
389 hbmBuffer
= CreateDIBSection(hdcBuffer
, &bmi
, DIB_RGB_COLORS
, &pBuffer
, NULL
, 0);
391 SelectObject(hdcBuffer
, hbmBuffer
);
396 rcClip
.right
= This
->width
+ 1;
397 rcClip
.bottom
= This
->height
+ 1;
401 uint32 ext_disc_reason
;
403 rdp_main_loop(This
, &deactivated
, &ext_disc_reason
);
404 // TODO: handle redirection
405 // EVENT: OnDisconnect
407 SendMessage(hwnd
, WM_CLOSE
, 0, 0);
412 /* Virtual channel stuff */
413 extern "C" void channel_process(RDPCLIENT
* This
, STREAM s
, uint16 mcs_channel
)
419 typedef struct CHANNEL_HANDLE_
431 LPVOID
* ppInitHandle
,
432 PCHANNEL_DEF pChannel
,
434 ULONG versionRequested
,
435 PCHANNEL_INIT_EVENT_FN pChannelInitEventProc
438 if(channelCount
<= 0)
439 return CHANNEL_RC_BAD_CHANNEL
;
441 if(ppInitHandle
== NULL
)
442 return CHANNEL_RC_BAD_INIT_HANDLE
;
445 return CHANNEL_RC_BAD_CHANNEL
;
447 if(pChannelInitEventProc
== NULL
)
448 return CHANNEL_RC_BAD_PROC
;
450 RDPCLIENT
* This
= (RDPCLIENT
*)TlsGetValue(tlsIndex
);
453 return CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY
;
455 if(This
->num_channels
+ channelCount
> CHANNEL_MAX_COUNT
)
456 return CHANNEL_RC_TOO_MANY_CHANNELS
;
458 for(INT i
= 0; i
< channelCount
; ++ i
)
460 if(strlen(pChannel
[i
].name
) > CHANNEL_NAME_LEN
)
461 return CHANNEL_RC_BAD_CHANNEL
;
464 memcpy(This
->channel_defs
+ This
->num_channels
, pChannel
, sizeof(*pChannel
) * channelCount
);
467 for(INT i
= 0; i
< channelCount
; ++ i
)
469 pChannel
[i
].options
|= CHANNEL_OPTION_INITIALIZED
;
471 int j
= This
->num_channels
+ i
;
472 This
->channel_data
[j
].opened
= 0;
473 This
->channel_data
[j
].pChannelInitEventProc
= pChannelInitEventProc
;
474 This
->channel_data
[j
].pChannelOpenEventProc
= NULL
;
478 This
->num_channels
+= channelCount
;
480 *ppInitHandle
= This
;
482 return CHANNEL_RC_OK
;
492 PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc
495 if(pInitHandle
== NULL
)
496 return CHANNEL_RC_BAD_INIT_HANDLE
;
498 if(pOpenHandle
== NULL
)
499 return CHANNEL_RC_BAD_CHANNEL_HANDLE
;
501 if(pChannelName
== NULL
)
502 return CHANNEL_RC_UNKNOWN_CHANNEL_NAME
;
504 if(pChannelOpenEventProc
== NULL
)
505 return CHANNEL_RC_BAD_PROC
;
507 RDPCLIENT
* This
= (RDPCLIENT
*)pInitHandle
;
510 for(unsigned i
= 0; i
< This
->num_channels
; ++ i
)
512 if(strcmp(pChannelName
, This
->channel_defs
[i
].name
) == 0)
514 if(This
->channel_data
[i
].opened
)
515 return CHANNEL_RC_ALREADY_OPEN
;
517 This
->channel_data
[i
].opened
= 1;
518 This
->channel_data
[i
].pChannelOpenEventProc
= pChannelOpenEventProc
;
520 // TODO: allocate a handle here
528 return CHANNEL_RC_OK
;
531 UINT VCAPITYPE VirtualChannelClose
536 // TODO: channel handle management
537 return CHANNEL_RC_BAD_CHANNEL_HANDLE
;
540 UINT VCAPITYPE VirtualChannelWrite
549 return CHANNEL_RC_BAD_CHANNEL_HANDLE
;
555 WSAStartup(MAKEWORD(2, 2), &wsd
);
557 static RDPCLIENT This_
; // NOTE: this is HUGE and would overflow the stack!
558 ZeroMemory(&This_
, sizeof(This_
));
560 RDPCLIENT
* This
= &This_
;
563 Threading model for MissTosca:
564 - main thread is the GUI thread. Message loop maintained by caller
565 - protocol I/O is handled in an I/O thread (or thread pool)
566 - extra threads maintained by virtual channel handlers. Virtual channel writes are thread-neutral
568 How we handle drawing: at the moment just an off-screen buffer we dump on-screen when asked to.
569 Still considering how to draw on-screen directly and *then* buffering off-screen (for example,
570 when running inside another remote session)
573 // FIXME: keyboard mess
574 This
->keylayout
= 0x409;
575 This
->keyboard_type
= 0x4;
576 This
->keyboard_subtype
= 0x0;
577 This
->keyboard_functionkeys
= 0xc;
580 This
->server_depth
= 24;
581 This
->bitmap_compression
= True
;
582 //This->sendmotion = True;
583 This
->bitmap_cache
= True
;
584 This
->bitmap_cache_persist_enable
= False
;
585 This
->bitmap_cache_precache
= True
;
586 This
->encryption
= True
;
587 This
->packet_encryption
= True
;
588 This
->desktop_save
= True
;
589 This
->polygon_ellipse_orders
= False
; // = True;
590 //This->fullscreen = False;
591 //This->grab_keyboard = True;
592 //This->hide_decorations = False;
593 This
->use_rdp5
= True
;
594 //This->rdpclip = True;
595 This
->console_session
= False
;
596 //This->numlock_sync = False;
597 //This->seamless_rdp = False;
598 This
->rdp5_performanceflags
= RDP5_NO_WALLPAPER
| RDP5_NO_FULLWINDOWDRAG
| RDP5_NO_MENUANIMATIONS
;
599 This
->tcp_port_rdp
= TCP_PORT_RDP
;
602 This
->cache
.bmpcache_lru
[0] = NOT_SET
;
603 This
->cache
.bmpcache_lru
[1] = NOT_SET
;
604 This
->cache
.bmpcache_lru
[2] = NOT_SET
;
605 This
->cache
.bmpcache_mru
[0] = NOT_SET
;
606 This
->cache
.bmpcache_mru
[1] = NOT_SET
;
607 This
->cache
.bmpcache_mru
[2] = NOT_SET
;
609 This
->rdp
.current_status
= 1;
614 ZeroMemory(&wc
, sizeof(wc
));
616 wc
.lpfnWndProc
= mstsc_WndProc
;
617 wc
.hbrBackground
= static_cast<HBRUSH
>(GetStockObject(HOLLOW_BRUSH
));
618 wc
.lpszClassName
= TEXT("MissTosca_Desktop");
620 wmZMouseWheel
= RegisterWindowMessage(MSH_MOUSEWHEEL
);
622 ATOM a
= RegisterClass(&wc
);
628 WS_POPUP
| WS_VISIBLE
,
639 // The righ time to start the protocol thread
641 HANDLE hThread
= CreateThread(NULL
, 0, mstsc_ProtocolIOThread
, This
, 0, &dwThreadId
);
643 // Your standard, garden variety message loop
646 while(GetMessage(&msg
, NULL
, 0, 0))
648 TranslateMessage(&msg
);
649 DispatchMessage(&msg
);