libfreerdp-core: fix code style
[platform/upstream/freerdp.git] / client / Windows / wf_client.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * Windows Client
4  *
5  * Copyright 2009-2011 Jay Sorg
6  * Copyright 2010-2011 Vic Lee
7  * Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *       http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <winpr/windows.h>
27
28 #include <winpr/crt.h>
29 #include <winpr/credui.h>
30
31 #include <errno.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <tchar.h>
36 #include <assert.h>
37 #include <sys/types.h>
38
39 #include <freerdp/log.h>
40 #include <freerdp/event.h>
41 #include <freerdp/freerdp.h>
42 #include <freerdp/constants.h>
43
44 #include <freerdp/codec/region.h>
45 #include <freerdp/client/cmdline.h>
46 #include <freerdp/client/channels.h>
47 #include <freerdp/channels/channels.h>
48
49 #include "wf_gdi.h"
50 #include "wf_rail.h"
51 #include "wf_channels.h"
52 #include "wf_graphics.h"
53 #include "wf_cliprdr.h"
54
55 #include "wf_client.h"
56
57 #include "resource.h"
58
59 #define TAG CLIENT_TAG("windows")
60
61 int wf_create_console(void)
62 {
63         if (!AllocConsole())
64                 return 1;
65
66         freopen("CONOUT$", "w", stdout);
67         freopen("CONOUT$", "w", stderr);
68         WLog_INFO(TAG,  "Debug console created.");
69         return 0;
70 }
71
72 BOOL wf_sw_begin_paint(wfContext* wfc)
73 {
74         rdpGdi* gdi = ((rdpContext*) wfc)->gdi;
75         gdi->primary->hdc->hwnd->invalid->null = 1;
76         gdi->primary->hdc->hwnd->ninvalid = 0;
77         return TRUE;
78 }
79
80 BOOL wf_sw_end_paint(wfContext* wfc)
81 {
82         int i;
83         rdpGdi* gdi;
84         int ninvalid;
85         RECT updateRect;
86         HGDI_RGN cinvalid;
87         REGION16 invalidRegion;
88         RECTANGLE_16 invalidRect;
89         const RECTANGLE_16* extents;
90         rdpContext* context = (rdpContext*) wfc;
91
92         gdi = context->gdi;
93
94         ninvalid = gdi->primary->hdc->hwnd->ninvalid;
95         cinvalid = gdi->primary->hdc->hwnd->cinvalid;
96
97         if (ninvalid < 1)
98                 return TRUE;
99
100         region16_init(&invalidRegion);
101
102         for (i = 0; i < ninvalid; i++)
103         {
104                 invalidRect.left = cinvalid[i].x;
105                 invalidRect.top = cinvalid[i].y;
106                 invalidRect.right = cinvalid[i].x + cinvalid[i].w;
107                 invalidRect.bottom = cinvalid[i].y + cinvalid[i].h;
108
109                 region16_union_rect(&invalidRegion, &invalidRegion, &invalidRect);
110         }
111
112         if (!region16_is_empty(&invalidRegion))
113         {
114                 extents = region16_extents(&invalidRegion);
115
116                 updateRect.left = extents->left;
117                 updateRect.top = extents->top;
118                 updateRect.right = extents->right;
119                 updateRect.bottom = extents->bottom;
120
121                 InvalidateRect(wfc->hwnd, &updateRect, FALSE);
122
123                 if (wfc->rail)
124                         wf_rail_invalidate_region(wfc, &invalidRegion);
125         }
126
127         region16_uninit(&invalidRegion);
128         return TRUE;
129 }
130
131 BOOL wf_sw_desktop_resize(wfContext* wfc)
132 {
133         rdpGdi* gdi;
134         rdpContext* context;
135         rdpSettings* settings;
136         freerdp* instance = wfc->instance;
137
138         context = (rdpContext*) wfc;
139         settings = wfc->instance->settings;
140         gdi = context->gdi;
141
142         wfc->width = settings->DesktopWidth;
143         wfc->height = settings->DesktopHeight;
144
145         gdi->primary->bitmap->data = NULL;
146         gdi_free(instance);
147
148         if (wfc->primary)
149         {
150                 wf_image_free(wfc->primary);
151                 wfc->primary = wf_image_new(wfc, wfc->width, wfc->height, wfc->dstBpp, NULL);
152         }
153
154         if (!gdi_init(instance, CLRCONV_ALPHA | CLRBUF_32BPP, wfc->primary->pdata))
155                 return FALSE;
156
157         gdi = instance->context->gdi;
158         wfc->hdc = gdi->primary->hdc;
159
160         return TRUE;
161 }
162
163 BOOL wf_hw_begin_paint(wfContext* wfc)
164 {
165         wfc->hdc->hwnd->invalid->null = 1;
166         wfc->hdc->hwnd->ninvalid = 0;
167         return TRUE;
168 }
169
170 BOOL wf_hw_end_paint(wfContext* wfc)
171 {
172         return TRUE;
173 }
174
175 BOOL wf_hw_desktop_resize(wfContext* wfc)
176 {
177         BOOL same;
178         RECT rect;
179         rdpSettings* settings;
180
181         settings = wfc->instance->settings;
182
183         wfc->width = settings->DesktopWidth;
184         wfc->height = settings->DesktopHeight;
185
186         if (wfc->primary)
187         {
188                 same = (wfc->primary == wfc->drawing) ? TRUE : FALSE;
189
190                 wf_image_free(wfc->primary);
191
192                 wfc->primary = wf_image_new(wfc, wfc->width, wfc->height, wfc->dstBpp, NULL);
193
194                 if (same)
195                         wfc->drawing = wfc->primary;
196         }
197
198         if (wfc->fullscreen != TRUE)
199         {
200                 if (wfc->hwnd)
201                         SetWindowPos(wfc->hwnd, HWND_TOP, -1, -1, wfc->width + wfc->diff.x, wfc->height + wfc->diff.y, SWP_NOMOVE);
202         }
203         else
204         {
205                 wf_update_offset(wfc);
206                 GetWindowRect(wfc->hwnd, &rect);
207                 InvalidateRect(wfc->hwnd, &rect, TRUE);
208         }
209         return TRUE;
210 }
211
212 BOOL wf_pre_connect(freerdp* instance)
213 {
214         wfContext* wfc;
215         int desktopWidth;
216         int desktopHeight;
217         rdpContext* context;
218         rdpSettings* settings;
219
220         context = instance->context;
221         wfc = (wfContext*) instance->context;
222         wfc->instance = instance;
223         wfc->codecs = instance->context->codecs;
224
225         settings = instance->settings;
226
227         if (settings->ConnectionFile)
228         {
229                 if (wfc->connectionRdpFile)
230                 {
231                         freerdp_client_rdp_file_free(wfc->connectionRdpFile);
232                 }
233
234                 wfc->connectionRdpFile = freerdp_client_rdp_file_new();
235                 WLog_INFO(TAG,  "Using connection file: %s", settings->ConnectionFile);
236                 freerdp_client_parse_rdp_file(wfc->connectionRdpFile, settings->ConnectionFile);
237                 freerdp_client_populate_settings_from_rdp_file(wfc->connectionRdpFile, settings);
238         }
239
240         settings->OsMajorType = OSMAJORTYPE_WINDOWS;
241         settings->OsMinorType = OSMINORTYPE_WINDOWS_NT;
242         settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
243         settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE;
244         settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
245         settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE;
246         settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE;
247         settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE;
248         settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE;
249         settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE;
250         settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE;
251         settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE;
252         settings->OrderSupport[NEG_LINETO_INDEX] = TRUE;
253         settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE;
254         settings->OrderSupport[NEG_MEMBLT_INDEX] = TRUE;
255         settings->OrderSupport[NEG_MEM3BLT_INDEX] = FALSE;
256         settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE;
257         settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = FALSE;
258         settings->OrderSupport[NEG_FAST_INDEX_INDEX] = FALSE;
259         settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = FALSE;
260         settings->OrderSupport[NEG_POLYGON_SC_INDEX] = FALSE;
261         settings->OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE;
262         settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
263         settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
264
265         settings->GlyphSupportLevel = GLYPH_SUPPORT_NONE;
266
267         wfc->fullscreen = settings->Fullscreen;
268
269         if (wfc->fullscreen)
270                 wfc->fs_toggle = 1;
271
272         wfc->clrconv = (HCLRCONV) malloc(sizeof(CLRCONV));
273         ZeroMemory(wfc->clrconv, sizeof(CLRCONV));
274
275         wfc->clrconv->palette = NULL;
276         wfc->clrconv->alpha = FALSE;
277
278         if (!(instance->context->cache = cache_new(settings)))
279                 return FALSE;
280
281         desktopWidth = settings->DesktopWidth;
282         desktopHeight = settings->DesktopHeight;
283
284         if (wfc->percentscreen > 0)
285         {
286                 desktopWidth = (GetSystemMetrics(SM_CXSCREEN) * wfc->percentscreen) / 100;
287                 settings->DesktopWidth = desktopWidth;
288
289                 desktopHeight = (GetSystemMetrics(SM_CYSCREEN) * wfc->percentscreen) / 100;
290                 settings->DesktopHeight = desktopHeight;
291         }
292
293         if (wfc->fullscreen)
294         {
295                 if (settings->UseMultimon)
296                 {
297                         desktopWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
298                         desktopHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
299                 }
300                 else
301                 {
302                         desktopWidth = GetSystemMetrics(SM_CXSCREEN);
303                         desktopHeight = GetSystemMetrics(SM_CYSCREEN);
304                 }
305         }
306
307         /* FIXME: desktopWidth has a limitation that it should be divisible by 4,
308          *        otherwise the screen will crash when connecting to an XP desktop.*/
309         desktopWidth = (desktopWidth + 3) & (~3);
310
311         if (desktopWidth != settings->DesktopWidth)
312         {
313                 freerdp_set_param_uint32(settings, FreeRDP_DesktopWidth, desktopWidth);
314         }
315
316         if (desktopHeight != settings->DesktopHeight)
317         {
318                 freerdp_set_param_uint32(settings, FreeRDP_DesktopHeight, desktopHeight);
319         }
320
321         if ((settings->DesktopWidth < 64) || (settings->DesktopHeight < 64) ||
322                 (settings->DesktopWidth > 4096) || (settings->DesktopHeight > 4096))
323         {
324                 WLog_ERR(TAG, "invalid dimensions %d %d", settings->DesktopWidth, settings->DesktopHeight);
325                 return FALSE;
326         }
327
328         freerdp_set_param_uint32(settings, FreeRDP_KeyboardLayout, (int) GetKeyboardLayout(0) & 0x0000FFFF);
329
330         PubSub_SubscribeChannelConnected(instance->context->pubSub,
331                 (pChannelConnectedEventHandler) wf_OnChannelConnectedEventHandler);
332
333         PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
334                 (pChannelDisconnectedEventHandler) wf_OnChannelDisconnectedEventHandler);
335
336         freerdp_channels_pre_connect(instance->context->channels, instance);
337
338         return TRUE;
339 }
340
341 void wf_add_system_menu(wfContext* wfc)
342 {
343         HMENU hMenu = GetSystemMenu(wfc->hwnd, FALSE);
344
345         MENUITEMINFO item_info;
346         ZeroMemory(&item_info, sizeof(MENUITEMINFO));
347
348         item_info.fMask = MIIM_CHECKMARKS | MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_DATA;
349         item_info.cbSize = sizeof(MENUITEMINFO);
350         item_info.wID = SYSCOMMAND_ID_SMARTSIZING;
351         item_info.fType = MFT_STRING;
352         item_info.dwTypeData = _wcsdup(_T("Smart sizing"));
353         item_info.cch = (UINT) _wcslen(_T("Smart sizing"));
354         item_info.dwItemData = (ULONG_PTR) wfc;
355
356         InsertMenuItem(hMenu, 6, TRUE, &item_info);
357
358         if (wfc->instance->settings->SmartSizing)
359         {
360                 CheckMenuItem(hMenu, SYSCOMMAND_ID_SMARTSIZING, MF_CHECKED);
361         }
362 }
363
364 BOOL wf_post_connect(freerdp* instance)
365 {
366         rdpGdi* gdi;
367         DWORD dwStyle;
368         rdpCache* cache;
369         wfContext* wfc;
370         rdpContext* context;
371         WCHAR lpWindowName[64];
372         rdpSettings* settings;
373         EmbedWindowEventArgs e;
374
375         settings = instance->settings;
376         context = instance->context;
377         wfc = (wfContext*) instance->context;
378         cache = instance->context->cache;
379
380         wfc->dstBpp = 32;
381         wfc->width = settings->DesktopWidth;
382         wfc->height = settings->DesktopHeight;
383
384         if (settings->SoftwareGdi)
385         {
386                 wfc->primary = wf_image_new(wfc, wfc->width, wfc->height, wfc->dstBpp, NULL);
387
388                 if (!gdi_init(instance, CLRCONV_ALPHA | CLRBUF_32BPP, wfc->primary->pdata))
389                         return FALSE;
390
391                 gdi = instance->context->gdi;
392                 wfc->hdc = gdi->primary->hdc;
393         }
394         else
395         {
396                 wf_gdi_register_update_callbacks(instance->update);
397                 wfc->srcBpp = instance->settings->ColorDepth;
398                 wfc->primary = wf_image_new(wfc, wfc->width, wfc->height, wfc->dstBpp, NULL);
399
400                 if (!(wfc->hdc = gdi_GetDC()))
401                         return FALSE;
402
403                 wfc->hdc->bitsPerPixel = wfc->dstBpp;
404                 wfc->hdc->bytesPerPixel = wfc->dstBpp / 8;
405
406                 wfc->hdc->alpha = wfc->clrconv->alpha;
407                 wfc->hdc->invert = wfc->clrconv->invert;
408
409                 wfc->hdc->hwnd = (HGDI_WND) malloc(sizeof(GDI_WND));
410                 wfc->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0);
411                 wfc->hdc->hwnd->invalid->null = 1;
412
413                 wfc->hdc->hwnd->count = 32;
414                 wfc->hdc->hwnd->cinvalid = (HGDI_RGN) malloc(sizeof(GDI_RGN) * wfc->hdc->hwnd->count);
415                 wfc->hdc->hwnd->ninvalid = 0;
416
417                 if (settings->RemoteFxCodec)
418                 {
419                         wfc->tile = wf_image_new(wfc, 64, 64, 32, NULL);
420                 }
421         }
422
423         if (settings->WindowTitle != NULL)
424                 _snwprintf(lpWindowName, ARRAYSIZE(lpWindowName), L"%S", settings->WindowTitle);
425         else if (settings->ServerPort == 3389)
426                 _snwprintf(lpWindowName, ARRAYSIZE(lpWindowName), L"FreeRDP: %S", settings->ServerHostname);
427         else
428                 _snwprintf(lpWindowName, ARRAYSIZE(lpWindowName), L"FreeRDP: %S:%d", settings->ServerHostname, settings->ServerPort);
429
430         if (settings->EmbeddedWindow)
431                 settings->Decorations = FALSE;
432
433         if (wfc->fullscreen)
434                 dwStyle = WS_POPUP;
435         else if (!settings->Decorations)
436                 dwStyle = WS_CHILD | WS_BORDER;
437         else
438                 dwStyle = WS_CAPTION | WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | WS_MAXIMIZEBOX;
439
440         if (!wfc->hwnd)
441         {
442                 wfc->hwnd = CreateWindowEx((DWORD) NULL, wfc->wndClassName, lpWindowName, dwStyle,
443                         0, 0, 0, 0, wfc->hWndParent, NULL, wfc->hInstance, NULL);
444
445                 SetWindowLongPtr(wfc->hwnd, GWLP_USERDATA, (LONG_PTR) wfc);
446         }
447
448         wf_resize_window(wfc);
449
450         wf_add_system_menu(wfc);
451
452         BitBlt(wfc->primary->hdc, 0, 0, wfc->width, wfc->height, NULL, 0, 0, BLACKNESS);
453         wfc->drawing = wfc->primary;
454
455         EventArgsInit(&e, "wfreerdp");
456         e.embed = FALSE;
457         e.handle = (void*) wfc->hwnd;
458         PubSub_OnEmbedWindow(context->pubSub, context, &e);
459
460         ShowWindow(wfc->hwnd, SW_SHOWNORMAL);
461         UpdateWindow(wfc->hwnd);
462
463         if (settings->SoftwareGdi)
464         {
465                 instance->update->BeginPaint = (pBeginPaint) wf_sw_begin_paint;
466                 instance->update->EndPaint = (pEndPaint) wf_sw_end_paint;
467                 instance->update->DesktopResize = (pDesktopResize) wf_sw_desktop_resize;
468         }
469         else
470         {
471                 instance->update->BeginPaint = (pBeginPaint) wf_hw_begin_paint;
472                 instance->update->EndPaint = (pEndPaint) wf_hw_end_paint;
473                 instance->update->DesktopResize = (pDesktopResize) wf_hw_desktop_resize;
474         }
475
476         pointer_cache_register_callbacks(instance->update);
477         wf_register_pointer(context->graphics);
478
479         if (!settings->SoftwareGdi)
480         {
481                 brush_cache_register_callbacks(instance->update);
482                 bitmap_cache_register_callbacks(instance->update);
483                 offscreen_cache_register_callbacks(instance->update);
484                 wf_register_graphics(context->graphics);
485                 instance->update->BitmapUpdate = wf_gdi_bitmap_update;
486         }
487
488         if (freerdp_channels_post_connect(context->channels, instance) < 0)
489                 return FALSE;
490
491         if (wfc->fullscreen)
492                 floatbar_window_create(wfc);
493
494         return TRUE;
495 }
496
497 static CREDUI_INFOA wfUiInfo =
498 {
499         sizeof(CREDUI_INFOA),
500         NULL,
501         "Enter your credentials",
502         "Remote Desktop Security",
503         NULL
504 };
505
506 static BOOL wf_authenticate_raw(freerdp* instance, const char* title,
507                 char** username, char** password, char** domain)
508 {
509         BOOL fSave;
510         DWORD status;
511         DWORD dwFlags;
512         char UserName[CREDUI_MAX_USERNAME_LENGTH + 1];
513         char Password[CREDUI_MAX_PASSWORD_LENGTH + 1];
514         char User[CREDUI_MAX_USERNAME_LENGTH + 1];
515         char Domain[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1];
516
517         fSave = FALSE;
518         ZeroMemory(UserName, sizeof(UserName));
519         ZeroMemory(Password, sizeof(Password));
520         dwFlags = CREDUI_FLAGS_DO_NOT_PERSIST | CREDUI_FLAGS_EXCLUDE_CERTIFICATES;
521
522         status = CredUIPromptForCredentialsA(&wfUiInfo, title, NULL, 0,
523                 UserName, CREDUI_MAX_USERNAME_LENGTH + 1,
524                 Password, CREDUI_MAX_PASSWORD_LENGTH + 1, &fSave, dwFlags);
525
526         if (status != NO_ERROR)
527         {
528                 WLog_ERR(TAG, "CredUIPromptForCredentials unexpected status: 0x%08X", status);
529                 return FALSE;
530         }
531
532         ZeroMemory(User, sizeof(User));
533         ZeroMemory(Domain, sizeof(Domain));
534
535         status = CredUIParseUserNameA(UserName, User, sizeof(User), Domain, sizeof(Domain));
536         //WLog_ERR(TAG, "User: %s Domain: %s Password: %s", User, Domain, Password);
537         *username = _strdup(User);
538         if (!(*username))
539         {
540                 WLog_ERR(TAG, "strdup failed", status);
541                 return FALSE;
542         }
543
544         if (strlen(Domain) > 0)
545                 *domain = _strdup(Domain);
546         else
547                 *domain = _strdup("\0");
548
549         if (!(*domain))
550         {
551                 free(*username);
552                 WLog_ERR(TAG, "strdup failed", status);
553                 return FALSE;
554         }
555
556         *password = _strdup(Password);
557         if (!(*password))
558         {
559                 free(*username);
560                 free(*domain);
561                 return FALSE;
562         }
563
564         return TRUE;
565 }
566
567 static BOOL wf_authenticate(freerdp* instance,
568                 char** username, char** password, char** domain)
569 {
570         return wf_authenticate_raw(instance, instance->settings->ServerHostname,
571                         username, password, domain);
572 }
573
574 static BOOL wf_gw_authenticate(freerdp* instance,
575                 char** username, char** password, char** domain)
576 {
577         char tmp[MAX_PATH];
578         sprintf_s(tmp, sizeof(tmp), "Gateway %s", instance->settings->GatewayHostname);
579         return wf_authenticate_raw(instance, tmp, username, password, domain);
580 }
581
582 BOOL wf_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint)
583 {
584 #if 0
585         DWORD mode;
586         int read_size;
587         DWORD read_count;
588         TCHAR answer[2];
589         TCHAR* read_buffer;
590         HANDLE input_handle;
591 #endif
592         WLog_INFO(TAG, "Certificate details:");
593         WLog_INFO(TAG, "\tSubject: %s", subject);
594         WLog_INFO(TAG, "\tIssuer: %s", issuer);
595         WLog_INFO(TAG, "\tThumbprint: %s", fingerprint);
596         WLog_INFO(TAG, "The above X.509 certificate could not be verified, possibly because you do not have "
597                           "the CA certificate in your certificate store, or the certificate has expired. "
598                           "Please look at the documentation on how to create local certificate store for a private CA.");
599         /* TODO: ask for user validation */
600 #if 0
601         input_handle = GetStdHandle(STD_INPUT_HANDLE);
602
603         GetConsoleMode(input_handle, &mode);
604         mode |= ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT;
605         SetConsoleMode(input_handle, mode);
606 #endif
607
608         return TRUE;
609 }
610
611 static BOOL wf_auto_reconnect(freerdp* instance)
612 {
613         wfContext* wfc = (wfContext *)instance->context;
614
615         UINT32 num_retries = 0;
616         UINT32 max_retries = instance->settings->AutoReconnectMaxRetries;
617
618         /* Only auto reconnect on network disconnects. */
619         if (freerdp_error_info(instance) != 0)
620                 return FALSE;
621
622         /* A network disconnect was detected */
623         WLog_ERR(TAG, "Network disconnect!");
624
625         if (!instance->settings->AutoReconnectionEnabled)
626         {
627                 /* No auto-reconnect - just quit */
628                 return FALSE;
629         }
630
631         /* Perform an auto-reconnect. */
632         for (;;)
633         {
634                 /* Quit retrying if max retries has been exceeded */
635                 if (num_retries++ >= max_retries)
636                         return FALSE;
637
638                 /* Attempt the next reconnect */
639                 WLog_INFO(TAG,  "Attempting reconnect (%u of %u)", num_retries, max_retries);
640
641                 if (freerdp_reconnect(instance))
642                 {
643                         return TRUE;
644                 }
645
646                 Sleep(5000);
647         }
648
649         WLog_ERR(TAG, "Maximum reconnect retries exceeded");
650         return FALSE;
651 }
652
653 void* wf_input_thread(void* arg)
654 {
655         int status;
656         wMessage message;
657         wMessageQueue* queue;
658         freerdp* instance = (freerdp*) arg;
659
660         assert( NULL != instance);
661
662         status = 1;
663         queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE);
664
665         while (MessageQueue_Wait(queue))
666         {
667                 while (MessageQueue_Peek(queue, &message, TRUE))
668                 {
669                         status = freerdp_message_queue_process_message(instance,
670                                         FREERDP_INPUT_MESSAGE_QUEUE, &message);
671
672                         if (!status)
673                                 break;
674                 }
675
676                 if (!status)
677                         break;
678         }
679
680         ExitThread(0);
681
682         return NULL;
683 }
684
685 DWORD WINAPI wf_client_thread(LPVOID lpParam)
686 {
687         MSG msg;
688         int width;
689         int height;
690         BOOL msg_ret;
691         int quit_msg;
692         DWORD nCount;
693         HANDLE handles[64];
694         wfContext* wfc;
695         freerdp* instance;
696         rdpContext* context;
697         rdpChannels* channels;
698         rdpSettings* settings;
699         BOOL async_input;
700         BOOL async_transport;
701         HANDLE input_thread;
702
703         instance = (freerdp*) lpParam;
704         context = instance->context;
705         wfc = (wfContext*) instance->context;
706
707         if (!freerdp_connect(instance))
708                 return 0;
709
710         channels = instance->context->channels;
711         settings = instance->context->settings;
712
713         async_input = settings->AsyncInput;
714         async_transport = settings->AsyncTransport;
715
716         if (async_input)
717         {
718                 if (!(input_thread = CreateThread(NULL, 0,
719                                 (LPTHREAD_START_ROUTINE) wf_input_thread,
720                                 instance, 0, NULL)))
721                 {
722                         WLog_ERR(TAG, "Failed to create async input thread.");
723                         goto disconnect;
724                 }
725         }
726
727         while (1)
728         {
729                 nCount = 0;
730
731                 if (freerdp_focus_required(instance))
732                 {
733                         wf_event_focus_in(wfc);
734                         wf_event_focus_in(wfc);
735                 }
736
737                 if (!async_transport)
738                 {
739                         DWORD tmp = freerdp_get_event_handles(context, &handles[nCount], 64 - nCount);
740
741                         if (tmp == 0)
742                         {
743                                 WLog_ERR(TAG, "freerdp_get_event_handles failed");
744                                 break;
745                         }
746
747                         nCount += tmp;
748                 }
749
750                 if (MsgWaitForMultipleObjects(nCount, handles, FALSE, 1000, QS_ALLINPUT) == WAIT_FAILED)
751                 {
752                         WLog_ERR(TAG, "wfreerdp_run: WaitForMultipleObjects failed: 0x%04X", GetLastError());
753                         break;
754                 }
755
756                 if (!async_transport)
757                 {
758                         if (!freerdp_check_event_handles(context))
759                         {
760                                 if (wf_auto_reconnect(instance))
761                                         continue;
762
763                                 WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
764                                 break;
765                         }
766                 }
767
768                 if (freerdp_shall_disconnect(instance))
769                         break;
770
771                 quit_msg = FALSE;
772
773                 while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
774                 {
775                         msg_ret = GetMessage(&msg, NULL, 0, 0);
776
777                         if (instance->settings->EmbeddedWindow)
778                         {
779                                 if ((msg.message == WM_SETFOCUS) && (msg.lParam == 1))
780                                 {
781                                         PostMessage(wfc->hwnd, WM_SETFOCUS, 0, 0);
782                                 }
783                                 else if ((msg.message == WM_KILLFOCUS) && (msg.lParam == 1))
784                                 {
785                                         PostMessage(wfc->hwnd, WM_KILLFOCUS, 0, 0);
786                                 }
787                         }
788
789                         if (msg.message == WM_SIZE)
790                         {
791                                 width = LOWORD(msg.lParam);
792                                 height = HIWORD(msg.lParam);
793
794                                 SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0, width, height, SWP_FRAMECHANGED);
795                         }
796
797                         if ((msg_ret == 0) || (msg_ret == -1))
798                         {
799                                 quit_msg = TRUE;
800                                 break;
801                         }
802
803                         TranslateMessage(&msg);
804                         DispatchMessage(&msg);
805                 }
806
807                 if (quit_msg)
808                         break;
809         }
810
811         /* cleanup */
812         freerdp_channels_disconnect(channels, instance);
813
814         if (async_input)
815         {
816                 wMessageQueue* input_queue;
817                 input_queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE);
818                 if (MessageQueue_PostQuit(input_queue, 0))
819                         WaitForSingleObject(input_thread, INFINITE);
820                 CloseHandle(input_thread);
821         }
822
823 disconnect:
824         freerdp_disconnect(instance);
825         WLog_DBG(TAG, "Main thread exited.");
826
827         ExitThread(0);
828         return 0;
829 }
830
831 DWORD WINAPI wf_keyboard_thread(LPVOID lpParam)
832 {
833         MSG msg;
834         BOOL status;
835         wfContext* wfc;
836         HHOOK hook_handle;
837
838         wfc = (wfContext*) lpParam;
839         assert(NULL != wfc);
840
841         hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, wf_ll_kbd_proc, wfc->hInstance, 0);
842
843         if (hook_handle)
844         {
845                 while ((status = GetMessage(&msg, NULL, 0, 0)) != 0)
846                 {
847                         if (status == -1)
848                         {
849                                 WLog_ERR(TAG, "keyboard thread error getting message");
850                                 break;
851                         }
852                         else
853                         {
854                                 TranslateMessage(&msg);
855                                 DispatchMessage(&msg);
856                         }
857                 }
858
859                 UnhookWindowsHookEx(hook_handle);
860         }
861         else
862         {
863                 WLog_ERR(TAG, "failed to install keyboard hook");
864         }
865
866         WLog_DBG(TAG, "Keyboard thread exited.");
867         ExitThread(0);
868         return (DWORD) NULL;
869 }
870
871 rdpSettings* freerdp_client_get_settings(wfContext* wfc)
872 {
873         return wfc->instance->settings;
874 }
875
876 int freerdp_client_focus_in(wfContext* wfc)
877 {
878         PostThreadMessage(wfc->mainThreadId, WM_SETFOCUS, 0, 1);
879         return 0;
880 }
881
882 int freerdp_client_focus_out(wfContext* wfc)
883 {
884         PostThreadMessage(wfc->mainThreadId, WM_KILLFOCUS, 0, 1);
885         return 0;
886 }
887
888 int freerdp_client_set_window_size(wfContext* wfc, int width, int height)
889 {
890         WLog_DBG(TAG,  "freerdp_client_set_window_size %d, %d", width, height);
891
892         if ((width != wfc->client_width) || (height != wfc->client_height))
893         {
894                 PostThreadMessage(wfc->mainThreadId, WM_SIZE, SIZE_RESTORED, ((UINT) height << 16) | (UINT) width);
895         }
896
897         return 0;
898 }
899
900 // TODO: Some of that code is a duplicate of wf_pre_connect. Refactor?
901 int freerdp_client_load_settings_from_rdp_file(wfContext* wfc, char* filename)
902 {
903         rdpSettings* settings;
904
905         settings = wfc->instance->settings;
906
907         if (filename)
908         {
909                 settings->ConnectionFile = _strdup(filename);
910                 if (!settings->ConnectionFile)
911                 {
912                         return 3;
913                 }
914
915                 // free old settings file
916                 freerdp_client_rdp_file_free(wfc->connectionRdpFile);
917                 wfc->connectionRdpFile = freerdp_client_rdp_file_new();
918                 WLog_INFO(TAG,  "Using connection file: %s", settings->ConnectionFile);
919
920                 if (!freerdp_client_parse_rdp_file(wfc->connectionRdpFile, settings->ConnectionFile))
921                 {
922                         return 1;
923                 }
924
925                 if (!freerdp_client_populate_settings_from_rdp_file(wfc->connectionRdpFile, settings))
926                 {
927                         return 2;
928                 }
929         }
930
931         return 0;
932 }
933
934 void wf_size_scrollbars(wfContext* wfc, UINT32 client_width, UINT32 client_height)
935 {
936         if (wfc->disablewindowtracking)
937                 return;
938
939         // prevent infinite message loop
940         wfc->disablewindowtracking = TRUE;
941
942         if (wfc->instance->settings->SmartSizing)
943         {
944                 wfc->xCurrentScroll = 0;
945                 wfc->yCurrentScroll = 0;
946
947                 if (wfc->xScrollVisible || wfc->yScrollVisible)
948                 {
949                         if (ShowScrollBar(wfc->hwnd, SB_BOTH, FALSE))
950                         {
951                                 wfc->xScrollVisible = FALSE;
952                                 wfc->yScrollVisible = FALSE;
953                         }
954                 }
955         }
956         else
957         {
958                 SCROLLINFO si;
959                 BOOL horiz = wfc->xScrollVisible;
960                 BOOL vert = wfc->yScrollVisible;;
961
962                 if (!horiz && client_width < wfc->instance->settings->DesktopWidth)
963                 {
964                         horiz = TRUE;
965                 }
966                 else if (horiz && client_width >= wfc->instance->settings->DesktopWidth/* - GetSystemMetrics(SM_CXVSCROLL)*/)
967                 {
968                         horiz = FALSE;
969                 }
970
971                 if (!vert && client_height < wfc->instance->settings->DesktopHeight)
972                 {
973                         vert = TRUE;
974                 }
975                 else if (vert && client_height >= wfc->instance->settings->DesktopHeight/* - GetSystemMetrics(SM_CYHSCROLL)*/)
976                 {
977                         vert = FALSE;
978                 }
979
980                 if (horiz == vert && (horiz != wfc->xScrollVisible && vert != wfc->yScrollVisible))
981                 {
982                         if (ShowScrollBar(wfc->hwnd, SB_BOTH, horiz))
983                         {
984                                 wfc->xScrollVisible = horiz;
985                                 wfc->yScrollVisible = vert;
986                         }
987                 }
988
989                 if (horiz != wfc->xScrollVisible)
990                 {
991                         if (ShowScrollBar(wfc->hwnd, SB_HORZ, horiz))
992                         {
993                                 wfc->xScrollVisible = horiz;
994                         }
995                 }
996
997                 if (vert != wfc->yScrollVisible)
998                 {
999                         if (ShowScrollBar(wfc->hwnd, SB_VERT, vert))
1000                         {
1001                                 wfc->yScrollVisible = vert;
1002                         }
1003                 }
1004
1005                 if (horiz)
1006                 {
1007                         // The horizontal scrolling range is defined by
1008                         // (bitmap_width) - (client_width). The current horizontal
1009                         // scroll value remains within the horizontal scrolling range.
1010                         wfc->xMaxScroll = MAX(wfc->instance->settings->DesktopWidth - client_width, 0);
1011                         wfc->xCurrentScroll = MIN(wfc->xCurrentScroll, wfc->xMaxScroll);
1012                         si.cbSize = sizeof(si);
1013                         si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
1014                         si.nMin   = wfc->xMinScroll;
1015                         si.nMax   = wfc->instance->settings->DesktopWidth;
1016                         si.nPage  = client_width;
1017                         si.nPos   = wfc->xCurrentScroll;
1018                         SetScrollInfo(wfc->hwnd, SB_HORZ, &si, TRUE);
1019                 }
1020
1021                 if (vert)
1022                 {
1023                         // The vertical scrolling range is defined by
1024                         // (bitmap_height) - (client_height). The current vertical
1025                         // scroll value remains within the vertical scrolling range.
1026                         wfc->yMaxScroll = MAX(wfc->instance->settings->DesktopHeight - client_height, 0);
1027                         wfc->yCurrentScroll = MIN(wfc->yCurrentScroll, wfc->yMaxScroll);
1028                         si.cbSize = sizeof(si);
1029                         si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
1030                         si.nMin   = wfc->yMinScroll;
1031                         si.nMax   = wfc->instance->settings->DesktopHeight;
1032                         si.nPage  = client_height;
1033                         si.nPos   = wfc->yCurrentScroll;
1034                         SetScrollInfo(wfc->hwnd, SB_VERT, &si, TRUE);
1035                 }
1036         }
1037
1038         wfc->disablewindowtracking = FALSE;
1039         wf_update_canvas_diff(wfc);
1040 }
1041
1042 BOOL wfreerdp_client_global_init(void)
1043 {
1044         WSADATA wsaData;
1045
1046         if (!getenv("HOME"))
1047         {
1048                 char home[MAX_PATH * 2] = "HOME=";
1049                 strcat(home, getenv("HOMEDRIVE"));
1050                 strcat(home, getenv("HOMEPATH"));
1051                 _putenv(home);
1052         }
1053
1054         WSAStartup(0x101, &wsaData);
1055
1056 #if defined(WITH_DEBUG) || defined(_DEBUG)
1057         wf_create_console();
1058 #endif
1059
1060         freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0);
1061         return TRUE;
1062 }
1063
1064 void wfreerdp_client_global_uninit(void)
1065 {
1066         WSACleanup();
1067 }
1068
1069 BOOL wfreerdp_client_new(freerdp* instance, rdpContext* context)
1070 {
1071         wfContext* wfc = (wfContext*) context;
1072
1073         if (!(wfreerdp_client_global_init()))
1074                 return FALSE;
1075
1076         if (!(context->channels = freerdp_channels_new()))
1077                 return FALSE;
1078
1079         instance->PreConnect = wf_pre_connect;
1080         instance->PostConnect = wf_post_connect;
1081         instance->Authenticate = wf_authenticate;
1082         instance->GatewayAuthenticate = wf_gw_authenticate;
1083         instance->VerifyCertificate = wf_verify_certificate;
1084
1085         wfc->instance = instance;
1086         wfc->settings = instance->settings;
1087
1088         return TRUE;
1089 }
1090
1091 void wfreerdp_client_free(freerdp* instance, rdpContext* context)
1092 {
1093         if (!context)
1094                 return;
1095
1096         if (context->channels)
1097         {
1098                 freerdp_channels_close(context->channels, instance);
1099                 freerdp_channels_free(context->channels);
1100                 context->channels = NULL;
1101         }
1102
1103         if (context->cache)
1104         {
1105                 cache_free(context->cache);
1106                 context->cache = NULL;
1107         }
1108 }
1109
1110 int wfreerdp_client_start(rdpContext* context)
1111 {
1112         HWND hWndParent;
1113         HINSTANCE hInstance;
1114         wfContext* wfc = (wfContext*) context;
1115         freerdp* instance = context->instance;
1116
1117         hInstance = GetModuleHandle(NULL);
1118         hWndParent = (HWND) instance->settings->ParentWindowId;
1119         instance->settings->EmbeddedWindow = (hWndParent) ? TRUE : FALSE;
1120
1121         wfc->hWndParent = hWndParent;
1122         wfc->hInstance = hInstance;
1123         wfc->cursor = LoadCursor(NULL, IDC_ARROW);
1124         wfc->icon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1));
1125         wfc->wndClassName = _tcsdup(_T("FreeRDP"));
1126
1127         wfc->wndClass.cbSize = sizeof(WNDCLASSEX);
1128         wfc->wndClass.style = CS_HREDRAW | CS_VREDRAW;
1129         wfc->wndClass.lpfnWndProc = wf_event_proc;
1130         wfc->wndClass.cbClsExtra = 0;
1131         wfc->wndClass.cbWndExtra = 0;
1132         wfc->wndClass.hCursor = wfc->cursor;
1133         wfc->wndClass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
1134         wfc->wndClass.lpszMenuName = NULL;
1135         wfc->wndClass.lpszClassName = wfc->wndClassName;
1136         wfc->wndClass.hInstance = hInstance;
1137         wfc->wndClass.hIcon = wfc->icon;
1138         wfc->wndClass.hIconSm = wfc->icon;
1139         RegisterClassEx(&(wfc->wndClass));
1140
1141         wfc->keyboardThread = CreateThread(NULL, 0, wf_keyboard_thread, (void*) wfc, 0, &wfc->keyboardThreadId);
1142
1143         if (!wfc->keyboardThread)
1144                 return -1;
1145
1146         freerdp_client_load_addins(context->channels, instance->settings);
1147
1148         wfc->thread = CreateThread(NULL, 0, wf_client_thread, (void*) instance, 0, &wfc->mainThreadId);
1149
1150         if (!wfc->thread)
1151                 return -1;
1152
1153         return 0;
1154 }
1155
1156 int wfreerdp_client_stop(rdpContext* context)
1157 {
1158         wfContext* wfc = (wfContext*) context;
1159
1160         if (wfc->thread)
1161         {
1162                 PostThreadMessage(wfc->mainThreadId, WM_QUIT, 0, 0);
1163
1164                 WaitForSingleObject(wfc->thread, INFINITE);
1165                 CloseHandle(wfc->thread);
1166                 wfc->thread = NULL;
1167                 wfc->mainThreadId = 0;
1168         }
1169
1170         if (wfc->keyboardThread)
1171         {
1172                 PostThreadMessage(wfc->keyboardThreadId, WM_QUIT, 0, 0);
1173
1174                 WaitForSingleObject(wfc->keyboardThread, INFINITE);
1175                 CloseHandle(wfc->keyboardThread);
1176
1177                 wfc->keyboardThread = NULL;
1178                 wfc->keyboardThreadId = 0;
1179         }
1180
1181         return 0;
1182 }
1183
1184 int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
1185 {
1186         pEntryPoints->Version = 1;
1187         pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
1188
1189         pEntryPoints->GlobalInit = wfreerdp_client_global_init;
1190         pEntryPoints->GlobalUninit = wfreerdp_client_global_uninit;
1191
1192         pEntryPoints->ContextSize = sizeof(wfContext);
1193         pEntryPoints->ClientNew = wfreerdp_client_new;
1194         pEntryPoints->ClientFree = wfreerdp_client_free;
1195
1196         pEntryPoints->ClientStart = wfreerdp_client_start;
1197         pEntryPoints->ClientStop = wfreerdp_client_stop;
1198
1199         return 0;
1200 }