mirror of
https://github.com/munki/munki.git
synced 2026-01-10 00:30:51 -06:00
Removed readPlist(filepath) from MSUStatusWindowController; it now uses the equivalent function from FoundationPlist. Other minor cleanups. git-svn-id: http://munki.googlecode.com/svn/trunk@739 a4e17f2e-e282-11dd-95e1-755cbddbdd66
278 lines
10 KiB
Python
278 lines
10 KiB
Python
# encoding: utf-8
|
|
#
|
|
# MSUStatusWindowController.py
|
|
#
|
|
#
|
|
# Created by Greg Neagle on 9/21/09.
|
|
#
|
|
# Copyright 2009-2010 Greg Neagle.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
|
|
import os
|
|
import socket
|
|
import objc
|
|
import munki
|
|
import FoundationPlist
|
|
from Foundation import *
|
|
from SystemConfiguration import SCDynamicStoreCopyConsoleUser
|
|
from AppKit import *
|
|
import PyObjCTools
|
|
|
|
debug = False
|
|
|
|
class NSPropertyListSerializationException(Exception):
|
|
pass
|
|
|
|
def getLoginwindowPicture():
|
|
desktopPicturePath = ''
|
|
loginwindowPrefsPath = "/Library/Preferences/com.apple.loginwindow.plist"
|
|
if os.path.exists(loginwindowPrefsPath):
|
|
loginwindowPrefs = FoundationPlist.readPlist(loginwindowPrefsPath)
|
|
if loginwindowPrefs:
|
|
desktopPicturePath = loginwindowPrefs.get('DesktopPicture', '')
|
|
if desktopPicturePath:
|
|
if os.path.exists(desktopPicturePath):
|
|
theImage = \
|
|
NSImage.alloc().initWithContentsOfFile_(
|
|
desktopPicturePath)
|
|
if theImage:
|
|
return theImage
|
|
return NSImage.imageNamed_("Solid Aqua Blue")
|
|
theImage = NSImage.alloc().initWithContentsOfFile_(
|
|
"/System/Library/CoreServices/DefaultDesktop.jpg")
|
|
if theImage:
|
|
return theImage
|
|
else:
|
|
return NSImage.imageNamed_("Solid Aqua Blue")
|
|
|
|
|
|
|
|
class MSUStatusWindowController(NSObject):
|
|
'''
|
|
Controls the status window. This was formerly part of a
|
|
seperate application known as MunkiStatus.app
|
|
'''
|
|
|
|
window = objc.IBOutlet()
|
|
messageFld = objc.IBOutlet()
|
|
detailFld = objc.IBOutlet()
|
|
progressIndicator = objc.IBOutlet()
|
|
stopBtn = objc.IBOutlet()
|
|
imageFld = objc.IBOutlet()
|
|
|
|
backdropWindow = objc.IBOutlet()
|
|
backdropImageFld = objc.IBOutlet()
|
|
|
|
stopBtnState = 0
|
|
restartAlertDismissed = 0
|
|
session_started = False
|
|
session_connected = False
|
|
|
|
|
|
@objc.IBAction
|
|
def stopBtnClicked_(self, sender):
|
|
if debug:
|
|
NSLog(u"Stop button was clicked.")
|
|
sender.setState_(1)
|
|
self.stopBtnState = 1
|
|
sender.setEnabled_(False)
|
|
|
|
def startMunkiStatusSession(self):
|
|
NSLog(u"Managed Software Update.app PID: %s" % os.getpid())
|
|
consoleuser = munki.getconsoleuser()
|
|
if consoleuser == None or consoleuser == u"loginwindow":
|
|
if self.backdropWindow:
|
|
self.backdropWindow.setCanBecomeVisibleWithoutLogin_(True)
|
|
self.backdropWindow.setLevel_(NSStatusWindowLevel)
|
|
screenRect = NSScreen.mainScreen().frame()
|
|
self.backdropWindow.setFrame_display_(screenRect, True)
|
|
if self.backdropImageFld:
|
|
bgImage = getLoginwindowPicture()
|
|
self.backdropImageFld.setImage_(bgImage)
|
|
self.backdropWindow.orderFrontRegardless()
|
|
|
|
if self.window:
|
|
if consoleuser == None or consoleuser == u"loginwindow":
|
|
# needed so the window can show over the loginwindow
|
|
self.window.setCanBecomeVisibleWithoutLogin_(True)
|
|
self.window.setLevel_(NSScreenSaverWindowLevel - 1)
|
|
self.window.center()
|
|
self.window.setTitle_(u"Managed Software Update")
|
|
self.messageFld.setStringValue_(u"Starting…")
|
|
self.detailFld.setStringValue_(u"")
|
|
self.stopBtn.setHidden_(False)
|
|
self.stopBtn.setEnabled_(True)
|
|
if self.imageFld:
|
|
theImage = NSImage.imageNamed_("Managed Software Update")
|
|
self.imageFld.setImage_(theImage)
|
|
if self.progressIndicator:
|
|
self.progressIndicator.setMinValue_(0.0)
|
|
self.progressIndicator.setMaxValue_(100.0)
|
|
self.progressIndicator.setIndeterminate_(True)
|
|
self.progressIndicator.setUsesThreadedAnimation_(True)
|
|
self.progressIndicator.startAnimation_(self)
|
|
self.window.orderFrontRegardless()
|
|
# start our message processing thread
|
|
NSThread.detachNewThreadSelector_toTarget_withObject_(
|
|
self.handleSocket,
|
|
self,
|
|
None)
|
|
|
|
self.session_started = True
|
|
#NSApp.activateIgnoringOtherApps_(True)
|
|
|
|
|
|
def sessionStarted(self):
|
|
return self.session_started
|
|
|
|
def handleSocket(self):
|
|
# Autorelease pool for memory management
|
|
pool = NSAutoreleasePool.alloc().init()
|
|
|
|
socketSessionResult = 0
|
|
|
|
socketpath = "/tmp/com.googlecode.munki.munkistatus.%s" % os.getpid()
|
|
try:
|
|
os.remove(socketpath)
|
|
except OSError:
|
|
pass
|
|
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
s.bind(socketpath)
|
|
s.listen(1)
|
|
s.settimeout(30)
|
|
try:
|
|
conn, addr = s.accept()
|
|
# reset the timeout on the connected socket
|
|
conn.settimeout(None)
|
|
self.session_connected = True
|
|
if debug:
|
|
NSLog(u"Socket connection established.")
|
|
buffer = ''
|
|
keepLooping = True
|
|
while keepLooping:
|
|
data = conn.recv(1024)
|
|
if not data:
|
|
# socket connection was closed, we should terminate.
|
|
NSLog(u"Socket connection closed without QUIT message.")
|
|
socketSessionResult = -1
|
|
break
|
|
if debug:
|
|
NSLog(repr(data))
|
|
buffer = buffer + data
|
|
# do we have at least one return character?
|
|
if buffer.count('\n'):
|
|
lines = buffer.splitlines(True)
|
|
buffer = ''
|
|
for line in lines:
|
|
if line.endswith('\n'):
|
|
command = line.decode('UTF-8').rstrip('\n')
|
|
if debug:
|
|
NSLog(u"Socket received command: %s" % command)
|
|
if command.startswith(u"QUIT: "):
|
|
keepLooping = False
|
|
socketSessionResult = 0
|
|
break
|
|
response = self.processSocketMsg_(command)
|
|
if response:
|
|
conn.send(response)
|
|
else:
|
|
buffer = line
|
|
break
|
|
|
|
conn.close()
|
|
except socket.timeout:
|
|
NSLog("Socket timed out before connection.")
|
|
socketSessionResult = -2
|
|
except socket.error, errcode:
|
|
NSLog("Socket error: %s." % errcode)
|
|
socketSessionResult = -1
|
|
try:
|
|
os.remove(socketpath)
|
|
except OSError:
|
|
pass
|
|
|
|
self.window.orderOut_(self)
|
|
self.session_started = False
|
|
self.session_connected = False
|
|
NSApp.delegate().munkiStatusSessionEnded_(socketSessionResult)
|
|
|
|
# Clean up autorelease pool
|
|
del pool
|
|
|
|
def processSocketMsg_(self, message):
|
|
if message.startswith(u"ACTIVATE: "):
|
|
NSApp.activateIgnoringOtherApps_(True)
|
|
return ""
|
|
if message.startswith(u"HIDE: "):
|
|
self.window.orderOut_(self)
|
|
return ""
|
|
if message.startswith(u"SHOW: "):
|
|
self.window.orderFront_(self)
|
|
return ""
|
|
if message.startswith(u"TITLE: "):
|
|
self.window.setTitle_(message[7:])
|
|
return ""
|
|
if message.startswith(u"MESSAGE: "):
|
|
self.messageFld.setStringValue_(message[9:])
|
|
return ""
|
|
if message.startswith(u"DETAIL: "):
|
|
self.detailFld.setStringValue_(message[8:])
|
|
return ""
|
|
if message.startswith(u"PERCENT: "):
|
|
self.setPercentageDone(message[9:])
|
|
return ""
|
|
if message.startswith(u"GETSTOPBUTTONSTATE: "):
|
|
return "%s\n" % self.stopBtnState
|
|
if message.startswith(u"HIDESTOPBUTTON: "):
|
|
self.stopBtn.setHidden_(True)
|
|
return ""
|
|
if message.startswith(u"SHOWSTOPBUTTON: "):
|
|
self.stopBtn.setHidden_(False)
|
|
return ""
|
|
if message.startswith(u"ENABLESTOPBUTTON: "):
|
|
self.stopBtn.setEnabled_(True)
|
|
return ""
|
|
if message.startswith(u"DISABLESTOPBUTTON: "):
|
|
self.stopBtn.setEnabled_(False)
|
|
return ""
|
|
if message.startswith(u"RESTARTALERT: "):
|
|
self.doRestartAlert()
|
|
while 1:
|
|
if self.restartAlertDismissed:
|
|
break
|
|
return "1\n"
|
|
|
|
return ""
|
|
|
|
def setPercentageDone(self, percent):
|
|
if float(percent) < 0:
|
|
if not self.progressIndicator.isIndeterminate():
|
|
self.progressIndicator.setIndeterminate_(True)
|
|
self.progressIndicator.startAnimation_(self)
|
|
else:
|
|
if self.progressIndicator.isIndeterminate():
|
|
self.progressIndicator.stopAnimation_(self)
|
|
self.progressIndicator.setIndeterminate_(False)
|
|
self.progressIndicator.setDoubleValue_(float(percent))
|
|
|
|
@PyObjCTools.AppHelper.endSheetMethod
|
|
def alertDidEnd_returnCode_contextInfo_(self, alert, returncode, contextinfo):
|
|
self.restartAlertDismissed = 1
|
|
|
|
def doRestartAlert(self):
|
|
self.restartAlertDismissed = 0
|
|
alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Restart Required", u"Restart", objc.nil, objc.nil, "Software installed or removed requires a restart. You will have a chance to save open documents.")
|
|
alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.window, self, self.alertDidEnd_returnCode_contextInfo_, objc.nil)
|
|
|