예제 #1
0
 def alertedToRunningOnBatteryAndCancelled(self):
     '''Returns True if we are running on battery and user clicks
     the Cancel button'''
     power_info = munki.getPowerInfo()
     if (power_info.get('PowerSource') == 'Battery Power'
         and power_info.get('BatteryCharge', 0) < 50):
         alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
             NSLocalizedString(
                 u"Your computer is not connected to a power source.", u"No Power Source Warning text"),
             NSLocalizedString(u"Continue", u"Continue button text"),
             NSLocalizedString(u"Cancel", u"Cancel button title/short action text"),
             nil,
             u"%@", NSLocalizedString(
                 (u"For best results, you should connect your computer to a "
                 "power source before updating. Are you sure you want to "
                 "continue the update?"), u"No Power Source Warning detail"))
         msclog.log("MSU", "alert_on_battery_power")
         # making UI consistent with Apple Software Update...
         # set Cancel button to be activated by return key
         alert.buttons()[1].setKeyEquivalent_('\r')
         # set Continue button to be activated by Escape key
         alert.buttons()[0].setKeyEquivalent_(chr(27))
         buttonPressed = alert.runModal()
         if buttonPressed == NSAlertAlternateReturn:
             return True
     return False
예제 #2
0
 def kickOffInstallSession(self):
     '''start an update install/removal session'''
     # check for need to logout, restart, firmware warnings
     # warn about blocking applications, etc...
     # then start an update session
     if MunkiItems.updatesRequireRestart() or MunkiItems.updatesRequireLogout():
         # switch to updates view
         self.loadUpdatesPage_(self)
         # warn about need to logout or restart
         self.alert_controller.confirmUpdatesAndInstall()
     else:
         if self.alert_controller.alertedToBlockingAppsRunning():
             self.loadUpdatesPage_(self)
             return
         if self.alert_controller.alertedToRunningOnBatteryAndCancelled():
             self.loadUpdatesPage_(self)
             return
         self.managedsoftwareupdate_task = None
         msclog.log("user", "install_without_logout")
         self._update_in_progress = True
         self.displayUpdateCount()
         self.setStatusViewTitle_(NSLocalizedString(u"Updating...", u"Updating message"))
         result = munki.justUpdate()
         if result:
             msclog.debug_log("Error starting install session: %s" % result)
             self.munkiStatusSessionEnded_(2)
         else:
             self.managedsoftwareupdate_task = "installwithnologout"
             NSApp.delegate().statusController.startMunkiStatusSession()
             self.markPendingItemsAsInstalling()
예제 #3
0
    def alertedToBlockingAppsRunning(self):
        '''Returns True if blocking_apps are running; alerts as a side-effect'''
        apps_to_check = []
        for update_item in MunkiItems.getUpdateList():
            if 'blocking_applications' in update_item:
                apps_to_check.extend(update_item['blocking_applications'])
            else:
                apps_to_check.extend(
                    [os.path.basename(item.get('path'))
                     for item in update_item.get('installs', [])
                     if item['type'] == 'application']
                )

        running_apps = munki.getRunningBlockingApps(apps_to_check)
        if running_apps:
            current_user = munki.getconsoleuser()
            other_users_apps = [item['display_name'] for item in running_apps
                                if item['user'] != current_user]
            my_apps = [item['display_name'] for item in running_apps
                       if item['user'] == current_user]
            msclog.log(
                "MSC", "conflicting_apps", ','.join(other_users_apps + my_apps))
            if other_users_apps:
                detailText = NSLocalizedString(
                    u"Other logged in users are using the following "
                    "applications. Try updating later when they are no longer "
                    "in use:\n\n%s",
                    u"Other Users Blocking Apps Running detail")
                alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
                    NSLocalizedString(
                        u"Applications in use by others",
                        u"Other Users Blocking Apps Running title"),
                    NSLocalizedString(u"OK", u'OKButtonText'),
                    nil,
                    nil,
                    u"%@", detailText % u'\n'.join(set(other_users_apps))
                    )
            else:
                detailText = NSLocalizedString(
                    u"You must quit the following applications before "
                    "proceeding with installation or removal:\n\n%s",
                    u"Blocking Apps Running detail")
                alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
                    NSLocalizedString(
                        u"Conflicting applications running",
                        u"Blocking Apps Running title"),
                    NSLocalizedString(u"OK", u"OK button title"),
                    nil,
                    nil,
                    u"%@", detailText % u'\n'.join(set(my_apps))
                    )
            alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
                self.window, self,
                self.blockingAppsRunningAlertDidEnd_returnCode_contextInfo_,
                nil)
            return True
        else:
            return False
예제 #4
0
 def forceLogoutWarningDidEnd_returnCode_contextInfo_(
                                     self, alert, returncode, contextinfo):
     '''Called when the forced logout warning alert ends'''
     btn_pressed = self._force_warning_btns.get(returncode)
     if btn_pressed == self._force_warning_logout_btn:
         msclog.log("user", "install_with_logout")
         result = munki.logoutAndUpdate()
     elif btn_pressed == self._force_warning_ok_btn:
         msclog.log("user", "dismissed_forced_logout_warning")
예제 #5
0
 def userNotificationCenter_didActivateNotification_(self, center, notification):
     '''User clicked on a Notification Center alert'''
     user_info = notification.userInfo()
     if user_info.get('action') == 'open_url':
         url = user_info.get('value', 'munki://updates')
         msclog.log("MSU", "Got user notification to open %s" % url)
         self.openMunkiURL(url)
         center.removeDeliveredNotification_(notification)
     else:
         msclog.log("MSU", "Got user notification with unrecognized userInfo")
예제 #6
0
 def forceLogoutWarningDidEnd_returnCode_contextInfo_(
         self, alert, returncode, contextinfo):
     '''Called when the forced logout warning alert ends'''
     btn_pressed = self._force_warning_btns.get(returncode)
     if btn_pressed == self._force_warning_logout_btn:
         msclog.log("user", "install_with_logout")
         self.handlePossibleAuthRestart()
         try:
             munki.logoutAndUpdate()
         except munki.ProcessStartError, err:
             self.installSessionErrorAlert_(err)
예제 #7
0
 def updateAlertDidEnd_returnCode_contextInfo_(
                                self, alert, returncode, contextinfo):
     '''Called when alert invoked by alertToPendingUpdates ends'''
     if returncode == NSAlertDefaultReturn:
         msclog.log("user", "quit")
         NSApp.terminate_(self)
     elif returncode == NSAlertOtherReturn:
         msclog.log("user", "install_now_clicked")
         # make sure this alert panel is gone before we proceed
         # which might involve opening another alert sheet
         alert.window().orderOut_(self)
         # initiate the updates
         self.updateNow()
         self.loadUpdatesPage_(self)
예제 #8
0
 def installSessionErrorAlert(self):
     '''Something has gone wrong and we can't trigger an install at logout'''
     msclog.log("user", "install_session_failed")
     alertMessageText = NSLocalizedString(
         u"Install session failed", u"Install Session Failed title")
     detailText = NSLocalizedString(
         u"There is a configuration problem with the managed software "
         "installer. Could not start the process. Contact your systems "
         "administrator.", u"Could Not Start Session message")
     alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
         alertMessageText, OKButtonTitle, nil, nil, u"%@", detailText)
     alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
         self.window(), self,
         self.installSessionErrorAlertDidEnd_returnCode_contextInfo_, nil)
예제 #9
0
    def applicationDidFinishLaunching_(self, sender):
        '''NSApplication delegate method called at launch'''
        # Prevent automatic relaunching at login on Lion+
        if NSApp.respondsToSelector_('disableRelaunchOnLogin'):
            NSApp.disableRelaunchOnLogin()

        ver = NSBundle.mainBundle().infoDictionary().get('CFBundleShortVersionString')
        msclog.log("MSC", "launched", "VER=%s" % ver)
        
        # if we're running under Snow Leopard, swap out the Dock icon for one
        # without the Retina assets to avoid an appearance issue when the
        # icon has a badge in the Dock (and App Switcher)
        # Darwin major version 10 is Snow Leopard (10.6)
        if os.uname()[2].split('.')[0] == '10':
            myImage = NSImage.imageNamed_("Managed Software Center 10_6")
            NSApp.setApplicationIconImage_(myImage)

        # setup client logging
        msclog.setup_logging()

        # have the statuscontroller register for its own notifications
        self.statusController.registerForNotifications()

        # user may have launched the app manually, or it may have
        # been launched by /usr/local/munki/managedsoftwareupdate
        # to display available updates
        if munki.thereAreUpdatesToBeForcedSoon(hours=2):
            # skip the check and just display the updates
            # by pretending the lastcheck is now
            lastcheck = NSDate.date()
        else:
            lastcheck = munki.pref('LastCheckDate')
        max_cache_age = munki.pref('CheckResultsCacheSeconds')
        # if there is no lastcheck timestamp, check for updates.
        if not lastcheck:
            self.mainWindowController.checkForUpdates()
        elif lastcheck.timeIntervalSinceNow() * -1 > int(max_cache_age):
            # check for updates if the last check is over the
            # configured manualcheck cache age max.
            self.mainWindowController.checkForUpdates()
        elif MunkiItems.updateCheckNeeded():
            # check for updates if we have optional items selected for install
            # or removal that have not yet been processed
            self.mainWindowController.checkForUpdates()
        
        # load the initial view only if we are not already loading something else.
        # enables launching the app to a specific panel, eg. from URL handler
        if not self.mainWindowController.webView.isLoading():
            self.mainWindowController.loadInitialView()
예제 #10
0
 def doRestartAlert(self):
     '''Display a restart alert -- some item just installed or removed requires a restart'''
     msclog.log("MSC", "restart_required")
     self._status_restartAlertDismissed = 0
     alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
         NSLocalizedString(u"Restart Required", u"Restart Required title"),
         NSLocalizedString(u"Restart", u"Restart button title"),
         nil,
         nil,
         u"%@", NSLocalizedString(
             u"Software installed or removed requires a restart. You will "
             "have a chance to save open documents.", u"Restart Required alert detail"))
     alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
         self.statusWindowController.window(),
         self, self.restartAlertDidEnd_returnCode_contextInfo_, nil)
예제 #11
0
 def alertToExtraUpdates(self):
     '''Notify user of additional pending updates'''
     msclog.log("user", "extra_updates_pending")
     alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
         NSLocalizedString(
             u"Additional Pending Updates",
             u"Additional Pending Updates title"),
         NSLocalizedString(u"OK", u"OK button title"),
         nil,
         nil,
         u"%@", NSLocalizedString(
             u"There are additional pending updates to install or remove.",
             u"Additional Pending Updates detail")
         )
     alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
         self.window, self,
         self.extraUpdatesAlertDidEnd_returnCode_contextInfo_, nil)
예제 #12
0
 def openURL_withReplyEvent_(self, event, replyEvent):
     '''Handle openURL messages'''
     keyDirectObject = struct.unpack(">i", "----")[0]
     url = event.paramDescriptorForKeyword_(keyDirectObject).stringValue().decode('utf8')
     msclog.log("MSU", "Called by external URL: %s", url)
     parsed_url = urlparse(url)
     if parsed_url.scheme != 'munki':
         msclog.debug_log("URL %s has unsupported scheme" % url)
         return
     filename = mschtml.unquote(parsed_url.netloc)
     # add .html if no extension
     if not os.path.splitext(filename)[1]:
         filename += u'.html'
     if filename.endswith(u'.html'):
         mschtml.build_page(filename)
         self.mainWindowController.load_page(filename)
     else:
         msclog.debug_log("%s doesn't have a valid extension. Prevented from opening" % url)
예제 #13
0
 def promptForPasswordForAuthRestart(self):
     '''Set up and display our alert that prompts for password'''
     # Set up all the fields and buttons with localized text
     alert = NSAlert.alloc().init()
     alert.addButtonWithTitle_(
         NSLocalizedString(u"Allow", u"Allow button text"))
     alert.addButtonWithTitle_(
         NSLocalizedString(u"Deny", u"Deny button text"))
     alert.setMessageText_(NSLocalizedString(
         u"Managed Software Center wants to unlock the startup disk after "
         "restarting to complete all pending updates.",
         u"Password prompt title"))
     alert.setInformativeText_(NSLocalizedString(
         u"To allow this, enter your login password.",
         u"Password explanation"))
     alert.setAccessoryView_(self.passwordView)
     self.passwordLabel.setStringValue_(NSLocalizedString(
         u"Password:"******"Password label"))
     self.passwordField.setStringValue_(u"")
     # resize label to fit the text
     self.passwordLabel.sizeToFit()
     # resize the password field to use the rest of the available space
     viewWidth = self.passwordView.frame().size.width
     labelWidth = self.passwordLabel.frame().size.width
     fieldFrame = self.passwordField.frame()
     fieldFrame.origin.x = labelWidth + 8
     fieldFrame.size.width = viewWidth - labelWidth - 8
     self.passwordField.setFrame_(fieldFrame)
     # add esc as a key equivalent for the Deny button
     alert.buttons().objectAtIndex_(1).setKeyEquivalent_(chr(27))
     # change the Allow button to call our password validation method
     allowButton = alert.buttons().objectAtIndex_(0)
     allowButton.setTarget_(self)
     allowButton.setAction_(self.verifyPassword_)
     # make sure our password field is ready to accept input
     alert.window().setInitialFirstResponder_(self.passwordField)
     # we can finally run the alert!
     result = alert.runModal()
     if result == NSAlertFirstButtonReturn:
         # they clicked "Allow". We handled it in the verifyPassword method
         msclog.log("user", "stored password for auth restart")
     if result == NSAlertSecondButtonReturn:
         # they clicked "Deny"
         msclog.log("user", "denied password for auth restart")
예제 #14
0
 def alertedToMultipleUsers(self):
     '''Returns True if there are multiple GUI logins; alerts as a side effect'''
     if len(munki.currentGUIusers()) > 1:
         msclog.log("MSC", "multiple_gui_users_update_cancelled")
         alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
             NSLocalizedString(u"Other users logged in", u"Other Users Logged In title"),
             NSLocalizedString(u"Cancel", u"Cancel button title/short action text"),
             nil,
             nil,
             u"%@", NSLocalizedString(
                 (u"There are other users logged into this computer.\n"
                  "Updating now could cause other users to lose their "
                  "work.\n\nPlease try again later after the other users "
                  "have logged out."), u"Other Users Logged In detail"))
         alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
             self.window, self, self.multipleUserAlertDidEnd_returnCode_contextInfo_, nil)
         return True
     else:
         return False
예제 #15
0
 def updateNow(self):
     '''If user has added to/removed from the list of things to be updated,
     run a check session. If there are no more changes, proceed to an update
     installation session if items to be installed/removed are exclusively
     those selected by the user in this session'''
     if self.stop_requested:
         # reset the flag
         self.stop_requested = False
         self.resetAndReload()
         return
     if MunkiItems.updateCheckNeeded():
         # any item status changes that require an update check?
         msclog.debug_log('updateCheck needed')
         msclog.log("user", "check_then_install_without_logout")
         # since we are just checking for changed self-service items
         # we can suppress the Apple update check
         suppress_apple_update_check = True
         self._update_in_progress = True
         self.displayUpdateCount()
         result = munki.startUpdateCheck(suppress_apple_update_check)
         if result:
             msclog.debug_log("Error starting check-then-install session: %s" % result)
             self.munkiStatusSessionEnded_(2)
         else:
             self.managedsoftwareupdate_task = "checktheninstall"
             NSApp.delegate().statusController.startMunkiStatusSession()
             self.markRequestedItemsAsProcessing()
     elif (not self._alertedUserToOutstandingUpdates
           and MunkiItems.updatesContainNonUserSelectedItems()):
         # current list of updates contains some not explicitly chosen by the user
         msclog.debug_log('updateCheck not needed, items require user approval')
         self._update_in_progress = False
         self.displayUpdateCount()
         self.loadUpdatesPage_(self)
         self.alert_controller.alertToExtraUpdates()
     else:
         msclog.debug_log('updateCheck not needed')
         self._alertedUserToOutstandingUpdates = False
         self.kickOffInstallSession()
예제 #16
0
 def logoutAlertDidEnd_returnCode_contextInfo_(
                                     self, alert, returncode, contextinfo):
     '''Called when logout alert ends'''
     if returncode == NSAlertDefaultReturn:
         # make sure this alert panel is gone before we proceed, which
         # might involve opening another alert sheet
         alert.window().orderOut_(self)
         if self.alertedToFirmwareUpdatesAndCancelled():
             msclog.log("user", "alerted_to_firmware_updates_and_cancelled")
             return
         elif self.alertedToRunningOnBatteryAndCancelled():
             msclog.log("user", "alerted_on_battery_power_and_cancelled")
             return
         msclog.log("user", "install_with_logout")
         result = munki.logoutAndUpdate()
         if result:
             self.installSessionErrorAlert()
     elif returncode == NSAlertAlternateReturn:
         msclog.log("user", "cancelled")
예제 #17
0
 def logoutAlertDidEnd_returnCode_contextInfo_(
         self, alert, returncode, contextinfo):
     '''Called when logout alert ends'''
     if returncode == NSAlertDefaultReturn:
         # make sure this alert panel is gone before we proceed, which
         # might involve opening another alert sheet
         alert.window().orderOut_(self)
         if self.alertedToFirmwareUpdatesAndCancelled():
             msclog.log("user", "alerted_to_firmware_updates_and_cancelled")
             return
         elif self.alertedToRunningOnBatteryAndCancelled():
             msclog.log("user", "alerted_on_battery_power_and_cancelled")
             return
         msclog.log("user", "install_with_logout")
         self.handlePossibleAuthRestart()
         result = munki.logoutAndUpdate()
         if result:
             self.installSessionErrorAlert()
     elif returncode == NSAlertAlternateReturn:
         msclog.log("user", "cancelled")
예제 #18
0
 def openURL_withReplyEvent_(self, event, replyEvent):
     '''Handle openURL messages'''
     keyDirectObject = struct.unpack(">i", "----")[0]
     url = event.paramDescriptorForKeyword_(keyDirectObject).stringValue().decode('utf8')
     msclog.log("MSU", "Called by external URL: %s", url)
     self.openMunkiURL(url)
예제 #19
0
    def munkiStatusSessionEnded_(self, sessionResult):
        '''Called by StatusController when a Munki session ends'''
        msclog.debug_log(u"MunkiStatus session ended: %s" % sessionResult)
        msclog.debug_log(u"MunkiStatus session type: %s" % self.managedsoftwareupdate_task)
        tasktype = self.managedsoftwareupdate_task
        self.managedsoftwareupdate_task = None
        self._update_in_progress = False
        
        # The managedsoftwareupdate run will have changed state preferences
        # in ManagedInstalls.plist. Load the new values.
        munki.reload_prefs()
        lastCheckResult = munki.pref("LastCheckResult")
        if sessionResult != 0 or lastCheckResult < 0:
            OKButtonTitle = NSLocalizedString(u"OK", u"OK button title")
            alertMessageText = NSLocalizedString(
                                    u"Update check failed", u"Update Check Failed title")
            if tasktype == "installwithnologout":
                alertMessageText = NSLocalizedString(
                                        u"Install session failed", u"Install Session Failed title")

            if sessionResult == -1:
                # connection was dropped unexpectedly
                msclog.log("MSC", "cant_update", "unexpected process end")
                detailText = NSLocalizedString(
                    (u"There is a configuration problem with the managed software installer. "
                      "The process ended unexpectedly. Contact your systems administrator."),
                     u"Unexpected Session End message")
            elif sessionResult == -2:
                # session never started
                msclog.log("MSC", "cant_update", "process did not start")
                detailText = NSLocalizedString(
                    (u"There is a configuration problem with the managed software installer. "
                      "Could not start the process. Contact your systems administrator."),
                     u"Could Not Start Session message")
            elif lastCheckResult == -1:
                # server not reachable
                msclog.log("MSC", "cant_update", "cannot contact server")
                detailText = NSLocalizedString(
                    (u"Managed Software Center cannot contact the update server at this time.\n"
                      "Try again later. If this situation continues, "
                      "contact your systems administrator."), u"Cannot Contact Server detail")
            elif lastCheckResult == -2:
                # preflight failed
                msclog.log("MSU", "cant_update", "failed preflight")
                detailText = NSLocalizedString(
                    (u"Managed Software Center cannot check for updates now.\n"
                      "Try again later. If this situation continues, "
                      "contact your systems administrator."), u"Failed Preflight Check detail")
            # show the alert sheet
            self.window().makeKeyAndOrderFront_(self)
            alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
                alertMessageText, OKButtonTitle, nil, nil, u"%@", detailText)
            alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
                self.window(), self,
                self.munkiSessionErrorAlertDidEnd_returnCode_contextInfo_, nil)
            return
        
        if tasktype == 'checktheninstall':
            MunkiItems.reset()
            # possibly check again if choices have changed
            self.updateNow()
            return

        # all done checking and/or installing: display results
        self.resetAndReload()
        
        if MunkiItems.updateCheckNeeded():
            # more stuff pending? Let's do it...
            self.updateNow()
예제 #20
0
    def forcedLogoutWarning(self, notification_obj):
        '''Display a forced logout warning'''
        NSApp.activateIgnoringOtherApps_(True)
        info = notification_obj.userInfo()
        moreText = NSLocalizedString(
            (u"All pending updates will be installed. Unsaved work will be lost."
            "\nYou may avoid the forced logout by logging out now."),
            u"Forced Logout warning detail")
        logout_time = None
        if info:
            logout_time = info.get('logout_time')
        elif munki.thereAreUpdatesToBeForcedSoon():
            logout_time = munki.earliestForceInstallDate()
        if not logout_time:
            return
        time_til_logout = int(logout_time.timeIntervalSinceNow() / 60)
        if time_til_logout > 55:
            deadline_str = munki.stringFromDate(logout_time)
            msclog.log("user", "forced_logout_warning_initial")
            formatString = NSLocalizedString(
                    u"A logout will be forced at approximately %s.",
                    u"Logout warning string when logout is an hour or more away")
            infoText = formatString % deadline_str + u"\n" + moreText
        elif time_til_logout > 0:
            msclog.log("user", "forced_logout_warning_%s" % time_til_logout)
            formatString = NSLocalizedString(
                    u"A logout will be forced in less than %s minutes.",
                    u"Logout warning string when logout is in < 60 minutes")
            infoText = formatString % time_til_logout + u"\n" + moreText
        else:
            msclog.log("user", "forced_logout_warning_final")
            infoText = NSLocalizedString(
                (u"A logout will be forced in less than a minute.\nAll pending "
                  "updates will be installed. Unsaved work will be lost."),
                u"Logout warning string when logout is in less than a minute")

        # Set the OK button to default, unless less than 5 minutes to logout
        # in which case only the Logout button should be displayed.
        self._force_warning_logout_btn = NSLocalizedString(
            u"Log out and update now", u"Logout and Update Now button text")
        self._force_warning_ok_btn = NSLocalizedString(u"OK", u"OK button title")
        if time_til_logout > 5:
            self._force_warning_btns = {
                NSAlertDefaultReturn: self._force_warning_ok_btn,
                NSAlertAlternateReturn: self._force_warning_logout_btn,
            }
        else:
            self._force_warning_btns = {
                NSAlertDefaultReturn: self._force_warning_logout_btn,
                NSAlertAlternateReturn: nil,
            }

        if self.window.attachedSheet():
            # there's an existing sheet open
            NSApp.endSheet_(self.window.attachedSheet())

        alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
                    NSLocalizedString(
                        u"Forced Logout for Mandatory Install", u"Forced Logout title text"),
                    self._force_warning_btns[NSAlertDefaultReturn],
                    self._force_warning_btns[NSAlertAlternateReturn],
                    nil,
                    u"%@", infoText)
        alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
            self.window, self, self.forceLogoutWarningDidEnd_returnCode_contextInfo_, nil)
예제 #21
0
    def forcedLogoutWarning(self, notification_obj):
        '''Display a forced logout warning'''
        NSApp.activateIgnoringOtherApps_(True)
        info = notification_obj.userInfo()
        moreText = NSLocalizedString(
            u"All pending updates will be installed. Unsaved work will be lost."
            "\nYou may avoid the forced logout by logging out now.",
            u"Forced Logout warning detail")
        logout_time = None
        if info:
            logout_time = info.get('logout_time')
        elif munki.thereAreUpdatesToBeForcedSoon():
            logout_time = munki.earliestForceInstallDate()
        if not logout_time:
            return
        time_til_logout = int(logout_time.timeIntervalSinceNow() / 60)
        if time_til_logout > 55:
            deadline_str = munki.stringFromDate(logout_time)
            msclog.log("user", "forced_logout_warning_initial")
            formatString = NSLocalizedString(
                u"A logout will be forced at approximately %s.",
                u"Logout warning string when logout is an hour or more away")
            infoText = formatString % deadline_str + u"\n" + moreText
        elif time_til_logout > 0:
            msclog.log("user", "forced_logout_warning_%s" % time_til_logout)
            formatString = NSLocalizedString(
                u"A logout will be forced in less than %s minutes.",
                u"Logout warning string when logout is in < 60 minutes")
            infoText = formatString % time_til_logout + u"\n" + moreText
        else:
            msclog.log("user", "forced_logout_warning_final")
            infoText = NSLocalizedString(
                u"A logout will be forced in less than a minute.\nAll pending "
                "updates will be installed. Unsaved work will be lost.",
                u"Logout warning string when logout is in less than a minute")

        # Set the OK button to default, unless less than 5 minutes to logout
        # in which case only the Logout button should be displayed.
        self._force_warning_logout_btn = NSLocalizedString(
            u"Log out and update now", u"Logout and Update Now button text")
        self._force_warning_ok_btn = NSLocalizedString(u"OK",
                                                       u"OK button title")
        if time_til_logout > 5:
            self._force_warning_btns = {
                NSAlertDefaultReturn: self._force_warning_ok_btn,
                NSAlertAlternateReturn: self._force_warning_logout_btn,
            }
        else:
            self._force_warning_btns = {
                NSAlertDefaultReturn: self._force_warning_logout_btn,
                NSAlertAlternateReturn: nil,
            }

        if self.window.attachedSheet():
            # there's an existing sheet open
            NSApp.endSheet_(self.window.attachedSheet())

        alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
            NSLocalizedString(u"Forced Logout for Mandatory Install",
                              u"Forced Logout title text"),
            self._force_warning_btns[NSAlertDefaultReturn],
            self._force_warning_btns[NSAlertAlternateReturn], nil, u"%@",
            infoText)
        alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
            self.window, self,
            self.forceLogoutWarningDidEnd_returnCode_contextInfo_, nil)
예제 #22
0
 def restartAlertDidEnd_returnCode_contextInfo_(
         self, alert, returncode, contextinfo):
     '''Called when restartAlert ends'''
     msclog.log("MSC", "restart_confirmed")
     self._status_restartAlertDismissed = 1
     munki.restartNow()
예제 #23
0
class AlertController(NSObject):
    '''An object that handles some of our alerts, if for no other reason
    than to move a giant bunch of ugly code out of the WindowController'''
    def setWindow_(self, the_window):
        '''Store our parent window'''
        self.window = the_window

    def handlePossibleAuthRestart(self):
        '''Ask for and store a password for auth restart if needed/possible'''
        username = NSUserName()
        if (MunkiItems.updatesRequireRestart()
                and authrestart.verify_user(username)
                and not authrestart.verify_recovery_key_present()):
            # FV is on and user is in list of FV users, so they can
            # authrestart, and we do not have a stored FV recovery
            # key/password. So we should prompt the user for a password
            # we can use for fdesetup authrestart
            NSApp.delegate(
            ).passwordAlertController.promptForPasswordForAuthRestart()

    def forcedLogoutWarning(self, notification_obj):
        '''Display a forced logout warning'''
        NSApp.activateIgnoringOtherApps_(True)
        info = notification_obj.userInfo()
        moreText = NSLocalizedString(
            u"All pending updates will be installed. Unsaved work will be lost."
            "\nYou may avoid the forced logout by logging out now.",
            u"Forced Logout warning detail")
        logout_time = None
        if info:
            logout_time = info.get('logout_time')
        elif munki.thereAreUpdatesToBeForcedSoon():
            logout_time = munki.earliestForceInstallDate()
        if not logout_time:
            return
        time_til_logout = int(logout_time.timeIntervalSinceNow() / 60)
        if time_til_logout > 55:
            deadline_str = munki.stringFromDate(logout_time)
            msclog.log("user", "forced_logout_warning_initial")
            formatString = NSLocalizedString(
                u"A logout will be forced at approximately %s.",
                u"Logout warning string when logout is an hour or more away")
            infoText = formatString % deadline_str + u"\n" + moreText
        elif time_til_logout > 0:
            msclog.log("user", "forced_logout_warning_%s" % time_til_logout)
            formatString = NSLocalizedString(
                u"A logout will be forced in less than %s minutes.",
                u"Logout warning string when logout is in < 60 minutes")
            infoText = formatString % time_til_logout + u"\n" + moreText
        else:
            msclog.log("user", "forced_logout_warning_final")
            infoText = NSLocalizedString(
                u"A logout will be forced in less than a minute.\nAll pending "
                "updates will be installed. Unsaved work will be lost.",
                u"Logout warning string when logout is in less than a minute")

        # Set the OK button to default, unless less than 5 minutes to logout
        # in which case only the Logout button should be displayed.
        self._force_warning_logout_btn = NSLocalizedString(
            u"Log out and update now", u"Logout and Update Now button text")
        self._force_warning_ok_btn = NSLocalizedString(u"OK",
                                                       u"OK button title")
        if time_til_logout > 5:
            self._force_warning_btns = {
                NSAlertDefaultReturn: self._force_warning_ok_btn,
                NSAlertAlternateReturn: self._force_warning_logout_btn,
            }
        else:
            self._force_warning_btns = {
                NSAlertDefaultReturn: self._force_warning_logout_btn,
                NSAlertAlternateReturn: nil,
            }

        if self.window.attachedSheet():
            # there's an existing sheet open
            NSApp.endSheet_(self.window.attachedSheet())

        alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
            NSLocalizedString(u"Forced Logout for Mandatory Install",
                              u"Forced Logout title text"),
            self._force_warning_btns[NSAlertDefaultReturn],
            self._force_warning_btns[NSAlertAlternateReturn], nil, u"%@",
            infoText)
        alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
            self.window, self,
            self.forceLogoutWarningDidEnd_returnCode_contextInfo_, nil)

    @AppHelper.endSheetMethod
    def forceLogoutWarningDidEnd_returnCode_contextInfo_(
            self, alert, returncode, contextinfo):
        '''Called when the forced logout warning alert ends'''
        btn_pressed = self._force_warning_btns.get(returncode)
        if btn_pressed == self._force_warning_logout_btn:
            msclog.log("user", "install_with_logout")
            self.handlePossibleAuthRestart()
            try:
                munki.logoutAndUpdate()
            except munki.ProcessStartError, err:
                self.installSessionErrorAlert_(err)
        elif btn_pressed == self._force_warning_ok_btn:
            msclog.log("user", "dismissed_forced_logout_warning")
예제 #24
0
            # might involve opening another alert sheet
            alert.window().orderOut_(self)
            if self.alertedToFirmwareUpdatesAndCancelled():
                msclog.log("user", "alerted_to_firmware_updates_and_cancelled")
                return
            elif self.alertedToRunningOnBatteryAndCancelled():
                msclog.log("user", "alerted_on_battery_power_and_cancelled")
                return
            msclog.log("user", "install_with_logout")
            self.handlePossibleAuthRestart()
            try:
                munki.logoutAndUpdate()
            except munki.ProcessStartError, err:
                self.installSessionErrorAlert_(err)
        elif returncode == NSAlertAlternateReturn:
            msclog.log("user", "cancelled")

    def installSessionErrorAlert_(self, errmsg):
        '''Something has gone wrong and we can't trigger an install at logout'''
        msclog.log("user", "install_session_failed")
        alertMessageText = NSLocalizedString(u"Install session failed",
                                             u"Install Session Failed title")
        detailText = NSLocalizedString(
            u"There is a configuration problem with the managed software "
            "installer. Could not start the process. Contact your systems "
            "administrator.", u"Could Not Start Session message")
        detailText += u"\n\n" + unicode(errmsg)
        OKButtonTitle = NSLocalizedString(u"OK", u"OK button title")
        alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
            alertMessageText, OKButtonTitle, nil, nil, u"%@", detailText)
        alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(
예제 #25
0
 def restartAlertDidEnd_returnCode_contextInfo_(self, alert, returncode,
                                                contextinfo):
     '''Called when restartAlert ends'''
     msclog.log("MSC", "restart_confirmed")
     self._status_restartAlertDismissed = 1
     munki.restartNow()
예제 #26
0
 def openURL_withReplyEvent_(self, event, replyEvent):
     '''Handle openURL messages'''
     keyDirectObject = struct.unpack(">i", "----")[0]
     url = event.paramDescriptorForKeyword_(keyDirectObject).stringValue().decode('utf8')
     msclog.log("MSU", "Called by external URL: %s", url)
     self.openMunkiURL(url)
예제 #27
0
    def applicationDidFinishLaunching_(self, sender):
        '''NSApplication delegate method called at launch'''
        NSLog("Finished launching")
        # setup client logging
        msclog.setup_logging()

        # userInfo dict can be nil, seems to be with 10.6
        if sender.userInfo():
            userNotification = sender.userInfo().get(
                'NSApplicationLaunchUserNotificationKey')
            # we get this notification at launch because it's too early to have declared ourself
            # a NSUserNotificationCenterDelegate
            if userNotification:
                NSLog("Launched via Notification interaction")
                self.userNotificationCenter_didActivateNotification_(
                    NSUserNotificationCenter.defaultUserNotificationCenter(),
                    userNotification)

        # Prevent automatic relaunching at login on Lion+
        if NSApp.respondsToSelector_('disableRelaunchOnLogin'):
            NSApp.disableRelaunchOnLogin()

        ver = NSBundle.mainBundle().infoDictionary().get(
            'CFBundleShortVersionString')
        msclog.log("MSC", "launched", "VER=%s" % ver)

        # if we're running under Snow Leopard, swap out the Dock icon for one
        # without the Retina assets to avoid an appearance issue when the
        # icon has a badge in the Dock (and App Switcher)
        # Darwin major version 10 is Snow Leopard (10.6)
        if os.uname()[2].split('.')[0] == '10':
            myImage = NSImage.imageNamed_("Managed Software Center 10_6")
            NSApp.setApplicationIconImage_(myImage)

        # if we are running under Mountain Lion or later set ourselves as a delegate
        # for NSUserNotificationCenter notifications
        if os.uname()[2].split('.')[0] > '11':
            NSUserNotificationCenter.defaultUserNotificationCenter(
            ).setDelegate_(self)

        # have the statuscontroller register for its own notifications
        self.statusController.registerForNotifications()

        # user may have launched the app manually, or it may have
        # been launched by /usr/local/munki/managedsoftwareupdate
        # to display available updates
        if munki.thereAreUpdatesToBeForcedSoon(hours=2):
            # skip the check and just display the updates
            # by pretending the lastcheck is now
            lastcheck = NSDate.date()
        else:
            lastcheck = munki.pref('LastCheckDate')
        max_cache_age = munki.pref('CheckResultsCacheSeconds')
        # if there is no lastcheck timestamp, check for updates.
        if not lastcheck:
            self.mainWindowController.checkForUpdates()
        elif lastcheck.timeIntervalSinceNow() * -1 > int(max_cache_age):
            # check for updates if the last check is over the
            # configured manualcheck cache age max.
            self.mainWindowController.checkForUpdates()
        elif MunkiItems.updateCheckNeeded():
            # check for updates if we have optional items selected for install
            # or removal that have not yet been processed
            self.mainWindowController.checkForUpdates()

        # load the initial view only if we are not already loading something else.
        # enables launching the app to a specific panel, eg. from URL handler
        if not self.mainWindowController.webView.isLoading():
            self.mainWindowController.loadInitialView()
예제 #28
0
            # might involve opening another alert sheet
            alert.window().orderOut_(self)
            if self.alertedToFirmwareUpdatesAndCancelled():
                msclog.log("user", "alerted_to_firmware_updates_and_cancelled")
                return
            elif self.alertedToRunningOnBatteryAndCancelled():
                msclog.log("user", "alerted_on_battery_power_and_cancelled")
                return
            msclog.log("user", "install_with_logout")
            self.handlePossibleAuthRestart()
            try:
                munki.logoutAndUpdate()
            except munki.ProcessStartError, err:
                self.installSessionErrorAlert_(err)
        elif returncode == NSAlertAlternateReturn:
            msclog.log("user", "cancelled")

    def installSessionErrorAlert_(self, errmsg):
        '''Something has gone wrong and we can't trigger an install at logout'''
        msclog.log("user", "install_session_failed")
        alertMessageText = NSLocalizedString(
            u"Install session failed", u"Install Session Failed title")
        detailText = NSLocalizedString(
            u"There is a configuration problem with the managed software "
            "installer. Could not start the process. Contact your systems "
            "administrator.", u"Could Not Start Session message")
        detailText += u"\n\n" + unicode(errmsg)
        OKButtonTitle = NSLocalizedString(u"OK", u"OK button title")
        alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(
            alertMessageText, OKButtonTitle, nil, nil, u"%@", detailText)
        alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(