1/*
2 RDP ui callbacks
3
4 Copyright 2013 Thincast Technologies GmbH, Authors: Martin Fleisz, Dorian Johnson
5
6 This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
7 If a copy of the MPL was not distributed with this file, You can obtain one at
8 http://mozilla.org/MPL/2.0/.
9 */
10
11#import <Foundation/Foundation.h>
12
13#import <freerdp/gdi/gdi.h>
14#import "ios_freerdp_ui.h"
15
16#import "RDPSession.h"
17
18#pragma mark -
19#pragma mark Certificate authentication
20
21static void ios_resize_display_buffer(mfInfo *mfi);
22static BOOL ios_ui_authenticate_raw(freerdp *instance, char **username, char **password,
23                                    char **domain, const char *title)
24{
25	mfInfo *mfi = MFI_FROM_INSTANCE(instance);
26	NSMutableDictionary *params = [NSMutableDictionary
27	    dictionaryWithObjectsAndKeys:(*username) ? [NSString stringWithUTF8String:*username] : @"",
28	                                 @"username",
29	                                 (*password) ? [NSString stringWithUTF8String:*password] : @"",
30	                                 @"password",
31	                                 (*domain) ? [NSString stringWithUTF8String:*domain] : @"",
32	                                 @"domain",
33	                                 [NSString
34	                                     stringWithUTF8String:instance->settings->ServerHostname],
35	                                 @"hostname", // used for the auth prompt message; not changed
36	                                 nil];
37	// request auth UI
38	[mfi->session performSelectorOnMainThread:@selector(sessionRequestsAuthenticationWithParams:)
39	                               withObject:params
40	                            waitUntilDone:YES];
41	// wait for UI request to be completed
42	[[mfi->session uiRequestCompleted] lock];
43	[[mfi->session uiRequestCompleted] wait];
44	[[mfi->session uiRequestCompleted] unlock];
45
46	if (![[params valueForKey:@"result"] boolValue])
47	{
48		mfi->unwanted = YES;
49		return FALSE;
50	}
51
52	// Free old values
53	free(*username);
54	free(*password);
55	free(*domain);
56	// set values back
57	*username = strdup([[params objectForKey:@"username"] UTF8String]);
58	*password = strdup([[params objectForKey:@"password"] UTF8String]);
59	*domain = strdup([[params objectForKey:@"domain"] UTF8String]);
60
61	if (!(*username) || !(*password) || !(*domain))
62	{
63		free(*username);
64		free(*password);
65		free(*domain);
66		return FALSE;
67	}
68
69	return TRUE;
70}
71
72BOOL ios_ui_authenticate(freerdp *instance, char **username, char **password, char **domain)
73{
74	return ios_ui_authenticate_raw(instance, username, password, domain, "");
75}
76
77BOOL ios_ui_gw_authenticate(freerdp *instance, char **username, char **password, char **domain)
78{
79	return ios_ui_authenticate_raw(instance, username, password, domain, "gateway");
80}
81
82DWORD ios_ui_verify_certificate(freerdp *instance, const char *common_name, const char *subject,
83                                const char *issuer, const char *fingerprint, BOOL host_mismatch)
84{
85	// check whether we accept all certificates
86	if ([[NSUserDefaults standardUserDefaults] boolForKey:@"security.accept_certificates"] == YES)
87		return 2;
88
89	mfInfo *mfi = MFI_FROM_INSTANCE(instance);
90	NSMutableDictionary *params = [NSMutableDictionary
91	    dictionaryWithObjectsAndKeys:(subject) ? [NSString stringWithUTF8String:subject] : @"",
92	                                 @"subject",
93	                                 (issuer) ? [NSString stringWithUTF8String:issuer] : @"",
94	                                 @"issuer",
95	                                 (fingerprint) ? [NSString stringWithUTF8String:subject] : @"",
96	                                 @"fingerprint", nil];
97	// request certificate verification UI
98	[mfi->session performSelectorOnMainThread:@selector(sessionVerifyCertificateWithParams:)
99	                               withObject:params
100	                            waitUntilDone:YES];
101	// wait for UI request to be completed
102	[[mfi->session uiRequestCompleted] lock];
103	[[mfi->session uiRequestCompleted] wait];
104	[[mfi->session uiRequestCompleted] unlock];
105
106	if (![[params valueForKey:@"result"] boolValue])
107	{
108		mfi->unwanted = YES;
109		return 0;
110	}
111
112	return 1;
113}
114
115DWORD ios_ui_verify_changed_certificate(freerdp *instance, const char *common_name,
116                                        const char *subject, const char *issuer,
117                                        const char *new_fingerprint, const char *old_subject,
118                                        const char *old_issuer, const char *old_fingerprint)
119{
120	return ios_ui_verify_certificate(instance, common_name, subject, issuer, new_fingerprint,
121	                                 FALSE);
122}
123
124#pragma mark -
125#pragma mark Graphics updates
126
127BOOL ios_ui_begin_paint(rdpContext *context)
128{
129	rdpGdi *gdi = context->gdi;
130	gdi->primary->hdc->hwnd->invalid->null = TRUE;
131	return TRUE;
132}
133
134BOOL ios_ui_end_paint(rdpContext *context)
135{
136	mfInfo *mfi = MFI_FROM_INSTANCE(context->instance);
137	rdpGdi *gdi = context->gdi;
138	CGRect dirty_rect =
139	    CGRectMake(gdi->primary->hdc->hwnd->invalid->x, gdi->primary->hdc->hwnd->invalid->y,
140	               gdi->primary->hdc->hwnd->invalid->w, gdi->primary->hdc->hwnd->invalid->h);
141
142	if (!gdi->primary->hdc->hwnd->invalid->null)
143		[mfi->session performSelectorOnMainThread:@selector(setNeedsDisplayInRectAsValue:)
144		                               withObject:[NSValue valueWithCGRect:dirty_rect]
145		                            waitUntilDone:NO];
146
147	return TRUE;
148}
149
150BOOL ios_ui_resize_window(rdpContext *context)
151{
152	rdpSettings *settings;
153	rdpGdi *gdi;
154
155	if (!context || !context->settings)
156		return FALSE;
157
158	settings = context->settings;
159	gdi = context->gdi;
160
161	if (!gdi_resize(gdi, settings->DesktopWidth, settings->DesktopHeight))
162		return FALSE;
163
164	ios_resize_display_buffer(MFI_FROM_INSTANCE(context->instance));
165	return TRUE;
166}
167
168#pragma mark -
169#pragma mark Exported
170
171static void ios_create_bitmap_context(mfInfo *mfi)
172{
173	[mfi->session performSelectorOnMainThread:@selector(sessionBitmapContextWillChange)
174	                               withObject:nil
175	                            waitUntilDone:YES];
176	rdpGdi *gdi = mfi->instance->context->gdi;
177	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
178
179	if (GetBytesPerPixel(gdi->dstFormat) == 2)
180		mfi->bitmap_context = CGBitmapContextCreate(
181		    gdi->primary_buffer, gdi->width, gdi->height, 5, gdi->stride, colorSpace,
182		    kCGBitmapByteOrder16Little | kCGImageAlphaNoneSkipFirst);
183	else
184		mfi->bitmap_context = CGBitmapContextCreate(
185		    gdi->primary_buffer, gdi->width, gdi->height, 8, gdi->stride, colorSpace,
186		    kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst);
187
188	CGColorSpaceRelease(colorSpace);
189	[mfi->session performSelectorOnMainThread:@selector(sessionBitmapContextDidChange)
190	                               withObject:nil
191	                            waitUntilDone:YES];
192}
193
194void ios_allocate_display_buffer(mfInfo *mfi)
195{
196	ios_create_bitmap_context(mfi);
197}
198
199void ios_resize_display_buffer(mfInfo *mfi)
200{
201	// Release the old context in a thread-safe manner
202	CGContextRef old_context = mfi->bitmap_context;
203	mfi->bitmap_context = NULL;
204	CGContextRelease(old_context);
205	// Create the new context
206	ios_create_bitmap_context(mfi);
207}
208