]>
Commit | Line | Data |
---|---|---|
c2493c4e JF |
1 | /* Cydia - iPhone UIKit Front-End for Debian APT |
2 | * Copyright (C) 2008-2015 Jay Freeman (saurik) | |
3 | */ | |
4 | ||
5 | /* GNU General Public License, Version 3 {{{ */ | |
6 | /* | |
7 | * Cydia is free software: you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published | |
9 | * by the Free Software Foundation, either version 3 of the License, | |
10 | * or (at your option) any later version. | |
11 | * | |
12 | * Cydia is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with Cydia. If not, see <http://www.gnu.org/licenses/>. | |
19 | **/ | |
20 | /* }}} */ | |
21 | ||
22 | #include "CyteKit/UCPlatform.h" | |
23 | ||
24 | #include <sys/mount.h> | |
25 | #include <sys/sysctl.h> | |
26 | ||
27 | #include <IOKit/IOKitLib.h> | |
28 | #include <objc/runtime.h> | |
29 | ||
30 | #include "CyteKit/CyteObject.h" | |
31 | #include "CyteKit/WebViewController.h" | |
32 | #include "CyteKit/countByEnumeratingWithState.h" | |
33 | #include "CyteKit/extern.h" | |
34 | ||
35 | #include "iPhonePrivate.h" | |
36 | #include <Menes/ObjectHandle.h> | |
37 | ||
38 | @implementation NSDictionary (Cydia) | |
39 | - (id) invokeUndefinedMethodFromWebScript:(NSString *)name withArguments:(NSArray *)arguments { | |
40 | if (false); | |
41 | else if ([name isEqualToString:@"get"]) | |
42 | return [self objectForKey:[arguments objectAtIndex:0]]; | |
43 | else if ([name isEqualToString:@"keys"]) | |
44 | return [self allKeys]; | |
45 | return nil; | |
46 | } @end | |
47 | ||
48 | static NSString *CYHex(NSData *data, bool reverse = false) { | |
49 | if (data == nil) | |
50 | return nil; | |
51 | ||
52 | size_t length([data length]); | |
53 | uint8_t bytes[length]; | |
54 | [data getBytes:bytes]; | |
55 | ||
56 | char string[length * 2 + 1]; | |
57 | for (size_t i(0); i != length; ++i) | |
58 | sprintf(string + i * 2, "%.2x", bytes[reverse ? length - i - 1 : i]); | |
59 | ||
60 | return [NSString stringWithUTF8String:string]; | |
61 | } | |
62 | ||
63 | static NSObject *CYIOGetValue(const char *path, NSString *property) { | |
64 | io_registry_entry_t entry(IORegistryEntryFromPath(kIOMasterPortDefault, path)); | |
65 | if (entry == MACH_PORT_NULL) | |
66 | return nil; | |
67 | ||
68 | CFTypeRef value(IORegistryEntryCreateCFProperty(entry, (CFStringRef) property, kCFAllocatorDefault, 0)); | |
69 | IOObjectRelease(entry); | |
70 | ||
71 | if (value == NULL) | |
72 | return nil; | |
73 | return [(id) value autorelease]; | |
74 | } | |
75 | ||
76 | @implementation CyteObject { | |
77 | _H<CyteWebViewController> indirect_; | |
78 | } | |
79 | ||
80 | + (BOOL) isKeyExcludedFromWebScript:(const char *)name { | |
81 | return false; | |
82 | } | |
83 | ||
84 | - (id) initWithDelegate:(CyteWebViewController *)indirect { | |
85 | if ((self = [super init]) != nil) { | |
86 | indirect_ = indirect; | |
87 | } return self; | |
88 | } | |
89 | ||
90 | ||
91 | - (NSArray *) attributeKeys { | |
92 | return [NSArray arrayWithObjects: | |
93 | @"bbsnum", | |
94 | @"bittage", | |
95 | @"build", | |
96 | @"coreFoundationVersionNumber", | |
97 | @"ecid", | |
98 | @"firmware", | |
99 | @"hostname", | |
100 | @"idiom", | |
101 | @"model", | |
102 | @"serial", | |
103 | nil]; | |
104 | } | |
105 | ||
106 | - (unsigned) bittage { | |
107 | #if 0 | |
108 | #elif defined(__arm64__) | |
109 | return 64; | |
110 | #elif defined(__arm__) | |
111 | return 32; | |
112 | #else | |
113 | return 0; | |
114 | #endif | |
115 | } | |
116 | ||
117 | - (NSString *) bbsnum { | |
118 | return (id) CYHex((NSData *) CYIOGetValue("IOService:/AppleARMPE/baseband", @"snum"), false) ?: [NSNull null]; | |
119 | } | |
120 | ||
121 | - (NSString *) build { | |
122 | return [NSString stringWithUTF8String:System_]; | |
123 | } | |
124 | ||
125 | - (NSString *) coreFoundationVersionNumber { | |
126 | return [NSString stringWithFormat:@"%.2f", kCFCoreFoundationVersionNumber]; | |
127 | } | |
128 | ||
129 | - (NSString *) ecid { | |
130 | return (id) [CYHex((NSData *) CYIOGetValue("IODeviceTree:/chosen", @"unique-chip-id"), true) uppercaseString] ?: [NSNull null]; | |
131 | } | |
132 | ||
133 | - (NSString *) firmware { | |
134 | return [[UIDevice currentDevice] systemVersion]; | |
135 | } | |
136 | ||
137 | - (NSString *) hostname { | |
138 | return [[UIDevice currentDevice] name]; | |
139 | } | |
140 | ||
141 | - (NSString *) idiom { | |
142 | return IsWildcat_ ? @"ipad" : @"iphone"; | |
143 | } | |
144 | ||
145 | - (NSString *) model { | |
146 | return [NSString stringWithUTF8String:Machine_]; | |
147 | } | |
148 | ||
149 | - (NSString *) serial { | |
150 | return (NSString *) CYIOGetValue("IOService:/", @"IOPlatformSerialNumber"); | |
151 | } | |
152 | ||
153 | ||
154 | + (NSString *) webScriptNameForSelector:(SEL)selector { | |
155 | if (false); | |
156 | else if (selector == @selector(addInternalRedirect::)) | |
157 | return @"addInternalRedirect"; | |
158 | else if (selector == @selector(close)) | |
159 | return @"close"; | |
160 | else if (selector == @selector(stringWithFormat:arguments:)) | |
161 | return @"format"; | |
162 | else if (selector == @selector(getIORegistryEntry::)) | |
163 | return @"getIORegistryEntry"; | |
164 | else if (selector == @selector(getKernelNumber:)) | |
165 | return @"getKernelNumber"; | |
166 | else if (selector == @selector(getKernelString:)) | |
167 | return @"getKernelString"; | |
168 | else if (selector == @selector(getLocaleIdentifier)) | |
169 | return @"getLocaleIdentifier"; | |
170 | else if (selector == @selector(getPreferredLanguages)) | |
171 | return @"getPreferredLanguages"; | |
172 | else if (selector == @selector(isReachable:)) | |
173 | return @"isReachable"; | |
174 | else if (selector == @selector(localizedStringForKey:value:table:)) | |
175 | return @"localize"; | |
176 | else if (selector == @selector(popViewController:)) | |
177 | return @"popViewController"; | |
178 | else if (selector == @selector(registerFrame:)) | |
179 | return @"registerFrame"; | |
180 | else if (selector == @selector(removeButton)) | |
181 | return @"removeButton"; | |
182 | else if (selector == @selector(scrollToBottom:)) | |
183 | return @"scrollToBottom"; | |
184 | else if (selector == @selector(setAllowsNavigationAction:)) | |
185 | return @"setAllowsNavigationAction"; | |
186 | else if (selector == @selector(setBadgeValue:)) | |
187 | return @"setBadgeValue"; | |
188 | else if (selector == @selector(setButtonImage:withStyle:toFunction:)) | |
189 | return @"setButtonImage"; | |
190 | else if (selector == @selector(setButtonTitle:withStyle:toFunction:)) | |
191 | return @"setButtonTitle"; | |
192 | else if (selector == @selector(setHidesBackButton:)) | |
193 | return @"setHidesBackButton"; | |
194 | else if (selector == @selector(setHidesNavigationBar:)) | |
195 | return @"setHidesNavigationBar"; | |
196 | else if (selector == @selector(setNavigationBarStyle:)) | |
197 | return @"setNavigationBarStyle"; | |
198 | else if (selector == @selector(setNavigationBarTintRed:green:blue:alpha:)) | |
199 | return @"setNavigationBarTintColor"; | |
200 | else if (selector == @selector(setPasteboardString:)) | |
201 | return @"setPasteboardString"; | |
202 | else if (selector == @selector(setPasteboardURL:)) | |
203 | return @"setPasteboardURL"; | |
204 | else if (selector == @selector(setScrollAlwaysBounceVertical:)) | |
205 | return @"setScrollAlwaysBounceVertical"; | |
206 | else if (selector == @selector(setScrollIndicatorStyle:)) | |
207 | return @"setScrollIndicatorStyle"; | |
208 | else if (selector == @selector(setViewportWidth:)) | |
209 | return @"setViewportWidth"; | |
210 | else if (selector == @selector(statfs:)) | |
211 | return @"statfs"; | |
212 | else if (selector == @selector(supports:)) | |
213 | return @"supports"; | |
214 | else if (selector == @selector(unload)) | |
215 | return @"unload"; | |
216 | else | |
217 | return nil; | |
218 | } | |
219 | ||
220 | + (BOOL) isSelectorExcludedFromWebScript:(SEL)selector { | |
221 | return [self webScriptNameForSelector:selector] == nil; | |
222 | } | |
223 | ||
224 | - (void) addInternalRedirect:(NSString *)from :(NSString *)to { | |
225 | [CyteWebViewController performSelectorOnMainThread:@selector(addDiversion:) withObject:[[[Diversion alloc] initWithFrom:from to:to] autorelease] waitUntilDone:NO]; | |
226 | } | |
227 | ||
228 | - (void) close { | |
229 | [indirect_ performSelectorOnMainThread:@selector(close) withObject:nil waitUntilDone:NO]; | |
230 | } | |
231 | ||
232 | - (NSString *) getKernelString:(NSString *)name { | |
233 | const char *string([name UTF8String]); | |
234 | ||
235 | size_t size; | |
236 | if (sysctlbyname(string, NULL, &size, NULL, 0) == -1) | |
237 | return (id) [NSNull null]; | |
238 | ||
239 | char value[size + 1]; | |
240 | if (sysctlbyname(string, value, &size, NULL, 0) == -1) | |
241 | return (id) [NSNull null]; | |
242 | ||
243 | // XXX: just in case you request something ludicrous | |
244 | value[size] = '\0'; | |
245 | ||
246 | return [NSString stringWithCString:value]; | |
247 | } | |
248 | ||
249 | - (NSObject *) getIORegistryEntry:(NSString *)path :(NSString *)entry { | |
250 | NSObject *value(CYIOGetValue([path UTF8String], entry)); | |
251 | ||
252 | if (value != nil) | |
253 | if ([value isKindOfClass:[NSData class]]) | |
254 | value = CYHex((NSData *) value); | |
255 | ||
256 | return value; | |
257 | } | |
258 | ||
259 | - (NSString *) getLocaleIdentifier { | |
260 | _H<const __CFLocale> locale(CFLocaleCopyCurrent(), true); | |
261 | return locale == NULL ? (NSString *) [NSNull null] : (NSString *) CFLocaleGetIdentifier(locale); | |
262 | } | |
263 | ||
264 | - (NSArray *) getPreferredLanguages { | |
265 | return [NSLocale preferredLanguages]; | |
266 | } | |
267 | ||
268 | - (NSNumber *) isReachable:(NSString *)name { | |
269 | return [NSNumber numberWithBool:CyteIsReachable([name UTF8String])]; | |
270 | } | |
271 | ||
272 | - (NSString *) localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)table { | |
273 | if (reinterpret_cast<id>(value) == [WebUndefined undefined]) | |
274 | value = nil; | |
275 | if (reinterpret_cast<id>(table) == [WebUndefined undefined]) | |
276 | table = nil; | |
277 | return [[NSBundle mainBundle] localizedStringForKey:key value:value table:table]; | |
278 | } | |
279 | ||
280 | - (void) popViewController:(NSNumber *)value { | |
281 | if (value == (id) [WebUndefined undefined]) | |
282 | value = [NSNumber numberWithBool:YES]; | |
283 | [indirect_ performSelectorOnMainThread:@selector(popViewControllerWithNumber:) withObject:value waitUntilDone:NO]; | |
284 | } | |
285 | ||
286 | - (void) registerFrame:(DOMHTMLIFrameElement *)iframe { | |
287 | WebFrame *frame([iframe contentFrame]); | |
288 | [indirect_ registerFrame:frame]; | |
289 | } | |
290 | ||
291 | - (void) removeButton { | |
292 | [indirect_ removeButton]; | |
293 | } | |
294 | ||
295 | - (void) scrollToBottom:(NSNumber *)animated { | |
296 | [indirect_ performSelectorOnMainThread:@selector(scrollToBottomAnimated:) withObject:animated waitUntilDone:NO]; | |
297 | } | |
298 | ||
299 | - (void) setAllowsNavigationAction:(NSString *)value { | |
300 | [indirect_ performSelectorOnMainThread:@selector(setAllowsNavigationActionByNumber:) withObject:value waitUntilDone:NO]; | |
301 | } | |
302 | ||
303 | - (void) setBadgeValue:(id)value { | |
304 | [indirect_ performSelectorOnMainThread:@selector(setBadgeValue:) withObject:value waitUntilDone:NO]; | |
305 | } | |
306 | ||
307 | - (void) setButtonImage:(NSString *)button withStyle:(NSString *)style toFunction:(id)function { | |
308 | [indirect_ setButtonImage:button withStyle:style toFunction:function]; | |
309 | } | |
310 | ||
311 | - (void) setButtonTitle:(NSString *)button withStyle:(NSString *)style toFunction:(id)function { | |
312 | [indirect_ setButtonTitle:button withStyle:style toFunction:function]; | |
313 | } | |
314 | ||
315 | - (void) setHidesBackButton:(NSString *)value { | |
316 | [indirect_ performSelectorOnMainThread:@selector(setHidesBackButtonByNumber:) withObject:value waitUntilDone:NO]; | |
317 | } | |
318 | ||
319 | - (void) setHidesNavigationBar:(NSString *)value { | |
320 | [indirect_ performSelectorOnMainThread:@selector(setHidesNavigationBarByNumber:) withObject:value waitUntilDone:NO]; | |
321 | } | |
322 | ||
323 | - (void) setNavigationBarStyle:(NSString *)value { | |
324 | [indirect_ performSelectorOnMainThread:@selector(setNavigationBarStyle:) withObject:value waitUntilDone:NO]; | |
325 | } | |
326 | ||
327 | - (void) setNavigationBarTintRed:(NSNumber *)red green:(NSNumber *)green blue:(NSNumber *)blue alpha:(NSNumber *)alpha { | |
328 | float opacity(alpha == (id) [WebUndefined undefined] ? 1 : [alpha floatValue]); | |
329 | UIColor *color([UIColor colorWithRed:[red floatValue] green:[green floatValue] blue:[blue floatValue] alpha:opacity]); | |
330 | [indirect_ performSelectorOnMainThread:@selector(setNavigationBarTintColor:) withObject:color waitUntilDone:NO]; | |
331 | } | |
332 | ||
333 | - (void) setPasteboardString:(NSString *)value { | |
334 | [[objc_getClass("UIPasteboard") generalPasteboard] setString:value]; | |
335 | } | |
336 | ||
337 | - (void) setPasteboardURL:(NSString *)value { | |
338 | [[objc_getClass("UIPasteboard") generalPasteboard] setURL:[NSURL URLWithString:value]]; | |
339 | } | |
340 | ||
341 | - (void) setScrollAlwaysBounceVertical:(NSNumber *)value { | |
342 | [indirect_ performSelectorOnMainThread:@selector(setScrollAlwaysBounceVerticalNumber:) withObject:value waitUntilDone:NO]; | |
343 | } | |
344 | ||
345 | - (void) setScrollIndicatorStyle:(NSString *)style { | |
346 | [indirect_ performSelectorOnMainThread:@selector(setScrollIndicatorStyleWithName:) withObject:style waitUntilDone:NO]; | |
347 | } | |
348 | ||
349 | - (void) setViewportWidth:(float)width { | |
350 | [indirect_ setViewportWidthOnMainThread:width]; | |
351 | } | |
352 | ||
353 | - (NSArray *) statfs:(NSString *)path { | |
354 | struct statfs stat; | |
355 | ||
356 | if (path == nil || statfs([path UTF8String], &stat) == -1) | |
357 | return nil; | |
358 | ||
359 | return [NSArray arrayWithObjects: | |
360 | [NSNumber numberWithUnsignedLong:stat.f_bsize], | |
361 | [NSNumber numberWithUnsignedLong:stat.f_blocks], | |
362 | [NSNumber numberWithUnsignedLong:stat.f_bfree], | |
363 | nil]; | |
364 | } | |
365 | ||
366 | - (NSString *) stringWithFormat:(NSString *)format arguments:(WebScriptObject *)arguments { | |
367 | //NSLog(@"SWF:\"%@\" A:%@", format, [arguments description]); | |
368 | unsigned count([arguments count]); | |
369 | id values[count]; | |
370 | for (unsigned i(0); i != count; ++i) | |
371 | values[i] = [arguments objectAtIndex:i]; | |
372 | return [[[NSString alloc] initWithFormat:format arguments:reinterpret_cast<va_list>(values)] autorelease]; | |
373 | } | |
374 | ||
375 | - (BOOL) supports:(NSString *)feature { | |
376 | return [feature isEqualToString:@"window.open"]; | |
377 | } | |
378 | ||
379 | - (void) unload { | |
380 | [[indirect_ rootViewController] performSelectorOnMainThread:@selector(unloadData) withObject:nil waitUntilDone:NO]; | |
381 | } | |
382 | ||
383 | @end |