FreeRDP
Loading...
Searching...
No Matches
ios_freerdp_ui.m
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 <freerdp/client.h>
15#import "ios_freerdp_ui.h"
16
17#import "RDPSession.h"
18
19#pragma mark -
20#pragma mark Certificate authentication
21
22static void ios_resize_display_buffer(mfInfo *mfi);
23
24BOOL ios_ui_authenticate_ex(freerdp *instance, char **username, char **password, char **domain,
25 rdp_auth_reason reason)
26{
27 const char *target = freerdp_settings_get_server_name(instance->context->settings);
28 switch (reason)
29 {
30 case AUTH_RDSTLS:
31 case AUTH_NLA:
32 break;
33
34 case AUTH_TLS:
35 case AUTH_RDP:
36 case AUTH_SMARTCARD_PIN: /* in this case password is pin code */
37 case AUTH_FIDO_PIN:
38 if ((*username) && (*password))
39 return TRUE;
40 break;
41 case GW_AUTH_HTTP:
42 case GW_AUTH_RDG:
43 case GW_AUTH_RPC:
44 target =
45 freerdp_settings_get_string(instance->context->settings, FreeRDP_GatewayHostname);
46 break;
47 default:
48 break;
49 }
50
51 mfInfo *mfi = MFI_FROM_INSTANCE(instance);
52 NSMutableDictionary *params = [NSMutableDictionary
53 dictionaryWithObjectsAndKeys:(*username) ? [NSString stringWithUTF8String:*username] : @"",
54 @"username",
55 (*password) ? [NSString stringWithUTF8String:*password] : @"",
56 @"password",
57 (*domain) ? [NSString stringWithUTF8String:*domain] : @"",
58 @"domain", [NSString stringWithUTF8String:target],
59 @"hostname", // used for the auth prompt message; not changed
60 nil];
61 // request auth UI
62 [mfi->session performSelectorOnMainThread:@selector(sessionRequestsAuthenticationWithParams:)
63 withObject:params
64 waitUntilDone:YES];
65 // wait for UI request to be completed
66 [[mfi->session uiRequestCompleted] lock];
67 [[mfi->session uiRequestCompleted] wait];
68 [[mfi->session uiRequestCompleted] unlock];
69
70 if (![[params valueForKey:@"result"] boolValue])
71 {
72 mfi->unwanted = YES;
73 return FALSE;
74 }
75
76 // Free old values
77 free(*username);
78 free(*password);
79 free(*domain);
80 // set values back
81 *username = _strdup([[params objectForKey:@"username"] UTF8String]);
82 *password = _strdup([[params objectForKey:@"password"] UTF8String]);
83 *domain = _strdup([[params objectForKey:@"domain"] UTF8String]);
84
85 if (!(*username) || !(*password) || !(*domain))
86 {
87 free(*username);
88 free(*password);
89 free(*domain);
90 return FALSE;
91 }
92
93 return TRUE;
94}
95
96DWORD ios_ui_verify_certificate_ex(freerdp *instance, const char *host, UINT16 port,
97 const char *common_name, const char *subject, const char *issuer,
98 const char *fingerprint, DWORD flags)
99{
100 // check whether we accept all certificates
101 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"security.accept_certificates"] == YES)
102 return 2;
103
104 mfInfo *mfi = MFI_FROM_INSTANCE(instance);
105 NSMutableDictionary *params = [NSMutableDictionary
106 dictionaryWithObjectsAndKeys:(subject) ? [NSString stringWithUTF8String:subject] : @"",
107 @"subject",
108 (issuer) ? [NSString stringWithUTF8String:issuer] : @"",
109 @"issuer",
110 (fingerprint) ? [NSString stringWithUTF8String:subject] : @"",
111 @"fingerprint", nil];
112 // request certificate verification UI
113 [mfi->session performSelectorOnMainThread:@selector(sessionVerifyCertificateWithParams:)
114 withObject:params
115 waitUntilDone:YES];
116 // wait for UI request to be completed
117 [[mfi->session uiRequestCompleted] lock];
118 [[mfi->session uiRequestCompleted] wait];
119 [[mfi->session uiRequestCompleted] unlock];
120
121 if (![[params valueForKey:@"result"] boolValue])
122 {
123 mfi->unwanted = YES;
124 return 0;
125 }
126
127 return 1;
128}
129
130DWORD ios_ui_verify_changed_certificate_ex(freerdp *instance, const char *host, UINT16 port,
131 const char *common_name, const char *subject,
132 const char *issuer, const char *fingerprint,
133 const char *old_subject, const char *old_issuer,
134 const char *old_fingerprint, DWORD flags)
135{
136 return ios_ui_verify_certificate_ex(instance, host, port, common_name, subject, issuer,
137 fingerprint, flags);
138}
139
140SSIZE_T ios_ui_retry_dialog(freerdp *instance, const char *what, size_t current, void *userarg)
141{
142 WINPR_ASSERT(instance);
143 WINPR_ASSERT(what);
144
145 // waiting for an Azure VM to start ("arm-transport")
146 if (strcmp(what, "connection") != 0)
147 return client_common_retry_dialog(instance, what, current, userarg);
148
149 mfInfo *mfi = MFI_FROM_INSTANCE(instance);
150 WINPR_ASSERT(mfi);
151
152 // cancel button of the connecting view
153 if (mfi->unwanted)
154 return -1;
155
156 if (current == 0)
157 [mfi->session performSelectorOnMainThread:@selector(sessionWillReconnect)
158 withObject:nil
159 waitUntilDone:NO];
160
161 // delay before the next attempt, in ms
162 return 5000;
163}
164
165#pragma mark -
166#pragma mark Graphics updates
167
168BOOL ios_ui_begin_paint(rdpContext *context)
169{
170 WINPR_ASSERT(context);
171
172 rdpGdi *gdi = context->gdi;
173 WINPR_ASSERT(gdi);
174 WINPR_ASSERT(gdi->primary);
175
176 HGDI_DC hdc = gdi->primary->hdc;
177 WINPR_ASSERT(hdc);
178 if (!hdc->hwnd)
179 return TRUE;
180
181 HGDI_WND hwnd = hdc->hwnd;
182 if (!hwnd->invalid)
183 return TRUE;
184 hwnd->invalid->null = TRUE;
185 return TRUE;
186}
187
188BOOL ios_ui_end_paint(rdpContext *context)
189{
190 WINPR_ASSERT(context);
191
192 mfInfo *mfi = MFI_FROM_INSTANCE(context->instance);
193 WINPR_ASSERT(mfi);
194
195 rdpGdi *gdi = context->gdi;
196 WINPR_ASSERT(gdi);
197 WINPR_ASSERT(gdi->primary);
198
199 HGDI_DC hdc = gdi->primary->hdc;
200 WINPR_ASSERT(hdc);
201 if (!hdc->hwnd)
202 return TRUE;
203
204 HGDI_WND hwnd = hdc->hwnd;
205 WINPR_ASSERT(hwnd->invalid || (hwnd->ninvalid == 0));
206
207 if (hwnd->invalid->null)
208 return TRUE;
209
210 CGRect dirty_rect =
211 CGRectMake(hwnd->invalid->x, hwnd->invalid->y, hwnd->invalid->w, hwnd->invalid->h);
212
213 if (!hwnd->invalid->null)
214 [mfi->session performSelectorOnMainThread:@selector(setNeedsDisplayInRectAsValue:)
215 withObject:[NSValue valueWithCGRect:dirty_rect]
216 waitUntilDone:NO];
217
218 return TRUE;
219}
220
221BOOL ios_ui_resize_window(rdpContext *context)
222{
223 rdpSettings *settings;
224 rdpGdi *gdi;
225
226 if (!context || !context->settings)
227 return FALSE;
228
229 settings = context->settings;
230 gdi = context->gdi;
231
232 if (!gdi_resize(gdi, freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
233 freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)))
234 return FALSE;
235
236 ios_resize_display_buffer(MFI_FROM_INSTANCE(context->instance));
237 return TRUE;
238}
239
240#pragma mark -
241#pragma mark Clipboard
242
243void ios_ui_set_clipboard_text(rdpContext *context, const char *text, UINT32 size)
244{
245 WINPR_ASSERT(context);
246
247 mfInfo *mfi = MFI_FROM_INSTANCE(context->instance);
248 WINPR_ASSERT(mfi);
249
250 NSString *string = [[NSString alloc] initWithBytes:text
251 length:size
252 encoding:NSUTF8StringEncoding];
253 if (string)
254 [mfi->session performSelectorOnMainThread:@selector(setRemoteClipboardText:)
255 withObject:string
256 waitUntilDone:NO];
257 [string release];
258}
259
260char *ios_ui_get_clipboard_text(rdpContext *context)
261{
262 WINPR_ASSERT(context);
263
264 mfInfo *mfi = MFI_FROM_INSTANCE(context->instance);
265 WINPR_ASSERT(mfi);
266
267 // called on the cliprdr channel thread, which has no autorelease pool
268 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
269 NSMutableDictionary *params = [NSMutableDictionary dictionary];
270 [mfi->session performSelectorOnMainThread:@selector(sessionRequestsClipboardTextWithParams:)
271 withObject:params
272 waitUntilDone:YES];
273
274 NSString *text = [params objectForKey:@"text"];
275 char *result = text ? _strdup([text UTF8String]) : nullptr;
276 [pool release];
277 return result;
278}
279
280#pragma mark -
281#pragma mark Exported
282
283static void ios_create_bitmap_context(mfInfo *mfi)
284{
285 [mfi->session performSelectorOnMainThread:@selector(sessionBitmapContextWillChange)
286 withObject:nil
287 waitUntilDone:YES];
288 rdpGdi *gdi = mfi->instance->context->gdi;
289 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
290
291 if (FreeRDPGetBytesPerPixel(gdi->dstFormat) == 2)
292 mfi->bitmap_context = CGBitmapContextCreate(
293 gdi->primary_buffer, gdi->width, gdi->height, 5, gdi->stride, colorSpace,
294 kCGBitmapByteOrder16Little | kCGImageAlphaNoneSkipFirst);
295 else
296 mfi->bitmap_context = CGBitmapContextCreate(
297 gdi->primary_buffer, gdi->width, gdi->height, 8, gdi->stride, colorSpace,
298 kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst);
299
300 CGColorSpaceRelease(colorSpace);
301 [mfi->session performSelectorOnMainThread:@selector(sessionBitmapContextDidChange)
302 withObject:nil
303 waitUntilDone:YES];
304}
305
306void ios_allocate_display_buffer(mfInfo *mfi)
307{
308 ios_create_bitmap_context(mfi);
309}
310
311void ios_resize_display_buffer(mfInfo *mfi)
312{
313 // Release the old context in a thread-safe manner
314 CGContextRef old_context = mfi->bitmap_context;
315 mfi->bitmap_context = nullptr;
316 CGContextRelease(old_context);
317 // Create the new context
318 ios_create_bitmap_context(mfi);
319}
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_server_name(const rdpSettings *settings)
A helper function to return the correct server name.
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.