Merged [18119] and [18120] which brings joscar to r 484, fixing rate limiting and...
[adiumx.git] / Other / SystemVersionCheck.m
blobc6bbbb23db772b6b390eae9b010d478af16ff86f
1 //
2 //  SystemVersionCheck.m
3 //  SystemVersionCheck
4 //
5 //  Created by Chris Campbell on 12/03/2005.
6 //  Copyright Big Nerd Ranch 2005. All rights reserved.
7 //
9 #import <Foundation/Foundation.h>
10 #import <AppKit/AppKit.h>
12 #include <stdlib.h>
13 #include <unistd.h>
15 static void GetVersionComponentsFromString(int *majorPtr, int *minorPtr, int *bugfixPtr, NSString *versionString)
17     int major = 0;
18     int minor = 0;
19     int bugfix = 0;
20     
21     NSArray *array = [versionString componentsSeparatedByString:@"."];
22     
23     if ([array count] > 0) {
24         major = [[array objectAtIndex:0] intValue];
25         
26         if ([array count] > 1) {
27             minor = [[array objectAtIndex:1] intValue];
28             
29             if ([array count] > 2) {
30                 bugfix = [[array objectAtIndex:2] intValue];
31             }
32         }
33     }
34     
35     if (majorPtr != NULL) {
36         *majorPtr = major;
37     }
38     
39     if (minorPtr != NULL) {
40         *minorPtr = minor;
41     }
42     
43     if (bugfixPtr != NULL) {
44         *bugfixPtr = bugfix;
45     }
48 static BOOL CheckSystemVersion(NSString **requiredVersionPtr, BOOL *sameMajorMinorPtr)
50     // Determine the required version
51             
52     NSString *requiredVersion = [[[[NSBundle mainBundle] infoDictionary] objectForKey:@"LSEnvironment"] objectForKey:@"MinimumSystemVersion"];
53     
54     if ([requiredVersion length] == 0) {
55         requiredVersion = @"10.3.9";
56     }
57     
58     if (requiredVersionPtr != NULL) {
59         *requiredVersionPtr = requiredVersion;
60     }
61     
62     int requiredMajor, requiredMinor, requiredBugfix;
63     GetVersionComponentsFromString(&requiredMajor, &requiredMinor, &requiredBugfix, requiredVersion);
64     
65     // Determine the system version
66     
67     NSString *systemVersion = [[NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"] objectForKey:@"ProductVersion"];    
68     
69     if ([systemVersion length] == 0) {
70         // Can't parse the system version
71         if (sameMajorMinorPtr != NULL) {
72             *sameMajorMinorPtr = NO;
73             return NO;
74         }
75     }
76     
77     int systemMajor, systemMinor, systemBugfix;
78     GetVersionComponentsFromString(&systemMajor, &systemMinor, &systemBugfix, systemVersion);
79     
80     if (sameMajorMinorPtr != NULL) {
81         *sameMajorMinorPtr = (systemMajor == requiredMajor && systemMinor == requiredMinor);
82     }
83     
84     if (systemMajor < requiredMajor) {
85         return NO;
86     } else if (systemMajor > requiredMajor) {
87         return YES;
88     }
89     
90     // systemMajor == requiredMajor...
91     
92     if (systemMinor < requiredMinor) {
93         return NO;
94     } else if (systemMinor > requiredMinor) {
95         return YES;
96     }
97     
98     // systemMinor == requiredMinor...
99     
100     if (systemBugfix < requiredBugfix) {
101         return NO;
102     }
103     
104     // syhsemBugfix >= requiredBugfix...
105     
106     return YES;
109 static NSString *LocalizedInfoStringForKey(NSString *key)
111     // First, look for an InfoPlist.strings entry
112     
113     NSBundle *bundle = [NSBundle mainBundle];
114     
115     NSString *value = [bundle localizedStringForKey:key value:nil table:@"InfoPlist"];
117     if (key != value) {
118         return value;
119     }
120     
121     // Otherwise, look in the Info.plist file
122     
123     return [[bundle infoDictionary] objectForKey:key];
126 static NSString *LocalizedApplicationName()
128     NSString *value = LocalizedInfoStringForKey(@"CFBundleDisplayName");
130     if (!value) {
131         value = LocalizedInfoStringForKey(@"CFBundleName");
132     }
133     
134     return value;
137 int main(int argc, char *argv[])
139     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
140     
141     // Grab the executable name from the Info.plist.
142     // If there isn't one, error out and exit
143     
144     NSString *executableName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleExecutable"];
145     
146     if (!executableName) {
147         fprintf(stderr, "ERROR: %s must be run from inside a .app wrapper\n", argv[0]);
148         return EXIT_FAILURE;
149     }
150     
151     NSString *requiredVersion;
152     BOOL sameMajorMinor;
153     BOOL canLaunch = CheckSystemVersion(&requiredVersion, &sameMajorMinor);
154     
155     if (!canLaunch) {
156                 
157         NSString *applicationName = LocalizedApplicationName();
158         
159         // Use the name of the application as the alert window's title
160         
161         NSString *windowTitle = applicationName;
162         if ([windowTitle length] == 0) {
163             windowTitle = @"";
164         }
165         
166         if ([applicationName length] == 0) {
167             applicationName = @"This application";
168         }
169         
170         NSString *title = [NSString stringWithFormat:@"%@ requires Mac OS X %@ or later", applicationName, requiredVersion];
171         
172         NSString *messageFormat;
173         NSString *defaultButton;
174         NSString *alternateButton;
175         if (sameMajorMinor) {
176             messageFormat = @"Please use Software Update to upgrade to Mac OS X %@ or later.\n";
177             defaultButton = @"Open Software Update";
178             alternateButton = @"Quit";
179         } else {
180             messageFormat = @"Please install Mac OS X %@ or later.\n";
181             defaultButton = @"Quit";
182             alternateButton = nil;
183         }
184         
185         // Load NSApplication and all the GUI stuff
186         
187         [NSApplication sharedApplication];
188         
189         NSPanel *alertPanel = NSGetAlertPanel(title, messageFormat, defaultButton, alternateButton, nil, requiredVersion);
190         [alertPanel setTitle:windowTitle];
191         
192         int choice = [NSApp runModalForWindow:alertPanel];
193         
194         NSReleaseAlertPanel(alertPanel);
195         alertPanel = nil;
196         
197         if (sameMajorMinor && choice == NSAlertDefaultReturn) {
198             // Open Software Update
199             [[NSWorkspace sharedWorkspace] openFile:@"/System/Library/CoreServices/Software Update.app"];
200         }
201         
202         return EXIT_SUCCESS;
203         
204     }
205         
206     // Get the path of the real executable
207     
208     NSString *path = [[NSBundle mainBundle] pathForAuxiliaryExecutable:[NSString stringWithFormat:@"%@.real", executableName]];
209     
210     if (!path) {
211         return EXIT_FAILURE;
212     }
213     
214     // Construct a new argv array for the exec'ed process
215     
216     NSMutableData *argvData = [[NSMutableData alloc] initWithBytes:argv length:(argc * sizeof(*argv))];
217     
218     // Change the first argument to the path of the new executable
219     
220     ((const char **)[argvData mutableBytes])[0] = [path UTF8String];
222     // Append a NULL char* to the end of the array
223     
224     char *nullPtr = NULL;
225     
226     [argvData appendBytes:&nullPtr length:sizeof(nullPtr)];
227     [pool release];
229         pool = [[NSAutoreleasePool alloc] init];
230     execv(((const char **)[argvData bytes])[0], (char * const *)[argvData bytes]);
231     
232     // This should never be reached
233         
234     [argvData release];
235     argvData = nil;
236         
237     [pool release];
238     pool = nil;
239     
240     return EXIT_FAILURE;