Changeset 273
- Timestamp:
- 01/08/07 12:36:33 (2 years ago)
- Files:
-
- trunk/CPFPerianPrefPaneController.h (modified) (3 diffs)
- trunk/CPFPerianPrefPaneController.m (modified) (24 diffs)
- trunk/PerianPrefPane.nib/keyedobjects.nib (modified) (previous)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/CPFPerianPrefPaneController.h
r247 r273 3 3 #import <Cocoa/Cocoa.h> 4 4 #import <PreferencePanes/NSPreferencePane.h> 5 #import <Security/Security.h> 5 6 6 7 #define ComponentInfoDictionaryKey @"Components" … … 12 13 typedef enum 13 14 { 14 InstallStatusNotInstalled, 15 InstallStatusOutdated, 16 InstallStatusInstalled 15 InstallStatusInstalledInWrongLocation = 0, 16 InstallStatusNotInstalled = 1, 17 InstallStatusOutdatedWithAnotherInWrongLocation = 2, 18 InstallStatusOutdated = 3, 19 InstallStatusInstalledInBothLocations = 4, 20 InstallStatusInstalled = 5 17 21 } InstallStatus; 22 23 InstallStatus inline currentInstallStatus(InstallStatus status) 24 { 25 return (status | 1); 26 } 27 28 BOOL inline isWrongLocationInstalled(InstallStatus status) 29 { 30 return ((status & 1) == 0); 31 } 32 33 InstallStatus inline setWrongLocationInstalled(InstallStatus status) 34 { 35 return (status & ~1); 36 } 18 37 19 38 typedef enum … … 47 66 48 67 InstallStatus installStatus; //This is only marked as installed if everything is installed 68 BOOL userInstalled; 69 AuthorizationRef auth; 70 NSMutableString *errorString; 49 71 50 72 NSURL *perianForumURL; trunk/CPFPerianPrefPaneController.m
r250 r273 1 1 #import "CPFPerianPrefPaneController.h" 2 #import <Security/Security.h>3 2 #include <sys/stat.h> 4 3 … … 31 30 } 32 31 33 - (BOOL)systemInstalled 34 { 35 NSString *myPath = [[self bundle] bundlePath]; 36 37 if([myPath hasPrefix:NSHomeDirectory()]) 38 return NO; 39 return YES; 40 } 41 42 - (NSString *)quickTimeComponentDir 43 { 44 NSString *basePath = nil; 45 46 if(![self systemInstalled]) 47 basePath = NSHomeDirectory(); 48 else 49 basePath = [NSString stringWithString:@"/"]; 50 51 return [basePath stringByAppendingPathComponent:@"Library/QuickTime"]; 52 } 53 54 - (NSString *)coreAudioComponentDir 55 { 56 NSString *basePath = nil; 57 58 if(![self systemInstalled]) 59 basePath = NSHomeDirectory(); 60 else 61 basePath = [NSString stringWithString:@"/"]; 62 63 return [basePath stringByAppendingPathComponent:@"Library/Audio/Plug-Ins/Components"]; 64 } 65 66 - (NSString *)frameworkComponentDir 67 { 68 NSString *basePath = nil; 69 70 if(![self systemInstalled]) 71 basePath = NSHomeDirectory(); 72 else 73 basePath = [NSString stringWithString:@"/"]; 74 75 return [basePath stringByAppendingPathComponent:@"Library/Frameworks"]; 76 } 77 78 - (InstallStatus)installStatusForComponent:(NSString *)component type:(ComponentType)type withMyVersion:(NSString *)myVersion 32 - (NSString *)installationBasePath:(BOOL)userInstallation 33 { 34 if(userInstallation) 35 return NSHomeDirectory(); 36 return [NSString stringWithString:@"/"]; 37 } 38 39 - (NSString *)quickTimeComponentDir:(BOOL)userInstallation 40 { 41 return [[self installationBasePath:userInstallation] stringByAppendingPathComponent:@"Library/QuickTime"]; 42 } 43 44 - (NSString *)coreAudioComponentDir:(BOOL)userInstallation 45 { 46 return [[self installationBasePath:userInstallation] stringByAppendingPathComponent:@"Library/Audio/Plug-Ins/Components"]; 47 } 48 49 - (NSString *)frameworkComponentDir:(BOOL)userInstallation 50 { 51 return [[self installationBasePath:userInstallation] stringByAppendingPathComponent:@"Library/Frameworks"]; 52 } 53 54 - (NSString *)basePathForType:(ComponentType)type user:(BOOL)userInstallation 79 55 { 80 56 NSString *path = nil; … … 83 59 { 84 60 case ComponentTypeCoreAudio: 85 path = [self coreAudioComponentDir ];61 path = [self coreAudioComponentDir:userInstallation]; 86 62 break; 87 63 case ComponentTypeQuickTime: 88 path = [self quickTimeComponentDir ];64 path = [self quickTimeComponentDir:userInstallation]; 89 65 break; 90 66 case ComponentTypeFramework: 91 path = [self frameworkComponentDir ];67 path = [self frameworkComponentDir:userInstallation]; 92 68 break; 93 69 } 94 path = [path stringByAppendingPathComponent:component]; 70 return path; 71 } 72 73 - (InstallStatus)installStatusForComponent:(NSString *)component type:(ComponentType)type withMyVersion:(NSString *)myVersion 74 { 75 NSString *path = nil; 76 InstallStatus ret = InstallStatusNotInstalled; 77 78 path = [[self basePathForType:type user:userInstalled] stringByAppendingPathComponent:component]; 95 79 96 80 NSDictionary *infoDict = [NSDictionary dictionaryWithContentsOfFile:[path stringByAppendingPathComponent:@"Contents/Info.plist"]]; 81 if(infoDict != nil) 82 { 83 NSString *currentVersion = [infoDict objectForKey:BundleVersionKey]; 84 if([currentVersion compare:myVersion] == NSOrderedAscending) 85 ret = InstallStatusOutdated; 86 87 ret = InstallStatusInstalled; 88 } 89 90 /* Check other installation type */ 91 path = [[self basePathForType:type user:!userInstalled] stringByAppendingPathComponent:component]; 92 93 infoDict = [NSDictionary dictionaryWithContentsOfFile:[path stringByAppendingPathComponent:@"Contents/Info.plist"]]; 97 94 if(infoDict == nil) 98 return InstallStatusNotInstalled; 99 100 NSString *currentVersion = [infoDict objectForKey:BundleVersionKey]; 101 if([currentVersion compare:myVersion] == NSOrderedAscending) 102 return InstallStatusOutdated; 103 104 return InstallStatusInstalled; 95 /* Above result is all there is */ 96 return ret; 97 98 return setWrongLocationInstalled(ret); 105 99 } 106 100 … … 116 110 perianAppID = CFSTR("org.perian.perian"); 117 111 a52AppID = CFSTR("com.cod3r.a52codec"); 112 113 NSString *myPath = [[self bundle] bundlePath]; 114 115 if([myPath hasPrefix:@"/Library"]) 116 userInstalled = NO; 117 else 118 userInstalled = YES; 118 119 } 119 120 … … 125 126 NSDictionary *infoDict = [[self bundle] infoDictionary]; 126 127 installStatus = [self installStatusForComponent:@"Perian.component" type:ComponentTypeQuickTime withMyVersion:[infoDict objectForKey:BundleVersionKey]]; 127 if( installStatus== InstallStatusNotInstalled)128 if(currentInstallStatus(installStatus) == InstallStatusNotInstalled) 128 129 { 129 130 [textField_installStatus setStringValue:NSLocalizedString(@"Perian is not Installed", @"")]; 130 131 [button_install setTitle:NSLocalizedString(@"Install Perian", @"")]; 131 132 } 132 else if( installStatus== InstallStatusOutdated)133 else if(currentInstallStatus(installStatus) == InstallStatusOutdated) 133 134 { 134 135 [textField_installStatus setStringValue:NSLocalizedString(@"Perian is Installed, but Outdated", @"")]; … … 151 152 switch(installStatus) 152 153 { 154 case InstallStatusInstalledInWrongLocation: 153 155 case InstallStatusNotInstalled: 154 156 [textField_installStatus setStringValue:NSLocalizedString(@"Perian is Installed, but parts are Not Installed", @"")]; 155 157 [button_install setTitle:NSLocalizedString(@"Install Perian", @"")]; 156 158 break; 159 case InstallStatusOutdatedWithAnotherInWrongLocation: 157 160 case InstallStatusOutdated: 158 161 [textField_installStatus setStringValue:NSLocalizedString(@"Perian is Installed, but parts are Outdated", @"")]; 159 162 [button_install setTitle:NSLocalizedString(@"Update Perian", @"")]; 163 break; 164 case InstallStatusInstalledInBothLocations: 165 [textField_installStatus setStringValue:NSLocalizedString(@"Perian is Installed Twice", @"")]; 166 [button_install setTitle:NSLocalizedString(@"Correct Installation", @"")]; 160 167 break; 161 168 case InstallStatusInstalled: … … 165 172 } 166 173 } 174 else if(isWrongLocationInstalled(installStatus)) 175 { 176 [textField_installStatus setStringValue:NSLocalizedString(@"Perian is Installed Twice", @"")]; 177 [button_install setTitle:NSLocalizedString(@"Correct Installation", @"")]; 178 } 167 179 else 168 180 { … … 194 206 [perianDonateURL release]; 195 207 [perianWebSiteURL release]; 208 if(auth != nil) 209 AuthorizationFree(auth, 0); 210 [errorString release]; 196 211 [super dealloc]; 197 212 } … … 205 220 struct stat sb; 206 221 if(stat([destination fileSystemRepresentation], &sb) != 0) 222 { 223 [errorString appendFormat:NSLocalizedString(@"No such directory %@\n", @""), destination]; 207 224 return FALSE; 225 } 208 226 209 227 char *buf = NULL; … … 211 229 "ditto -x -k --rsrc \"$SRC_ARCHIVE\" \"$DST_PATH\""); 212 230 if(!buf) 231 { 232 [errorString appendFormat:NSLocalizedString(@"Could not allocate memory for extraction command\n", @"")]; 213 233 return FALSE; 234 } 214 235 215 236 setenv("SRC_ARCHIVE", [archivePath fileSystemRepresentation], 1); … … 219 240 if(WIFEXITED(status) && WEXITSTATUS(status) == 0) 220 241 ret = YES; 242 else 243 [errorString appendFormat:NSLocalizedString(@"Extraction for %@ failed\n", @""), archivePath]; 221 244 222 245 free(buf); … … 226 249 } 227 250 228 - (BOOL)_authenticatedExtractArchivePath:(NSString *)archivePath toDestination:(NSString *)destination finalPath:(NSString *)finalPath authorization:(AuthorizationRef)auth251 - (BOOL)_authenticatedExtractArchivePath:(NSString *)archivePath toDestination:(NSString *)destination finalPath:(NSString *)finalPath 229 252 { 230 253 BOOL ret = NO, oldExist = NO; … … 234 257 235 258 if(stat([destination fileSystemRepresentation], &sb) != 0) 259 { 260 [errorString appendFormat:NSLocalizedString(@"No such directory %@\n", @""), destination]; 236 261 return FALSE; 262 } 237 263 238 264 char *buf = NULL; … … 250 276 sb.st_uid, sb.st_gid); 251 277 if(!buf) 278 { 279 [errorString appendFormat:NSLocalizedString(@"Could not allocate memory for extraction command\n", @"")]; 252 280 return FALSE; 281 } 253 282 254 283 setenv("SRC_ARCHIVE", [archivePath fileSystemRepresentation], 1); … … 264 293 if(pid != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0) 265 294 ret = YES; 266 } 295 else 296 [errorString appendFormat:NSLocalizedString(@"Extraction for %@ failed\n", @""), archivePath]; 297 } 298 else 299 [errorString appendFormat:NSLocalizedString(@"Authentication failed for extraction for %@\n", @""), archivePath]; 300 267 301 free(buf); 268 302 unsetenv("SRC_ARCHIVE"); … … 273 307 } 274 308 275 - (BOOL)_authenticatedRemove:(NSString *)componentPath authorization:(AuthorizationRef)auth309 - (BOOL)_authenticatedRemove:(NSString *)componentPath 276 310 { 277 311 BOOL ret = NO; 278 312 struct stat sb; 279 313 if(stat([componentPath fileSystemRepresentation], &sb) != 0) 314 /* No error, just forget it */ 280 315 return FALSE; 281 316 … … 284 319 "rm -rf \"$COMP_PATH\""); 285 320 if(!buf) 321 { 322 [errorString appendFormat:NSLocalizedString(@"Could not allocate memory for removal command\n", @"")]; 286 323 return FALSE; 324 } 287 325 288 326 setenv("COMP_PATH", [componentPath fileSystemRepresentation], 1); … … 295 333 if(pid != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0) 296 334 ret = YES; 297 } 335 else 336 [errorString appendFormat:NSLocalizedString(@"Removal for %@ failed\n", @""), componentPath]; 337 } 338 else 339 [errorString appendFormat:NSLocalizedString(@"Authentication failed for removal for %@\n", @""), componentPath]; 298 340 free(buf); 299 341 unsetenv("COMP_PATH"); … … 302 344 303 345 304 - (BOOL)installArchive:(NSString *)archivePath forPiece:(NSString *)component type:(ComponentType)type withMyVersion:(NSString *)myVersion andAuthorization:(AuthorizationRef)auth 305 { 306 NSString *containingDir = nil; 307 switch(type) 308 { 309 case ComponentTypeCoreAudio: 310 containingDir = [self coreAudioComponentDir]; 311 break; 312 case ComponentTypeQuickTime: 313 containingDir = [self quickTimeComponentDir]; 314 break; 315 case ComponentTypeFramework: 316 containingDir = [self frameworkComponentDir]; 317 break; 318 } 346 - (BOOL)installArchive:(NSString *)archivePath forPiece:(NSString *)component type:(ComponentType)type withMyVersion:(NSString *)myVersion 347 { 348 NSString *containingDir = [self basePathForType:type user:userInstalled]; 349 BOOL ret = YES; 350 319 351 InstallStatus pieceStatus = [self installStatusForComponent:component type:type withMyVersion:myVersion]; 320 if( auth != nil && pieceStatus!= InstallStatusInstalled)321 { 322 BOOL result = [self _authenticatedExtractArchivePath:archivePath toDestination:containingDir finalPath:[containingDir stringByAppendingPathComponent:component] authorization:auth];352 if(!userInstalled && currentInstallStatus(pieceStatus) != InstallStatusInstalled) 353 { 354 BOOL result = [self _authenticatedExtractArchivePath:archivePath toDestination:containingDir finalPath:[containingDir stringByAppendingPathComponent:component]]; 323 355 if(result == NO) 324 ret urnNO;356 ret = NO; 325 357 } 326 358 else 327 359 { 328 360 //Not authenticated 329 if( pieceStatus== InstallStatusOutdated)361 if(currentInstallStatus(pieceStatus) == InstallStatusOutdated) 330 362 { 331 363 //Remove the old one here … … 333 365 BOOL result = [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:containingDir destination:@"" files:[NSArray arrayWithObject:component] tag:&tag]; 334 366 if(result == NO) 335 ret urnNO;367 ret = NO; 336 368 } 337 if( pieceStatus!= InstallStatusInstalled)369 if(currentInstallStatus(pieceStatus) != InstallStatusInstalled) 338 370 { 339 371 //Decompress and install new one 340 372 BOOL result = [self _extractArchivePath:archivePath toDestination:containingDir]; 341 373 if(result == NO) 342 ret urnNO;374 ret = NO; 343 375 } 344 376 } 345 return YES; 377 if(ret != NO && isWrongLocationInstalled(pieceStatus) != 0) 378 { 379 /* Let's try and remove the wrong one, if we can, but only if install succeeded */ 380 containingDir = [self basePathForType:type user:!userInstalled]; 381 382 if(userInstalled) 383 [self _authenticatedRemove:[containingDir stringByAppendingPathComponent:component]]; 384 else 385 { 386 int tag = 0; 387 [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:containingDir destination:@"" files:[NSArray arrayWithObject:component] tag:&tag]; 388 } 389 } 390 return ret; 346 391 } 347 392 … … 355 400 NSString *quickTimeComponentPath = [componentPath stringByAppendingPathComponent:@"QuickTime"]; 356 401 NSString *frameworkComponentPath = [componentPath stringByAppendingPathComponent:@"Frameworks"]; 357 AuthorizationRef auth = nil; 358 359 if([self systemInstalled]) 360 { 361 if(!AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &auth) == errAuthorizationSuccess) 362 // Try it anyway, it will likely fail, but who knows what kind of screwed up systems people have 363 auth = nil; 364 } 365 366 [self installArchive:[componentPath stringByAppendingPathComponent:@"Perian.zip"] forPiece:@"Perian.component" type:ComponentTypeQuickTime withMyVersion:[infoDict objectForKey:BundleVersionKey] andAuthorization:auth]; 402 403 [errorString release]; 404 errorString = [[NSMutableString alloc] init]; 405 /* This doesn't ask the user, so create it anyway. If we don't need it, no problem */ 406 if(AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &auth) != errAuthorizationSuccess) 407 /* Oh well, hope we don't need it */ 408 auth = nil; 409 410 [self installArchive:[componentPath stringByAppendingPathComponent:@"Perian.zip"] forPiece:@"Perian.component" type:ComponentTypeQuickTime withMyVersion:[infoDict objectForKey:BundleVersionKey]]; 367 411 368 412 NSEnumerator *componentEnum = [myComponentsInfo objectEnumerator]; … … 384 428 break; 385 429 } 386 [self installArchive:archivePath forPiece:[myComponent objectForKey:ComponentNameKey] type:type withMyVersion:[myComponent objectForKey:BundleVersionKey] andAuthorization:auth];430 [self installArchive:archivePath forPiece:[myComponent objectForKey:ComponentNameKey] type:type withMyVersion:[myComponent objectForKey:BundleVersionKey]]; 387 431 } 388 432 if(auth != nil) 433 { 389 434 AuthorizationFree(auth, 0); 435 auth = nil; 436 } 390 437 [self performSelectorOnMainThread:@selector(installComplete:) withObject:nil waitUntilDone:NO]; 391 438 [pool release]; … … 397 444 NSDictionary *infoDict = [[self bundle] infoDictionary]; 398 445 NSDictionary *myComponentsInfo = [infoDict objectForKey:ComponentInfoDictionaryKey]; 399 AuthorizationRef auth = nil; 400 401 if([self systemInstalled]) 402 { 403 if(!AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &auth) == errAuthorizationSuccess) 404 // Try it anyway, it will likely fail, but who knows what kind of screwed up systems people have 405 auth = nil; 406 } 446 447 [errorString release]; 448 errorString = [[NSMutableString alloc] init]; 449 /* This doesn't ask the user, so create it anyway. If we don't need it, no problem */ 450 if(AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &auth) != errAuthorizationSuccess) 451 /* Oh well, hope we don't need it */ 452 auth = nil; 407 453 408 454 int tag = 0; 409 455 BOOL result = NO; 410 456 if(auth != nil) 411 [self _authenticatedRemove:[[self quickTimeComponentDir ] stringByAppendingPathComponent:@"Perian.component"] authorization:auth];412 else 413 result = [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:[self quickTimeComponentDir ] destination:@"" files:[NSArray arrayWithObject:@"Perian.component"] tag:&tag];457 [self _authenticatedRemove:[[self quickTimeComponentDir:userInstalled] stringByAppendingPathComponent:@"Perian.component"]]; 458 else 459 result = [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:[self quickTimeComponentDir:userInstalled] destination:@"" files:[NSArray arrayWithObject:@"Perian.component"] tag:&tag]; 414 460 415 461 NSEnumerator *componentEnum = [myComponentsInfo objectEnumerator]; … … 418 464 { 419 465 ComponentType type = [[myComponent objectForKey:ComponentTypeKey] intValue]; 420 NSString *directory = nil; 421 switch(type) 422 { 423 case ComponentTypeCoreAudio: 424 directory = [self coreAudioComponentDir]; 425 break; 426 case ComponentTypeQuickTime: 427 directory = [self quickTimeComponentDir]; 428 break; 429 case ComponentTypeFramework: 430 directory = [self frameworkComponentDir]; 431 break; 432 } 466 NSString *directory = [self basePathForType:type user:userInstalled]; 433 467 if(auth != nil) 434 [self _authenticatedRemove:[directory stringByAppendingPathComponent:[myComponent objectForKey:ComponentNameKey]] authorization:auth];468 [self _authenticatedRemove:[directory stringByAppendingPathComponent:[myComponent objectForKey:ComponentNameKey]]]; 435 469 else 436 470 result = [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:directory destination:@"" files:[NSArray arrayWithObject:[myComponent objectForKey:ComponentNameKey]] tag:&tag]; 437 471 } 438 472 if(auth != nil) 473 { 439 474 AuthorizationFree(auth, 0); 475 auth = nil; 476 } 440 477 441 478 [self performSelectorOnMainThread:@selector(installComplete:) withObject:nil waitUntilDone:NO];
