diff options
Diffstat (limited to 'src/mumble/Overlay_macx.mm')
-rw-r--r-- | src/mumble/Overlay_macx.mm | 113 |
1 files changed, 110 insertions, 3 deletions
diff --git a/src/mumble/Overlay_macx.mm b/src/mumble/Overlay_macx.mm index 7a73ada1a..b077499d6 100644 --- a/src/mumble/Overlay_macx.mm +++ b/src/mumble/Overlay_macx.mm @@ -96,13 +96,120 @@ void Overlay::setActive(bool act) { static_cast<OverlayPrivateMac *>(d)->setActive(act); } +bool Overlay::supportsInstallableOverlay() { + return true; +} + bool Overlay::isInstalled() { - return false; + bool ret = false; + + // Get the path where we expect the overlay loader to be installed. + NSString *path = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MumbleOverlayLoaderBundle"]; + if (! path) { + qWarning("Overlay_macx: No MumbleOverlayLoaderPath specified in Info.plist. " + "Pretending overlay is already installed."); + return false; + } + + // Determine if the installed bundle is correctly installed (i.e. it's loadable) + NSBundle *bundle = [NSBundle bundleWithPath:path]; + return [bundle preflightAndReturnError:NULL]; } bool Overlay::needsUpgrade() { - return false; + // Get required version from our own Info.plist + NSUInteger reqVersion = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"MumbleOverlayLoaderRequiredVersion"] unsignedIntegerValue]; + + // Load the overlay loader bundle. + NSBundle *bundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"MumbleOverlayLoaderBundle"]]; + if (! bundle) { + qWarning("Overlay_macx: Unable to load the installed OSAX bundle. This shouldn't happen."); + return false; + } + + // Get its version. + NSUInteger curVersion = [[bundle objectForInfoDictionaryKey:@"MumbleOverlayLoaderVersion"] unsignedIntegerValue]; + + // If the two versions do not match up, we need to upgrade. + return curVersion != reqVersion; +} + +bool Overlay::installFiles() { + AuthorizationRef auth; + bool ret = false; + int pid, status; + OSStatus err; + + // Get the tarball that we should install. + NSString *tarballPath = [NSString stringWithFormat:@"%@/%@", [[NSBundle mainBundle] bundlePath], + [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MumbleOverlayInstallPayload"]]; + + // And the destination we should install it to. + NSString *destination = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MumbleOverlayInstallDestintaion"]; + + if (! tarballPath || ! destination) { + qWarning("Overlay_macx: Info.plist does not specify installation parameters."); + return false; + } + + // Request an AuthorizationRef. This is a mechanism in Mac OS X that allows a parent program + // to spawn child processes with euid = 0. + // + // When attempting to launch the child process, a dialog will pop up requesting the user to + // authorize the launch by logging in with as a user with admin privileges. + err = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &auth); + if (err == errAuthorizationSuccess) { + // This is the tar command that we execute to install our support files. + const char *argv[] = { "/usr/bin/tar", "-jxf", [tarballPath UTF8String], "-C", [destination UTF8String], NULL }; + // Launch the child process. + err = AuthorizationExecuteWithPrivileges(auth, argv[0], kAuthorizationFlagDefaults, const_cast<char * const *>(&argv[1]), NULL); + if (err == errAuthorizationSuccess) { + // And wait until it is dead. + do { + pid = wait(&status); + } while (pid == -1 && errno == EINTR); + ret = (pid != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0); + } else + qWarning("Overlay_macx: Failed to AuthorizeExecuteWithPrivileges. (err=%i)", err); + } else + qWarning("Overlay_macx: Failed to acquire AuthorizationRef. (err=%i)", err); + + if (! ret) { + qWarning("Overlay_macx: Failure in installer process. (pid=%i, exited=%u, exitStatus=%u)", + pid, WIFEXITED(status), WEXITSTATUS(status)); + } + + // Free the AuthorizationRef that we acquired earlier. We're done launching priviledged children. + AuthorizationFree(auth, kAuthorizationFlagDefaults); + return ret; } -void Overlay::installFiles() { +bool Overlay::uninstallFiles() { + // Get the absolute path of our overlay loader bundle. + NSString *path = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MumbleOverlayLoaderBundle"]; + // Make sure it is unloaded, at least from ourselves, before we trash it. + [[NSBundle bundleWithPath:path] unload]; + + // This is a tiny AppleScript that kindly asks the Finder to throw + // the currently installed loader bundle into the trash. + // + // This is nice because we don't need to have any privileged code in + // Mumble itself that does it, and because it goes into the user's + // trash. + NSString *uninstallScript = [NSString stringWithFormat:@"" + "set bundlePath to POSIX file \"%@\"\n" + "tell application \"Finder\" to delete bundlePath\n", path]; + + // Execute the script, and hope for the best. + NSError *error = nil; + NSString *script = [[NSAppleScript alloc] initWithSource:uninstallScript]; + [script executeAndReturnError:&error]; + [script release]; + + if (error) { + NSLog(@"%@", error); + return false; + } + + return true; } |