diff --git a/code/Managed Software Update/BorderlessWindow.h b/code/Managed Software Update/BorderlessWindow.h new file mode 100644 index 00000000..76c3374f --- /dev/null +++ b/code/Managed Software Update/BorderlessWindow.h @@ -0,0 +1,31 @@ +// +// BorderlessWindow.h +// +// Created by Greg Neagle on 5/16/09. +// Copyright 2009 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 + + +@interface BorderlessWindow : NSWindow + +- (id) initWithContentRect: (NSRect) contentRect + styleMask: (unsigned int) aStyle + backing: (NSBackingStoreType) bufferingType + defer: (BOOL) flag; + +@end diff --git a/code/Managed Software Update/BorderlessWindow.m b/code/Managed Software Update/BorderlessWindow.m new file mode 100644 index 00000000..6a80fac4 --- /dev/null +++ b/code/Managed Software Update/BorderlessWindow.m @@ -0,0 +1,41 @@ +// +// BorderlessWindow.m +// +// Created by Greg Neagle on 5/16/09. +// Copyright 2009 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 "BorderlessWindow.h" + + +@implementation BorderlessWindow + +- (id) initWithContentRect: (NSRect) contentRect + styleMask: (unsigned int) aStyle + backing: (NSBackingStoreType) bufferingType + defer: (BOOL) flag +{ + if (self = [super initWithContentRect: contentRect + styleMask: NSBorderlessWindowMask + backing: bufferingType + defer: flag]) + + { + // other initialization + } + + return self; +} +@end diff --git a/code/Managed Software Update/English.lproj/MainMenu.xib b/code/Managed Software Update/English.lproj/MainMenu.xib index b51ed30e..eb27f4cf 100644 --- a/code/Managed Software Update/English.lproj/MainMenu.xib +++ b/code/Managed Software Update/English.lproj/MainMenu.xib @@ -1,25 +1,38 @@ - + 1050 - 9L31a - 677 - 949.54 - 353.00 + 10F569 + 788 + 1038.29 + 461.00 + + YES + + YES + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.WebKitIBPlugin + + + YES + 788 + 788 + + YES + - + YES - com.apple.WebKitIBPlugin - com.apple.InterfaceBuilderKit com.apple.InterfaceBuilder.CocoaPlugin + com.apple.WebKitIBPlugin YES - + YES @@ -81,7 +94,7 @@ - UHJlZmVyZW5jZXPigKY + Preferences… , 1048576 2147483647 @@ -315,7 +328,7 @@ YES - RmluZOKApg + Find… f 1048576 2147483647 @@ -380,7 +393,7 @@ YES - U2hvdyBTcGVsbGluZ+KApg + Show Spelling… : 1048576 2147483647 @@ -586,519 +599,1027 @@ 15 2 - {{448, 228}, {512, 546}} + {{448, 259}, {512, 518}} 1954022400 Managed Software Update NSWindow - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} {512, 400} - 256 + 272 YES - + - 268 - + 18 + {{0, 6}, {512, 512}} + + 2 + YES - - YES - Apple PDF pasteboard type - Apple PICT pasteboard type - Apple PNG pasteboard type - NSFilenamesPboardType - NeXT Encapsulated PostScript v1.2 pasteboard type - NeXT TIFF v4.0 pasteboard type - - - {{20, 462}, {64, 64}} - - YES - - 130560 - 33554432 - - NSImage - Managed Software Update - - 0 - 0 - 0 - NO - - YES - - - - 266 - {{100, 504}, {395, 17}} - - YES - - 68288064 - 4195328 - Software updates are available for your computer. - - LucidaGrande-Bold - 1.300000e+01 - 16 - - - - 6 - System - controlColor - - 3 - MC42NjY2NjY2OQA - - - - 6 - System - controlTextColor - - 3 - MAA - - - - - - - 266 - {{100, 463}, {395, 34}} - - YES - - 67239424 - 272760832 - VXBkYXRpbmcgeW91ciBzb2Z0d2FyZSBtYXkgdGFrZSBzb21lIHRpbWUuIElmIHlvdSdyZSBub3QgcmVh -ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg - - LucidaGrande - 1.100000e+01 - 3100 - - - - - - - - - 289 - {{387, 12}, {115, 32}} - - YES - - 67239424 - 134217728 - Update now - - LucidaGrande - 1.300000e+01 - 1044 - - - -2038284033 - 129 - - DQ - 200 - 25 - - - - - 289 - {{291, 12}, {96, 32}} - - YES - - 67239424 - 134217728 - Later - - - -2038284033 - 129 - - Gw - 200 - 25 - - - - - 292 - {{38, 23}, {254, 14}} - - YES - - 68288064 - 272761856 - - - - - - - - - - 274 - - YES - - - 274 - - YES - - - 274 - - YES - - - 2304 - + + 1 + + + 256 + + YES + + + 268 + + YES + YES - - - 256 - {455, 154} - - YES - - - 256 - {455, 17} - - - - - - 256 - {{456, 0}, {16, 17}} - - - - YES - - 1.800000e+01 - 1.800000e+01 - 1.800000e+01 - - 75628032 - 0 - - - - 3 - MC4zMzMzMzI5OQA - - - 6 - System - headerTextColor - - - - - 67239424 - 33685504 - - 0 - 0 - 0 - NO - - 1 - YES - YES - - - - 3.050000e+02 - 4.000000e+01 - 1.000000e+03 - - 75628032 - 0 - Name - - - - - - 337772096 - 2048 - Text Cell - - - - 6 - System - controlBackgroundColor - - - - - 3 - YES - - - - 1.230000e+02 - 1.000000e+01 - 3.402823e+38 - - 75628032 - 0 - Version - - - 6 - System - headerColor - - 3 - MQA - - - - - - 337772096 - 2048 - Text Cell - - - - - - 3 - YES - - - - 3.000000e+00 - 2.000000e+00 - - - 6 - System - gridColor - - 3 - MC41AA - - - 1.700000e+01 - 1388314624 - 4 - 15 - 0 - NO + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{17, 428}, {64, 64}} + + 2 + YES + + 130560 + 33554432 + + NSImage + Managed Software Update + + 0 + 0 + 0 + NO + + YES + + + + 266 + {{97, 470}, {397, 17}} + + 2 + YES + + 68288064 + 4195328 + Software updates are available for your computer. + + LucidaGrande-Bold + 13 + 16 + + + + 6 + System + controlColor + + 3 + MC42NjY2NjY2NjY3AA - {{1, 17}, {455, 154}} - - - - - 4 - - - - 256 - {{456, 17}, {15, 154}} - - - _doScroller: - 3.700000e+01 - 1.947368e-01 - - - - 256 - {{-100, -100}, {455, 15}} - - 1 - - _doScroller: - 5.714286e-01 - - - - 2304 - - YES - + + 6 + System + controlTextColor + + 3 + MAA + - {{1, 0}, {455, 17}} - - - - - 4 - - {472, 172} - - - 18 - - - - - - QSAAAEEgAABBmAAAQZgAAA + + + 266 + {{97, 429}, {397, 34}} + + 2 + YES + + 67239424 + 272760832 + Updating your software may take some time. If you're not ready to update now, you can choose to update later. + + LucidaGrande + 11 + 3100 + + + + + + + + + 289 + {{386, 9}, {115, 32}} + + 2 + YES + + 67239424 + 134217728 + Update now + + LucidaGrande + 13 + 1044 + + + -2038284033 + 129 + + DQ + 200 + 25 + + + + + 289 + {{290, 9}, {96, 32}} + + 2 + YES + + 67239424 + 134217728 + Later + + + -2038284033 + 129 + + Gw + 200 + 25 + + + + + 292 + {{36, 47}, {254, 14}} + + 2 + YES + + 68288064 + 272761856 + + + + + + + + + + 274 + + YES + + + 274 + + YES + + + 274 + + YES + + + 2304 + + YES + + + 256 + {461, 141} + + 2 + YES + + + 256 + {461, 17} + + 2 + + + + + 256 + {{462, 0}, {16, 17}} + + 2 + + + YES + + 18 + 18 + 18 + + 75628096 + 2048 + + + + 3 + MC4zMzMzMzI5OQA + + + 6 + System + headerTextColor + + + + + 67239424 + 33685504 + + 0 + 0 + 0 + NO + + 1 + YES + + + + 271 + 40 + 1000 + + 75628096 + 2048 + Name + + + + + + 337772096 + 2048 + Text Cell + + + + 6 + System + controlBackgroundColor + + + + + 3 + YES + + + + 80 + 32 + 1000 + + 75628096 + 2048 + Version + + + 6 + System + headerColor + + 3 + MQA + + + + + + 337772096 + 2048 + Text Cell + + + + + + 3 + YES + + + + 80 + 32 + 3.4028234663852886e+38 + + 75628096 + 2048 + Size + + + + + + 337772096 + 2048 + Text Cell + + + + + + 3 + YES + + + + 3 + 2 + + + 6 + System + gridColor + + 3 + MC41AA + + + 17 + 1388314624 + + + 4 + 15 + 0 + NO + 0 + + + {{1, 17}, {461, 141}} + + + 2 + + + 4 + + + + 256 + {{462, 17}, {15, 141}} + + 2 + + _doScroller: + 0.94736842105263153 + + + + -2147483392 + {{-100, -100}, {455, 15}} + + 2 + 1 + + _doScroller: + 0.57142859999999995 + + + + 2304 + + YES + + + {{1, 0}, {461, 17}} + + + 2 + + + 4 + + + + {478, 159} + + + 2 + 18 + + + + + + QSAAAEEgAABBmAAAQZgAAA + + + {478, 159} + + 2 + NSView + + + + 274 + + YES + + + 274 + + YES + + YES + Apple HTML pasteboard type + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple URL pasteboard type + Apple Web Archive pasteboard type + NSColor pasteboard type + NSFilenamesPboardType + NSStringPboardType + NeXT RTFD pasteboard type + NeXT Rich Text Format v1.0 pasteboard type + NeXT TIFF v4.0 pasteboard type + WebURLsWithTitlesPboardType + public.png + public.url + public.url-name + + + {478, 169} + + + 2 + + + + + + YES + + YES + WebKitDefaultFixedFontSize + WebKitDefaultFontSize + WebKitJavaEnabled + WebKitJavaScriptCanOpenWindowsAutomatically + WebKitJavaScriptEnabled + WebKitMinimumFontSize + WebKitPluginsEnabled + WebKitStandardFont + + + YES + + + + + + + + Lucida Grande + + + + NO + YES + + + {{0, 168}, {478, 169}} + + 2 + NSView + + + {{17, 69}, {478, 337}} + + 2 + + + + 292 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{17, 46}, {16, 16}} + + 2 + YES + + 67239424 + 33816576 + + LucidaGrande + 9 + 3614 + + 0 + 0 + 0 + NO + + YES + + + + 292 + {{11, 9}, {165, 32}} + + 2 + YES + + 67239424 + 134217728 + Optional software... + + + -2038284033 + 129 + + Gw + 200 + 25 + + + {512, 512} + + 2 - {472, 172} - - NSView + Updates + + - - - 274 - - YES - - - 274 - - YES - + + 2 + + + 256 + + YES + + + 274 + YES - Apple HTML pasteboard type - Apple PDF pasteboard type - Apple PICT pasteboard type - Apple URL pasteboard type - Apple Web Archive pasteboard type - NSColor pasteboard type - NSFilenamesPboardType - NSStringPboardType - NeXT RTFD pasteboard type - NeXT Rich Text Format v1.0 pasteboard type - NeXT TIFF v4.0 pasteboard type - WebURLsWithTitlesPboardType - public.png - public.url - public.url-name - - - {472, 203} - - - - - - - - YES - - YES - WebKitAllowAnimatedImageLoopingPreferenceKey - WebKitAllowAnimatedImagesPreferenceKey - WebKitDefaultFixedFontSize - WebKitDefaultFontSize - WebKitJavaEnabled - WebKitJavaScriptCanOpenWindowsAutomatically - WebKitJavaScriptEnabled - WebKitMinimumFontSize - WebKitPluginsEnabled - WebKitStandardFont + + + 274 + + YES + + + 2304 + + YES + + + 256 + {461, 140} + + YES + + + 256 + {461, 17} + + + + + + 256 + {{462, 0}, {16, 17}} + + + + YES + + 18 + 18 + 18 + + 75628096 + 2048 + + + + 3 + MC4zMzMzMzI5ODU2AA + + + + + 67239424 + 0 + + + + 1211912703 + 2 + + NSImage + NSSwitch + + + NSSwitch + + + + 200 + 25 + + 3 + YES + YES + + + + 224 + 40 + 10000 + + 75628096 + 2048 + Name + + + 3 + MC4zMzMzMzI5ODU2AA + + + + + 67239488 + 6144 + Text Cell + + + + + + 3 + YES + + + + 60 + 40 + 1000 + + 75628096 + 2048 + Version + + + + + + 67239488 + 6144 + Text Cell + + + + + + 3 + YES + + + + 60 + 40 + 1000 + + 75628096 + 2048 + Size + + + + + + 67239488 + 6144 + Text Cell + + + + + + 3 + YES + + + + 84 + 40 + 1000 + + 75628096 + 2048 + Status + + + + + + 67239488 + 137216 + Text Cell + + LucidaGrande + 11 + 16 + + + + + + 3 + YES + + + + 3 + 2 + + + 17 + 1388314624 + + + 4 + 15 + 0 + NO + 0 + + + {{1, 17}, {461, 140}} + + + + + 4 + + + + 256 + {{462, 17}, {15, 140}} + + + _doScroller: + 0.91228070175438591 + + + + -2147483392 + {{-100, -100}, {423, 15}} + + 1 + + _doScroller: + 1 + 0.8493975903614458 + + + + 2304 + + YES + + + {{1, 0}, {461, 17}} + + + + + 4 + + + + {478, 158} + + + 18 + + + + + + QSAAAEEgAABBmAAAQZgAAA - - YES - - - - - - - - - - Lucida Grande + + + 274 + + YES + + YES + Apple HTML pasteboard type + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple URL pasteboard type + Apple Web Archive pasteboard type + NSColor pasteboard type + NSFilenamesPboardType + NSStringPboardType + NeXT RTFD pasteboard type + NeXT Rich Text Format v1.0 pasteboard type + NeXT TIFF v4.0 pasteboard type + WebURLsWithTitlesPboardType + public.png + public.url + public.url-name + + + {{0, 167}, {478, 170}} + + + + + + NO + YES + {{17, 69}, {478, 337}} + + + + + 289 + {{253, 9}, {96, 32}} + + YES + + 67239424 + 134217728 + Cancel + + + -2038284033 + 129 + + Gw + 200 + 25 + + + + + 289 + {{349, 9}, {152, 32}} + + YES + + 604110336 + 134217728 + Add or Remove + + + -2038284033 + 129 + + + 200 + 25 + + + + + 268 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{17, 428}, {64, 64}} + + 2 + YES + + 130560 + 33554432 + + 0 + 0 + 0 + NO + + YES + + + + 266 + {{97, 470}, {397, 17}} + + 2 + YES + + 68288064 + 4195328 + Add or remove optional software + + + + + + + + + 266 + {{97, 429}, {397, 34}} + + 2 + YES + + 67239424 + 272760832 + Check an item to have it installed. Uncheck an item to have it removed. + + + + + - NO - YES + {512, 512} - {{0, 181}, {472, 203}} - - NSView + Optional software + + - {{20, 60}, {472, 384}} - - - - - 292 - + + + 6 + YES + YES + YES - - YES - Apple PDF pasteboard type - Apple PICT pasteboard type - Apple PNG pasteboard type - NSFilenamesPboardType - NeXT Encapsulated PostScript v1.2 pasteboard type - NeXT TIFF v4.0 pasteboard type - + - {{20, 22}, {16, 16}} - - YES - - 67239424 - 33816576 - - LucidaGrande - 9.000000e+00 - 3614 - - 0 - 0 - 0 - NO - - YES - {512, 546} + {512, 518} + 2 {{0, 0}, {1440, 878}} {512, 422} - {3.40282e+38, 3.40282e+38} + {1.79769e+308, 1.79769e+308} - Managed_Software_UpdateAppDelegate + MSUAppDelegate MSUWebViewPolicyDelegate - MSUWindowController + MSUMainWindowController + YES name version image + size + count YES @@ -1108,6 +1629,190 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg YES YES + + MSUOptionalInstallsViewController + + + + YES + installed + name + version + install + enabled + status + + YES + + YES + YES + YES + YES + YES + + + 1 + 2 + {{335, 627}, {532, 123}} + 1946157056 + Managed Software Update + NSWindow + + {1.79769e+308, 1.79769e+308} + + + 256 + + YES + + + 289 + {{422, 12}, {96, 32}} + + YES + + -2080244224 + 134217728 + Stop + + + -2038284033 + 129 + + + 200 + 25 + + + + + 1290 + + {{99, 61}, {415, 20}} + + 16394 + 20 + 100 + + + + 266 + {{98, 86}, {412, 17}} + + YES + + 68288064 + 272630784 + + + + + + + + + + 266 + {{98, 43}, {417, 14}} + + YES + + 68288064 + 272761856 + + + + + + + + + + 268 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{20, 39}, {64, 64}} + + YES + + 130560 + 33554432 + + 0 + 3 + 0 + NO + + YES + + + {532, 123} + + + {{0, 0}, {1440, 878}} + {1.79769e+308, 1.79769e+308} + + + MSUStatusWindowController + + + 1 + 2 + {{196, 240}, {480, 270}} + 603984896 + BackdropWindow + BorderlessWindow + + {1.79769e+308, 1.79769e+308} + + + 256 + + YES + + + 274 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {480, 270} + + YES + + 130560 + 33554432 + 0 + 0 + 0 + NO + + YES + + + {480, 270} + + {{0, 0}, {1440, 878}} + {1.79769e+308, 1.79769e+308} + @@ -1336,46 +2041,6 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg 374 - - - contentArray: updatelist - - - - - - contentArray: updatelist - contentArray - updatelist - 2 - - - 408 - - - - descriptionView - - - - 418 - - - - laterBtnClicked: - - - - 419 - - - - updateNowBtnClicked: - - - - 420 - value: arrangedObjects.image @@ -1392,38 +2057,6 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg 422 - - - window_controller - - - - 432 - - - - delegate - - - - 433 - - - - array_controller - - - - 434 - - - - tableView - - - - 435 - policyDelegate @@ -1453,7 +2086,7 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg arrangedObjects.version NSConditionallySetsEditable - + 2 @@ -1473,28 +2106,212 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg arrangedObjects.name NSConditionallySetsEditable - + 2 441 + + + contentArray: optionallist + + + + + + contentArray: optionallist + contentArray + optionallist + 2 + + + 490 + + + + array_controller + + + + 505 + + + + cancelBtnClicked: + + + + 536 + + + + policyDelegate + + + + 537 + + + + delegate + + + + 538 + + + + descriptionView + + + + 539 + + + + tableView + + + + 540 + + + + view + + + + 541 + + + + theWindow + + + + 542 + + + + theTabView + + + + 554 + + + + descriptionView + + + + 556 + + + + optionalSoftwareBtn + + + + 557 + restartImageFld - + - 444 + 558 restartInfoFld - + - 445 + 559 + + + + tableView + + + + 560 + + + + view + + + + 561 + + + + laterBtnClicked: + + + + 562 + + + + optionalSoftwareBtnClicked: + + + + 563 + + + + updateNowBtnClicked: + + + + 564 + + + + optional_array_controller + + + + 565 + + + + update_array_controller + + + + 566 + + + + optional_view_controller + + + + 569 + + + + update_view_controller + + + + 570 + + + + window + + + + 571 @@ -1502,15 +2319,376 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg - 446 + 572 + + + + window_controller + + + + 573 + + + + window_controller + + + + 574 - updateNowBtnClicked: - - + AddRemoveBtnClicked: + + - 447 + 575 + + + + delegate + + + + 576 + + + + contentArray: updatelist + + + + + + contentArray: updatelist + contentArray + updatelist + 2 + + + 579 + + + + array_controller + + + + 580 + + + + value: arrangedObjects.size + + + + + + value: arrangedObjects.size + value + arrangedObjects.size + 2 + + + 584 + + + + value: arrangedObjects.install + + + + + + value: arrangedObjects.install + value + arrangedObjects.install + + YES + + YES + NSConditionallySetsEnabled + NSCreatesSortDescriptor + + + YES + + + + + 2 + + + 610 + + + + editable: arrangedObjects.enabled + + + + + + editable: arrangedObjects.enabled + editable + arrangedObjects.enabled + 2 + + + 613 + + + + enabled: arrangedObjects.enabled + + + + + + enabled: arrangedObjects.enabled + enabled + arrangedObjects.enabled + + 2 + + + 615 + + + + value: arrangedObjects.version + + + + + + value: arrangedObjects.version + value + arrangedObjects.version + + YES + + YES + NSAllowsEditingMultipleValuesSelection + NSConditionallySetsEditable + + + YES + + + + + 2 + + + 619 + + + + value: arrangedObjects.name + + + + + + value: arrangedObjects.name + value + arrangedObjects.name + + YES + + YES + NSAllowsEditingMultipleValuesSelection + NSConditionallySetsEditable + + + YES + + + + + 2 + + + 620 + + + + value: arrangedObjects.size + + + + + + value: arrangedObjects.size + value + arrangedObjects.size + + YES + + YES + NSAllowsEditingMultipleValuesSelection + NSConditionallySetsEditable + + + YES + + + + + 2 + + + 622 + + + + itemCheckBoxClicked: + + + + 626 + + + + AddRemoveBtn + + + + 627 + + + + value: arrangedObjects.status + + + + + + value: arrangedObjects.status + value + arrangedObjects.status + 2 + + + 631 + + + + backdropImageFld + + + + 649 + + + + messageFld + + + + 650 + + + + window + + + + 651 + + + + imageFld + + + + 652 + + + + detailFld + + + + 653 + + + + stopBtn + + + + 654 + + + + backdropWindow + + + + 655 + + + + stopBtnClicked: + + + + 656 + + + + progressIndicator + + + + 657 + + + + munkiStatusController + + + + 658 + + + + enabled: self.session_started + + + + + + enabled: self.session_started + enabled + self.session_started + + NSValueTransformerName + NSNegateBoolean + + 2 + + + 661 + + + + updateNowBtn + + + + 666 + + + + mainWindowController + + + + 672 @@ -1518,28 +2696,26 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg YES 0 - - YES - + -2 - - RmlsZSdzIE93bmVyA + + File's Owner -1 - + First Responder -3 - + Application @@ -1553,7 +2729,7 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg - + MainMenu @@ -1974,11 +3150,75 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg YES - + + Main Window 372 + + YES + + + + + + 373 + + + MSU App Delegate + + + 402 + + + + + 403 + + + Main Window Controller + + + 404 + + + Updates Array Controller + + + 483 + + + Optional Installs View Controller + + + 485 + + + OptionalItems Array Controller + + + 511 + + + YES + + + + + + + 512 + + + YES + + + + + + 513 + YES @@ -1986,17 +3226,35 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg - + + - + - 373 - - - Managed_Software_UpdateAppDelegate + 514 + + + YES + + + + + + 515 + + + YES + + + + + + + + 375 @@ -2005,7 +3263,7 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg YES - + 376 @@ -2019,7 +3277,7 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg YES - + 378 @@ -2033,7 +3291,7 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg YES - + 380 @@ -2047,7 +3305,7 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg YES - + 382 @@ -2061,7 +3319,7 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg YES - + 384 @@ -2075,7 +3333,7 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg YES - + 386 @@ -2087,19 +3345,10 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg YES - + - - - - 388 - - - YES - - - + 389 @@ -2111,25 +3360,41 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg - 390 - - + 388 + + + YES + + + 391 YES - - - + + + - 392 - + 395 + + + + + 394 + + + YES + + + + + @@ -2138,27 +3403,16 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg - 394 - - - YES - - - - + 392 + - 395 - - - - - 396 - + 400 + YES - + @@ -2171,44 +3425,34 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg + + 396 + + + YES + + + + + + 423 + + + 398 - - 400 - - - YES - - - - 401 - 402 - - - - - 403 - - - - - 404 - - - - - 423 - - + 390 + + 442 @@ -2217,21 +3461,371 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg YES - + 443 + + 516 + + + YES + + + + + + + 517 + + + YES + + + + + + 518 + + + YES + + + + + + 519 + + + + + 520 + + + + + 521 + + + + + 522 + + + YES + + + + + + + + + 523 + + + + + 524 + + + YES + + + + + + + + + + 525 + + + + + 526 + + + + + 527 + + + YES + + + + + + 528 + + + YES + + + + + + 529 + + + YES + + + + + + 530 + + + + + 531 + + + + + 532 + + + + + 543 + + + YES + + + + + + 544 + + + YES + + + + + + 545 + + + YES + + + + + + 546 + + + + + 547 + + + + + 548 + + + + + 549 + + + YES + + + + + + 550 + + + + + 555 + + + Updates View Controller + + + 581 + + + YES + + + + + + 582 + + + + + 585 + + + YES + + + + + + 586 + + + + + 628 + + + YES + + + + + + 629 + + + + + 633 + + + YES + + + + Status Window + + + 634 + + + StatusWindowController + + + 635 + + + YES + + + + BackdropWindow + + + 636 + + + YES + + + + + + 637 + + + YES + + + + + + 638 + + + + + 639 + + + YES + + + + + + + + + + 640 + + + YES + + + + + + 641 + + + YES + + + + + + 642 + + + YES + + + + + + 643 + + + + + 644 + + + YES + + + + + + 645 + + + + + 646 + + + + + 647 + + + + + 648 + + + YES - + YES - -1.IBPluginDependency - -2.IBPluginDependency -3.IBPluginDependency 103.IBPluginDependency 103.ImportedFromIB2 @@ -2350,13 +3944,13 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg 354.IBPluginDependency 354.ImportedFromIB2 371.IBEditorWindowLastContentRect + 371.IBPluginDependency 371.IBWindowTemplateEditedContentRect 371.NSWindowTemplate.visibleAtLaunch 371.editorWindowContentRectSynchronizationRect 371.windowTemplate.hasMinSize 371.windowTemplate.minSize 372.IBPluginDependency - 373.IBPluginDependency 375.IBPluginDependency 376.IBPluginDependency 377.IBPluginDependency @@ -2383,21 +3977,84 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg 398.IBPluginDependency 400.IBPluginDependency 401.IBPluginDependency - 402.IBPluginDependency - 403.IBPluginDependency 404.IBPluginDependency 423.IBPluginDependency 442.IBPluginDependency 443.IBPluginDependency + 485.IBPluginDependency 5.IBPluginDependency 5.ImportedFromIB2 + 511.IBAttributePlaceholdersKey + 511.IBPluginDependency + 512.IBPluginDependency + 513.IBPluginDependency + 513.IBUserGuides + 514.IBPluginDependency + 515.IBPluginDependency + 516.IBPluginDependency + 517.IBPluginDependency + 518.IBPluginDependency + 519.IBPluginDependency + 520.IBPluginDependency + 521.IBPluginDependency + 522.IBPluginDependency + 523.IBPluginDependency + 524.IBPluginDependency + 525.IBPluginDependency + 526.IBPluginDependency + 527.IBPluginDependency + 528.IBPluginDependency + 529.IBPluginDependency + 530.IBPluginDependency + 531.IBPluginDependency + 532.IBPluginDependency + 543.IBPluginDependency + 544.IBPluginDependency + 545.IBPluginDependency + 546.IBPluginDependency + 547.IBPluginDependency + 548.IBPluginDependency + 549.IBPluginDependency + 550.IBPluginDependency + 555.CustomClassName + 555.IBPluginDependency 56.IBPluginDependency 56.ImportedFromIB2 + 57.IBEditorWindowLastContentRect 57.IBPluginDependency 57.ImportedFromIB2 57.editorWindowContentRectSynchronizationRect 58.IBPluginDependency 58.ImportedFromIB2 + 581.IBPluginDependency + 582.IBPluginDependency + 585.IBPluginDependency + 586.IBPluginDependency + 628.IBPluginDependency + 629.IBPluginDependency + 633.IBEditorWindowLastContentRect + 633.IBPluginDependency + 633.IBWindowTemplateEditedContentRect + 633.NSWindowTemplate.visibleAtLaunch + 633.editorWindowContentRectSynchronizationRect + 635.IBEditorWindowLastContentRect + 635.IBPluginDependency + 635.IBWindowTemplateEditedContentRect + 635.NSWindowTemplate.visibleAtLaunch + 636.IBPluginDependency + 637.CustomClassName + 637.IBPluginDependency + 638.IBPluginDependency + 639.IBPluginDependency + 640.IBPluginDependency + 641.IBPluginDependency + 642.IBPluginDependency + 643.IBPluginDependency + 644.IBPluginDependency + 645.IBPluginDependency + 646.IBPluginDependency + 647.IBPluginDependency + 648.IBPluginDependency 81.IBEditorWindowLastContentRect 81.IBPluginDependency 81.ImportedFromIB2 @@ -2412,129 +4069,128 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg YES com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilderKit - com.apple.InterfaceBuilderKit com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + {{596, 852}, {216, 23}} com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + {{436, 809}, {64, 6}} com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + {{608, 612}, {275, 83}} com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + {{365, 632}, {243, 243}} com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + {{608, 612}, {167, 43}} com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + {{608, 612}, {241, 103}} com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + {{544, 743}, {197, 73}} com.apple.InterfaceBuilder.CocoaPlugin - + {{525, 802}, {197, 73}} - {{214, 816}, {462, 20}} + {{24, 833}, {462, 20}} com.apple.InterfaceBuilder.CocoaPlugin - + {74, 862} {{11, 836}, {478, 20}} com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + {{608, 612}, {215, 63}} com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - - {{175, 220}, {512, 546}} - {{175, 220}, {512, 546}} - + + {{398, 252}, {512, 518}} + com.apple.InterfaceBuilder.CocoaPlugin + {{398, 252}, {512, 518}} + {{238, 285}, {480, 360}} - + {512, 400} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -2552,7 +4208,6 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin com.apple.WebKitIBPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -2570,32 +4225,102 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + + + InitialTabViewItem + + InitialTabViewItem + + + + com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - + + YES + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.WebKitIBPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + MSUupdatesViewController + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + {{36, 650}, {313, 183}} + com.apple.InterfaceBuilder.CocoaPlugin + {{23, 794}, {245, 183}} com.apple.InterfaceBuilder.CocoaPlugin - - {{433, 793}, {140, 23}} + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{364, 506}, {532, 123}} + com.apple.InterfaceBuilder.CocoaPlugin + {{364, 506}, {532, 123}} + + {{238, 285}, {480, 360}} + {{40, 137}, {480, 270}} + com.apple.InterfaceBuilder.CocoaPlugin + {{40, 137}, {480, 270}} + + com.apple.InterfaceBuilder.CocoaPlugin + ScaledImageView + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{433, 793}, {137, 23}} + com.apple.InterfaceBuilder.CocoaPlugin + {{323, 672}, {199, 203}} com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + YES - - YES - + YES @@ -2603,19 +4328,341 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg YES - - YES - + YES - 447 + 672 YES + + BorderlessWindow + NSWindow + + IBProjectSource + BorderlessWindow.h + + + + BorderlessWindow + NSWindow + + IBUserSource + + + + + MSUAppDelegate + NSObject + + YES + + YES + mainWindowController + munkiStatusController + optional_array_controller + optional_view_controller + update_array_controller + update_view_controller + + + YES + id + id + id + id + id + id + + + + YES + + YES + mainWindowController + munkiStatusController + optional_array_controller + optional_view_controller + update_array_controller + update_view_controller + + + YES + + mainWindowController + id + + + munkiStatusController + id + + + optional_array_controller + id + + + optional_view_controller + id + + + update_array_controller + id + + + update_view_controller + id + + + + + IBProjectSource + MSUAppDelegate.py + + + + MSUMainWindowController + NSWindowController + + YES + + YES + theTabView + theWindow + + + YES + id + id + + + + YES + + YES + theTabView + theWindow + + + YES + + theTabView + id + + + theWindow + id + + + + + IBProjectSource + MSUMainWindowController.py + + + + MSUOptionalInstallsViewController + NSViewController + + YES + + YES + AddRemoveBtnClicked: + cancelBtnClicked: + itemCheckBoxClicked: + + + YES + id + id + id + + + + YES + + YES + AddRemoveBtnClicked: + cancelBtnClicked: + itemCheckBoxClicked: + + + YES + + AddRemoveBtnClicked: + id + + + cancelBtnClicked: + id + + + itemCheckBoxClicked: + id + + + + + YES + + YES + AddRemoveBtn + array_controller + descriptionView + tableView + theWindow + window_controller + + + YES + id + id + id + id + id + id + + + + YES + + YES + AddRemoveBtn + array_controller + descriptionView + tableView + theWindow + window_controller + + + YES + + AddRemoveBtn + id + + + array_controller + id + + + descriptionView + id + + + tableView + id + + + theWindow + id + + + window_controller + id + + + + + IBProjectSource + MSUOptionalInstallsViewController.py + + + + MSUStatusWindowController + NSObject + + stopBtnClicked: + id + + + stopBtnClicked: + + stopBtnClicked: + id + + + + YES + + YES + backdropImageFld + backdropWindow + detailFld + imageFld + messageFld + progressIndicator + stopBtn + window + + + YES + id + id + id + id + id + id + id + id + + + + YES + + YES + backdropImageFld + backdropWindow + detailFld + imageFld + messageFld + progressIndicator + stopBtn + window + + + YES + + backdropImageFld + id + + + backdropWindow + id + + + detailFld + id + + + imageFld + id + + + messageFld + id + + + progressIndicator + id + + + stopBtn + id + + + window + id + + + + + IBProjectSource + MSUStatusWindowController.py + + MSUWebViewPolicyDelegate NSObject @@ -2625,70 +4672,794 @@ ZHkgdG8gdXBkYXRlIG5vdywgeW91IGNhbiBjaG9vc2UgdG8gdXBkYXRlIGxhdGVyLg - MSUWindowController - NSWindowController + MSUupdatesViewController + NSViewController YES - + YES laterBtnClicked: + optionalSoftwareBtnClicked: updateNowBtnClicked: YES id id + id - + YES - + YES - descriptionView - restartImageFld - restartInfoFld - tableView - theWindow + laterBtnClicked: + optionalSoftwareBtnClicked: + updateNowBtnClicked: YES - id - id - id - id - id + + laterBtnClicked: + id + + + optionalSoftwareBtnClicked: + id + + + updateNowBtnClicked: + id + - - IBProjectSource - MSUWindowController.py - - - - Managed_Software_UpdateAppDelegate - NSObject YES - + YES array_controller + descriptionView + optionalSoftwareBtn + restartImageFld + restartInfoFld + tableView + updateNowBtn window_controller YES id id + id + id + id + id + id + id + + + + YES + + YES + array_controller + descriptionView + optionalSoftwareBtn + restartImageFld + restartInfoFld + tableView + updateNowBtn + window_controller + + + YES + + array_controller + id + + + descriptionView + id + + + optionalSoftwareBtn + id + + + restartImageFld + id + + + restartInfoFld + id + + + tableView + id + + + updateNowBtn + id + + + window_controller + id + IBProjectSource - Managed_Software_UpdateAppDelegate.py + MSUupdatesViewController.py + + + + ScaledImageView + NSImageView + + IBProjectSource + ScaledImageView.h + + + + ScaledImageView + NSImageView + + IBUserSource + + + + + + YES + + NSActionCell + NSCell + + IBFrameworkSource + AppKit.framework/Headers/NSActionCell.h + + + + NSApplication + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSApplication.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSApplicationScripting.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSColorPanel.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSHelpManager.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSPageLayout.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSUserInterfaceItemSearching.h + + + + NSArrayController + NSObjectController + + IBFrameworkSource + AppKit.framework/Headers/NSArrayController.h + + + + NSBrowser + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSBrowser.h + + + + NSButton + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSButton.h + + + + NSButtonCell + NSActionCell + + IBFrameworkSource + AppKit.framework/Headers/NSButtonCell.h + + + + NSCell + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSCell.h + + + + NSControl + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSControl.h + + + + NSController + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSController.h + + + + NSFormatter + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSFormatter.h + + + + NSImageCell + NSCell + + IBFrameworkSource + AppKit.framework/Headers/NSImageCell.h + + + + NSImageView + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSImageView.h + + + + NSManagedObjectContext + NSObject + + IBFrameworkSource + CoreData.framework/Headers/NSManagedObjectContext.h + + + + NSMatrix + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSMatrix.h + + + + NSMenu + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSMenu.h + + + + NSMenuItem + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSMenuItem.h + + + + NSMovieView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSMovieView.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSAccessibility.h + + + + NSObject + + + + NSObject + + + + NSObject + + + + NSObject + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSDictionaryController.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSDragging.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSFontManager.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSFontPanel.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSKeyValueBinding.h + + + + NSObject + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSNibLoading.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSOutlineView.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSPasteboard.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSSavePanel.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSTableView.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSToolbarItem.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSView.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSArchiver.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSClassDescription.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSError.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSFileManager.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueCoding.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueObserving.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyedArchiver.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSObject.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSObjectScripting.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSPortCoder.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSRunLoop.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptClassDescription.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptKeyValueCoding.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptObjectSpecifiers.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptWhoseTests.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSThread.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURL.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURLConnection.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURLDownload.h + + + + NSObjectController + NSController + + IBFrameworkSource + AppKit.framework/Headers/NSObjectController.h + + + + NSProgressIndicator + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSProgressIndicator.h + + + + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSInterfaceStyle.h + + + + NSResponder + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSResponder.h + + + + NSScrollView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSScrollView.h + + + + NSScroller + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSScroller.h + + + + NSSplitView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSSplitView.h + + + + NSTabView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSTabView.h + + + + NSTabViewItem + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSTabViewItem.h + + + + NSTableColumn + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSTableColumn.h + + + + NSTableHeaderView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSTableHeaderView.h + + + + NSTableView + NSControl + + + + NSText + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSText.h + + + + NSTextField + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSTextField.h + + + + NSTextFieldCell + NSActionCell + + IBFrameworkSource + AppKit.framework/Headers/NSTextFieldCell.h + + + + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSClipView.h + + + + NSView + + + + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSRulerView.h + + + + NSView + NSResponder + + + + NSViewController + NSResponder + + view + NSView + + + view + + view + NSView + + + + IBFrameworkSource + AppKit.framework/Headers/NSViewController.h + + + + NSWindow + + IBFrameworkSource + AppKit.framework/Headers/NSDrawer.h + + + + NSWindow + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSWindow.h + + + + NSWindow + + IBFrameworkSource + AppKit.framework/Headers/NSWindowScripting.h + + + + NSWindowController + NSResponder + + showWindow: + id + + + showWindow: + + showWindow: + id + + + + IBFrameworkSource + AppKit.framework/Headers/NSWindowController.h 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES ../Managed Software Update.xcodeproj 3 + + YES + + YES + Managed Software Update + NSMenuCheckmark + NSMenuMixedState + NSSwitch + + + YES + {512, 512} + {9, 8} + {7, 2} + {15, 15} + + diff --git a/code/Managed Software Update/Info.plist b/code/Managed Software Update/Info.plist index c1f604d7..3dbe61c5 100644 --- a/code/Managed Software Update/Info.plist +++ b/code/Managed Software Update/Info.plist @@ -17,11 +17,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2.0.2 + 3.0 CFBundleSignature ???? CFBundleVersion - 2.0.2 + 3.0 NSMainNibFile MainMenu NSPrincipalClass diff --git a/code/Managed Software Update/MSUAppDelegate.py b/code/Managed Software Update/MSUAppDelegate.py new file mode 100644 index 00000000..efd5ec67 --- /dev/null +++ b/code/Managed Software Update/MSUAppDelegate.py @@ -0,0 +1,367 @@ +# +# MSUAppDelegate.py +# Managed Software Update +# +# Created by Greg Neagle on 2/10/10. +# 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. + +from Foundation import * +from AppKit import * +from objc import YES, NO +import os +import munki +import PyObjCTools + +def getconsoleuser(): + from SystemConfiguration import SCDynamicStoreCopyConsoleUser + cfuser = SCDynamicStoreCopyConsoleUser( None, None, None ) + return cfuser[0] + + +class MSUAppDelegate(NSObject): + + munkiStatusController = objc.IBOutlet() + mainWindowController = objc.IBOutlet() + + update_view_controller = objc.IBOutlet() + update_array_controller = objc.IBOutlet() + + optional_view_controller = objc.IBOutlet() + optional_array_controller = objc.IBOutlet() + + _emptyImage = NSImage.imageNamed_("Empty.png") + _restartImage = NSImage.imageNamed_("RestartReq.tif") + _logoutImage = NSImage.imageNamed_("LogOutReq.tif") + _listofupdates = [] + _optionalInstalls = [] + + restart_required = False + logout_required = False + runmode = "Normal" + managedsoftwareupdate_task = None + + def applicationDidFinishLaunching_(self, sender): + NSLog(u"Managed Software Update finished launching.") + + runmode = NSUserDefaults.standardUserDefaults().stringForKey_("mode") or \ + os.environ.get("ManagedSoftwareUpdateMode") + if runmode: + self.runmode = runmode + NSLog("Runmode: %s" % runmode) + + consoleuser = getconsoleuser() + if consoleuser == None or consoleuser == u"loginwindow": + # Status Window only + NSMenu.setMenuBarVisible_(NO) + self.munkiStatusController.startMunkiStatusSession() + elif self.runmode == "MunkiStatus": + self.munkiStatusController.startMunkiStatusSession() + else: + # display updates if available; if no available updates + # trigger an update check + if not self._listofupdates: + self.getAvailableUpdates() + if self._listofupdates: + self.buildUpdateTableData() + self.mainWindowController.theWindow.makeKeyAndOrderFront_(self) + NSApp.requestUserAttention_(NSCriticalRequest) + if self._optionalInstalls: + self.buildOptionalInstallsData() + else: + # no updates available. Should we check for some? + self.checkForUpdates() + + def munkiStatusSessionEnded_(self, socketSessionResult): + consoleuser = getconsoleuser() + if self.runmode == "MunkiStatus" or consoleuser == None or consoleuser == u"loginwindow": + # Status Window only, so we should just quit + NSApp.terminate_(self) + + alertMessageText = "Update check failed" + if self.managedsoftwareupdate_task == "installwithnologout": + alertMessageText = "Install session failed" + + if socketSessionResult == -1: + # connection was dropped unexpectedly + self.mainWindowController.theWindow.makeKeyAndOrderFront_(self) + alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(alertMessageText, u"Quit", objc.nil, objc.nil, "There is a configuration problem with the managed software installer. The process ended unexpectedly. Contact your systems administrator.") + alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.mainWindowController.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil) + return + + elif socketSessionResult == -2: + # socket timed out before connection + self.mainWindowController.theWindow.makeKeyAndOrderFront_(self) + alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(alertMessageText, u"Quit", objc.nil, objc.nil, "There is a configuration problem with the managed software installer. Could not start the process. Contact your systems administrator.") + alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.mainWindowController.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil) + return + + if self.managedsoftwareupdate_task == "installwithnologout": + # we're done. + NSApp.terminate_(self) + + elif self.managedsoftwareupdate_task == "manualcheck": + self.managedsoftwareupdate_task = None + self._listofupdates = [] + self.getAvailableUpdates() + self.buildUpdateTableData() + if self._optionalInstalls: + self.buildOptionalInstallsData() + + prefs = munki.getManagedInstallsPrefs() + lastCheckResult = prefs.get("LastCheckResult") + self.mainWindowController.theWindow.makeKeyAndOrderFront_(self) + if lastCheckResult == 0: + self.noUpdatesAlert() + elif lastCheckResult == 1: + NSApp.requestUserAttention_(NSCriticalRequest) + elif lastCheckResult == -1: + alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Cannot check for updates", u"Quit", objc.nil, objc.nil, "Managed Software Update cannot contact the update server at this time.\nIf this situtation continues, contact your systems administrator.") + alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.mainWindowController.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil) + elif lastCheckResult == -2: + alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Cannot check for updates", u"Quit", objc.nil, objc.nil, "Managed Software Update failed its preflight check.\nTry again later.") + alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.mainWindowController.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil) + + def noUpdatesAlert(self): + if self._optionalInstalls: + alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Your software is up to date.", u"Quit", u"Optional software...", objc.nil, "There is no new software for your computer at this time.") + alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.mainWindowController.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil) + else: + alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Your software is up to date.", u"Quit", objc.nil, objc.nil, "There is no new software for your computer at this time.") + alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.mainWindowController.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil) + + + def checkForUpdates(self): + # kick off an update check + self.mainWindowController.theWindow.orderOut_(self) + result = munki.startUpdateCheck() + if result == 0: + self.managedsoftwareupdate_task = "manualcheck" + self.munkiStatusController.window.makeKeyAndOrderFront_(self) + self.munkiStatusController.startMunkiStatusSession() + else: + self.mainWindowController.theWindow.makeKeyAndOrderFront_(self) + alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Update check failed", u"Quit", objc.nil, objc.nil, "There is a configuration problem with the managed software installer. Could not start the update check process. Contact your systems administrator.") + alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.mainWindowController.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil) + + def applicationDidBecomeActive_(self, sender): + pass + + + def getOptionalInstalls(self): + optionalInstalls = [] + installinfo = munki.getInstallInfo() + if installinfo: + optionalInstalls = installinfo.get("optional_installs", []) + if optionalInstalls: + self._optionalInstalls = optionalInstalls + self.update_view_controller.optionalSoftwareBtn.setHidden_(NO) + else: + self.update_view_controller.optionalSoftwareBtn.setHidden_(YES) + + + def getAvailableUpdates(self): + updatelist = [] + installinfo = munki.getInstallInfo() + if installinfo: + updatelist = installinfo.get("managed_installs", []) + if installinfo.get("removals"): + removallist = installinfo.get("removals") + restartNeeded = False + showRemovalDetail = munki.getRemovalDetailPrefs() + for item in removallist: + if item.get("RestartAction") == "RequireRestart" or item.get("RestartAction") == "RecommendRestart": + restartNeeded = True + if showRemovalDetail: + if display_name in item: + item["display_name"] = item["display_name"] + " (will be removed)" + elif name in item: + item["display_name"] = item["name"] + " (will be removed)" + updatelist.append(item) + if not showRemovalDetail: + row = {} + row["display_name"] = "Software removals" + row["version"] = "" + row["description"] = "Scheduled removal of managed software." + if restartNeeded: + row["RestartAction"] = "RequireRestart" + updatelist.append(row) + + if updatelist: + self._listofupdates = updatelist + self.update_view_controller.updateNowBtn.setEnabled_(YES) + self.getOptionalInstalls() + else: + appleupdates = munki.getAppleUpdates() + if appleupdates: + self._listofupdates = appleupdates.get("AppleUpdates", []) + self.update_view_controller.updateNowBtn.setEnabled_(YES) + self.update_view_controller.optionalSoftwareBtn.setHidden_(YES) + else: + self.update_view_controller.updateNowBtn.setEnabled_(NO) + self.getOptionalInstalls() + + + def buildOptionalInstallsData(self): + table = [] + for item in self._optionalInstalls: + row = {} + row['enabled'] = objc.YES + # current install state + row['installed'] = item.get("installed", objc.NO) + # user desired state + will_be_state = objc.NO + if item.get("installed") or item.get("will_be_installed"): + will_be_state = objc.YES + if item.get("will_be_removed"): + will_be_state = objc.NO + row['install'] = will_be_state + row['itemname'] = item['name'] + row['name'] = item.get("display_name") or item['name'] + row['version'] = munki.trimVersionString(item.get("version_to_install"),3) + row['description'] = item.get("description","") + if row['installed']: + row['size'] = "-" + status = "Installed" + if item.get("will_be_removed"): + status = "Will be removed" + elif not item.get('uninstallable'): + status = "Not removable" + row['enabled'] = objc.NO + else: + row['size'] = munki.humanReadable(item.get("installer_item_size",0)) + status = "Not installed" + if item.get("will_be_installed"): + status = "Will be installed" + elif item.get("note"): + # some reason we can't install + status = item.get("note") + row['enabled'] = objc.NO + row['status'] = status + row['original_status'] = status + row_dict = NSMutableDictionary.dictionaryWithDictionary_(row) + table.append(row_dict) + + if table: + self.optional_view_controller.setOptionallist_(table) + self.optional_view_controller.tableView.deselectAll_(self) + + + def addOrRemoveOptionalSoftware(self): + # record any requested changes in installed/removal state + # then kick off an update check + optional_install_choices = {} + optional_install_choices['managed_installs'] = [] + optional_install_choices['managed_uninstalls'] = [] + for row in self.optional_array_controller.arrangedObjects(): + if row['status'] == "Installed" or row['status'] == "Will be installed": + optional_install_choices['managed_installs'].append(row['itemname']) + if row['status'] == "Will be removed": + optional_install_choices['managed_uninstalls'].append(row['itemname']) + munki.writeSelfServiceManifest(optional_install_choices) + self.checkForUpdates() + + + def buildUpdateTableData(self): + table = [] + self.restart_required = False + self.logout_required = False + for item in self._listofupdates: + row = {} + if item.get("RestartAction") == "RequireRestart" or item.get("RestartAction") == "RecommendRestart": + row['image'] = self._restartImage + self.restart_required = True + elif item.get("RestartAction") == "RequireLogout" or item.get("RestartAction") == "RecommendLogout": + row['image'] = self._logoutImage + self.logout_required = True + else: + row['image'] = self._emptyImage + row['name'] = item.get("display_name") or item.get("name","") + row['version'] = munki.trimVersionString(item.get("version_to_install"),3) + if item.get("installer_item_size"): + row['size'] = munki.humanReadable(item.get("installer_item_size")) + else: + row['size'] = "" + row['description'] = item.get("description","") + row_dict = NSDictionary.dictionaryWithDictionary_(row) + table.append(row_dict) + + self.update_view_controller.setUpdatelist_(table) + self.update_view_controller.tableView.deselectAll_(self) + if self.restart_required: + self.update_view_controller.restartInfoFld.setStringValue_(u"Restart will be required.") + self.update_view_controller.restartImageFld.setImage_(self._restartImage) + elif self.logout_required: + self.update_view_controller.restartInfoFld.setStringValue_(u"Logout will be required.") + self.update_view_controller.restartImageFld.setImage_(self._logoutImage) + + + def confirmInstallUpdates(self): + if self.mainWindowController.theWindow.isVisible() == objc.NO: + return + if len(munki.currentGUIusers()) > 1: + alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Other users logged in", u"Cancel", objc.nil, objc.nil, "There are other users logged into this computer.\nUpdating now could cause other users to lose their work.\n\nPlease try again later after the other users have logged out.") + alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.mainWindowController.theWindow, self, self.multipleUserAlertDidEnd_returnCode_contextInfo_, objc.nil) + elif self.restart_required: + alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Restart Required", u"Log out and update", u"Cancel", objc.nil, "A restart is required after updating. Log out and update now?") + alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.mainWindowController.theWindow, self, self.logoutAlertDidEnd_returnCode_contextInfo_, objc.nil) + elif self.logout_required or munki.installRequiresLogout(): + alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Logout Required", u"Log out and update", u"Cancel", objc.nil, "A logout is required before updating. Log out and update now?") + alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.mainWindowController.theWindow, self, self.logoutAlertDidEnd_returnCode_contextInfo_, objc.nil) + else: + alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Logout Recommended", u"Log out and update", u"Cancel", u"Update without logging out", "A logout is recommended before updating. Log out and update now?") + alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.mainWindowController.theWindow, self, self.logoutAlertDidEnd_returnCode_contextInfo_, objc.nil) + + + def installSessionErrorAlert(self): + alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Cannot start installation session", u"Quit", objc.nil, objc.nil, "There is a configuration problem with the managed software installer. Could not start the install session. Contact your systems administrator.") + alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.mainWindowController.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil) + + + @PyObjCTools.AppHelper.endSheetMethod + def logoutAlertDidEnd_returnCode_contextInfo_(self, alert, returncode, contextinfo): + if returncode == 0: + NSLog("User cancelled") + elif returncode == 1: + NSLog("User chose to log out") + result = munki.logoutAndUpdate() + if result: + self.installSessionErrorAlert() + elif returncode == -1: + NSLog("User chose to update without logging out") + result = munki.justUpdate() + if result: + self.installSessionErrorAlert() + else: + self.managedsoftwareupdate_task = "installwithnologout" + self.mainWindowController.theWindow.orderOut_(self) + self.munkiStatusController.window.makeKeyAndOrderFront_(self) + self.munkiStatusController.startMunkiStatusSession() + + + @PyObjCTools.AppHelper.endSheetMethod + def multipleUserAlertDidEnd_returnCode_contextInfo_(self, alert, returncode, contextinfo): + pass + + @PyObjCTools.AppHelper.endSheetMethod + def quitAlertDidEnd_returnCode_contextInfo_(self, alert, returncode, contextinfo): + if returncode == 1: + NSApp.terminate_(self) + else: + self.update_view_controller.optionalSoftwareBtn.setHidden_(NO) + self.buildOptionalInstallsData() + self.mainWindowController.theTabView.selectNextTabViewItem_(self) + + + diff --git a/code/Managed Software Update/MSUMainWindowController.py b/code/Managed Software Update/MSUMainWindowController.py new file mode 100644 index 00000000..952acce9 --- /dev/null +++ b/code/Managed Software Update/MSUMainWindowController.py @@ -0,0 +1,35 @@ +# +# MSUMainWindowController.py +# Managed Software Update +# +# Created by Greg Neagle on 2/11/10. +# 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. + + +from objc import YES, NO, IBAction, IBOutlet +from Foundation import * +from AppKit import * + +class MSUMainWindowController(NSWindowController): + ''' + Controls the main window + ''' + + theTabView = IBOutlet() + theWindow = IBOutlet() + + def windowShouldClose_(self, sender): + # just quit + NSApp.terminate_(self) diff --git a/code/Managed Software Update/MSUOptionalInstallsViewController.py b/code/Managed Software Update/MSUOptionalInstallsViewController.py new file mode 100644 index 00000000..9e29c7e1 --- /dev/null +++ b/code/Managed Software Update/MSUOptionalInstallsViewController.py @@ -0,0 +1,100 @@ +# +# MSUOptionalInstallsViewController.py +# Managed Software Update +# +# Created by Greg Neagle on 7/8/10. +# Copyright 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. + +from objc import YES, NO, IBAction, IBOutlet +from Foundation import * +from AppKit import * + +class MSUOptionalInstallsViewController(NSViewController): + ''' + Controls the optional software view of the main window + ''' + + descriptionView = IBOutlet() + tableView = IBOutlet() + theWindow = IBOutlet() + array_controller = IBOutlet() + window_controller = IBOutlet() + AddRemoveBtn = IBOutlet() + + _optionallist = NSArray.arrayWithArray_([{"installed": NO, "install": NO, "name": "", "version": "", + "description": "", "size": "", "enabled": NO, + "status": "", "original_status": ""}]) + + def optionallist(self): + return self._optionallist + objc.accessor(optionallist) # PyObjC KVO hack + + def setOptionallist_(self, newlist): + self._optionallist = NSArray.arrayWithArray_(newlist) + objc.accessor(setOptionallist_) # PyObjC KVO hack + + @IBAction + def itemCheckBoxClicked_(self, sender): + self.updateRowStatus() + #self.updateAddRemoveBtnState() + + def updateRowStatus(self): + if self.array_controller.selectedObjects(): + row = self.array_controller.selectedObjects()[0] + if row['enabled']: + if row['installed']: + if row['install']: + row['status'] = "Installed" + else: + row['status'] = "Will be removed" + else: + # not row['installed'] + if row['install']: + row['status'] = "Will be installed" + else: + row['status'] = "Not installed" + if row['status'] != row['original_status']: + self.AddRemoveBtn.setEnabled_(YES) + else: + self.updateAddRemoveBtnState() + + def updateAddRemoveBtnState(self): + userChanges = NO + for row in self.array_controller.arrangedObjects(): + if row['status'] != row['original_status']: + userChanges = YES + break + self.AddRemoveBtn.setEnabled_(userChanges) + + @IBAction + def cancelBtnClicked_(self, sender): + self.window_controller.theTabView.selectPreviousTabViewItem_(sender) + if NSApp.delegate()._listofupdates == []: + NSApp.delegate().noUpdatesAlert() + + @IBAction + def AddRemoveBtnClicked_(self, sender): + # process Adds and/or Removes + self.window_controller.theTabView.selectPreviousTabViewItem_(sender) + NSApp.delegate().addOrRemoveOptionalSoftware() + + def tableViewSelectionDidChange_(self, sender): + if self.array_controller.selectedObjects(): + row = self.array_controller.selectedObjects()[0] + self.descriptionView.mainFrame().loadHTMLString_baseURL_(row.get("description",""), None) + self.updateRowStatus() + else: + self.descriptionView.mainFrame().loadHTMLString_baseURL_(u"", None) + diff --git a/code/Managed Software Update/MSUStatusWindowController.py b/code/Managed Software Update/MSUStatusWindowController.py new file mode 100644 index 00000000..1450dcfd --- /dev/null +++ b/code/Managed Software Update/MSUStatusWindowController.py @@ -0,0 +1,294 @@ +# 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 +from Foundation import * +from SystemConfiguration import SCDynamicStoreCopyConsoleUser +from AppKit import * +import PyObjCTools + +debug = False + +class NSPropertyListSerializationException(Exception): + pass + +def readPlist(filepath): + """ + Read a .plist file from filepath. Return the unpacked root object + (which usually is a dictionary). + """ + plistData = NSData.dataWithContentsOfFile_(filepath) + dataObject, plistFormat, error = NSPropertyListSerialization.propertyListFromData_mutabilityOption_format_errorDescription_(plistData, NSPropertyListMutableContainers, None, None) + if error: + raise NSPropertyListSerializationException(error) + else: + return dataObject + + +def getLoginwindowPicture(): + desktopPicturePath = '' + loginwindowPrefsPath = "/Library/Preferences/com.apple.loginwindow.plist" + if os.path.exists(loginwindowPrefsPath): + loginwindowPrefs = 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") + + +def getconsoleuser(): + from SystemConfiguration import SCDynamicStoreCopyConsoleUser + cfuser = SCDynamicStoreCopyConsoleUser( None, None, None ) + return cfuser[0] + + +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 = 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) + \ No newline at end of file diff --git a/code/Managed Software Update/MSUWindowController.py b/code/Managed Software Update/MSUupdatesViewController.py similarity index 58% rename from code/Managed Software Update/MSUWindowController.py rename to code/Managed Software Update/MSUupdatesViewController.py index 76275ecf..d9982ee4 100644 --- a/code/Managed Software Update/MSUWindowController.py +++ b/code/Managed Software Update/MSUupdatesViewController.py @@ -1,9 +1,9 @@ # -# MSUWindowController.py +# MSUupdatesViewController.py # Managed Software Update # -# Created by Greg Neagle on 2/11/10. -# Copyright 2009-2010 Greg Neagle. +# Created by Greg Neagle on 7/8/10. +# Copyright 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. @@ -17,18 +17,23 @@ # See the License for the specific language governing permissions and # limitations under the License. - from objc import YES, NO, IBAction, IBOutlet from Foundation import * from AppKit import * -class MSUWindowController(NSWindowController): - +class MSUupdatesViewController(NSViewController): + ''' + Controls the updates view of the main window + ''' + restartInfoFld = IBOutlet() restartImageFld = IBOutlet() descriptionView = IBOutlet() tableView = IBOutlet() - theWindow = IBOutlet() + optionalSoftwareBtn = IBOutlet() + array_controller = IBOutlet() + window_controller = IBOutlet() + updateNowBtn = IBOutlet() _updatelist = NSArray.arrayWithArray_([{"image": NSImage.imageNamed_("Empty.png"), "name": "", "version": "", "description": ""}]) @@ -49,6 +54,17 @@ class MSUWindowController(NSWindowController): # alert the user to logout, proceed without logout, or cancel NSApp.delegate().confirmInstallUpdates() - def windowShouldClose_(self, sender): - # just quit - NSApp.terminate_(self) + @IBAction + def optionalSoftwareBtnClicked_(self, sender): + # switch to optional software pane + self.window_controller.theTabView.selectNextTabViewItem_(sender) + NSApp.delegate().optional_view_controller.AddRemoveBtn.setEnabled_(NO) + NSApp.delegate().buildOptionalInstallsData() + + def tableViewSelectionDidChange_(self, sender): + if self.array_controller.selectedObjects(): + row = self.array_controller.selectedObjects()[0] + self.descriptionView.mainFrame().loadHTMLString_baseURL_(row.get("description",""), None) + else: + self.descriptionView.mainFrame().loadHTMLString_baseURL_(u"", None) + diff --git a/code/Managed Software Update/Managed Software Update.xcodeproj/project.pbxproj b/code/Managed Software Update/Managed Software Update.xcodeproj/project.pbxproj index e71d671a..1803ab85 100644 --- a/code/Managed Software Update/Managed Software Update.xcodeproj/project.pbxproj +++ b/code/Managed Software Update/Managed Software Update.xcodeproj/project.pbxproj @@ -9,11 +9,15 @@ /* Begin PBXBuildFile section */ 77631A270C06C501005415CB /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77631A260C06C501005415CB /* Python.framework */; }; 77631A3F0C0748CF005415CB /* main.py in Resources */ = {isa = PBXBuildFile; fileRef = 77631A3E0C0748CF005415CB /* main.py */; }; - 7790198F0C07548A00326F66 /* Managed_Software_UpdateAppDelegate.py in Resources */ = {isa = PBXBuildFile; fileRef = 7790198E0C07548A00326F66 /* Managed_Software_UpdateAppDelegate.py */; }; + 7790198F0C07548A00326F66 /* MSUAppDelegate.py in Resources */ = {isa = PBXBuildFile; fileRef = 7790198E0C07548A00326F66 /* MSUAppDelegate.py */; }; 77C8C1F90C07829500965286 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 77C8C1F70C07829500965286 /* MainMenu.xib */; }; 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; + C0458B4B11EB888C001F1172 /* BorderlessWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = C0458B4A11EB888C001F1172 /* BorderlessWindow.m */; }; + C0458B4D11EB8899001F1172 /* ScaledImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = C0458B4C11EB8899001F1172 /* ScaledImageView.m */; }; + C0458B5111EB88C0001F1172 /* MSUStatusWindowController.py in Resources */ = {isa = PBXBuildFile; fileRef = C0458B5011EB88C0001F1172 /* MSUStatusWindowController.py */; }; + C062868911E677820009B44B /* MSUOptionalInstallsViewController.py in Resources */ = {isa = PBXBuildFile; fileRef = C062868811E677820009B44B /* MSUOptionalInstallsViewController.py */; }; C0828C801123DBC5003D5807 /* MSUWebViewPolicyDelegate.py in Resources */ = {isa = PBXBuildFile; fileRef = C0828C7F1123DBC5003D5807 /* MSUWebViewPolicyDelegate.py */; }; C0828C901123DCFF003D5807 /* ShutDownReq.tif in Resources */ = {isa = PBXBuildFile; fileRef = C0828C871123DCFF003D5807 /* ShutDownReq.tif */; }; C0828C911123DCFF003D5807 /* RestartRec.tif in Resources */ = {isa = PBXBuildFile; fileRef = C0828C881123DCFF003D5807 /* RestartRec.tif */; }; @@ -24,9 +28,11 @@ C0828C961123DCFF003D5807 /* Restart.tif in Resources */ = {isa = PBXBuildFile; fileRef = C0828C8D1123DCFF003D5807 /* Restart.tif */; }; C0828C971123DCFF003D5807 /* package.tiff in Resources */ = {isa = PBXBuildFile; fileRef = C0828C8E1123DCFF003D5807 /* package.tiff */; }; C0828C981123DCFF003D5807 /* Installer.tiff in Resources */ = {isa = PBXBuildFile; fileRef = C0828C8F1123DCFF003D5807 /* Installer.tiff */; }; - C0828CA2112461C0003D5807 /* MSUWindowController.py in Resources */ = {isa = PBXBuildFile; fileRef = C0828CA1112461C0003D5807 /* MSUWindowController.py */; }; + C0828CA2112461C0003D5807 /* MSUMainWindowController.py in Resources */ = {isa = PBXBuildFile; fileRef = C0828CA1112461C0003D5807 /* MSUMainWindowController.py */; }; C0828D1011247A37003D5807 /* FoundationPlist.py in Resources */ = {isa = PBXBuildFile; fileRef = C0828D0E11247A37003D5807 /* FoundationPlist.py */; }; C0828D1211247B3A003D5807 /* munki.py in Resources */ = {isa = PBXBuildFile; fileRef = C0828D1111247B3A003D5807 /* munki.py */; }; + C09D9A2D11E6DC7800B3E573 /* MSUupdatesViewController.py in Resources */ = {isa = PBXBuildFile; fileRef = C09D9A2C11E6DC7800B3E573 /* MSUupdatesViewController.py */; }; + C0E9E82411EFB1EB003CE81A /* Solid Aqua Blue.png in Resources */ = {isa = PBXBuildFile; fileRef = C0E9E82311EFB1EB003CE81A /* Solid Aqua Blue.png */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -39,10 +45,16 @@ 32CA4F630368D1EE00C91783 /* Managed_Software_Update_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Managed_Software_Update_Prefix.pch; sourceTree = ""; }; 77631A260C06C501005415CB /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Python.framework; path = /System/Library/Frameworks/Python.framework; sourceTree = ""; }; 77631A3E0C0748CF005415CB /* main.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = main.py; sourceTree = ""; }; - 7790198E0C07548A00326F66 /* Managed_Software_UpdateAppDelegate.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = Managed_Software_UpdateAppDelegate.py; sourceTree = ""; }; + 7790198E0C07548A00326F66 /* MSUAppDelegate.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = MSUAppDelegate.py; sourceTree = ""; }; 77C8C1F80C07829500965286 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = ""; }; 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8D1107320486CEB800E47090 /* Managed Software Update.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Managed Software Update.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + C0458B4A11EB888C001F1172 /* BorderlessWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BorderlessWindow.m; sourceTree = ""; }; + C0458B4C11EB8899001F1172 /* ScaledImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ScaledImageView.m; sourceTree = ""; }; + C0458B4E11EB88AD001F1172 /* BorderlessWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BorderlessWindow.h; sourceTree = ""; }; + C0458B4F11EB88AD001F1172 /* ScaledImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScaledImageView.h; sourceTree = ""; }; + C0458B5011EB88C0001F1172 /* MSUStatusWindowController.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = MSUStatusWindowController.py; sourceTree = ""; }; + C062868811E677820009B44B /* MSUOptionalInstallsViewController.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = MSUOptionalInstallsViewController.py; sourceTree = ""; }; C0828C7F1123DBC5003D5807 /* MSUWebViewPolicyDelegate.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = MSUWebViewPolicyDelegate.py; sourceTree = ""; }; C0828C871123DCFF003D5807 /* ShutDownReq.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = ShutDownReq.tif; sourceTree = ""; }; C0828C881123DCFF003D5807 /* RestartRec.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = RestartRec.tif; sourceTree = ""; }; @@ -53,9 +65,11 @@ C0828C8D1123DCFF003D5807 /* Restart.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Restart.tif; sourceTree = ""; }; C0828C8E1123DCFF003D5807 /* package.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = package.tiff; sourceTree = ""; }; C0828C8F1123DCFF003D5807 /* Installer.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Installer.tiff; sourceTree = ""; }; - C0828CA1112461C0003D5807 /* MSUWindowController.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = MSUWindowController.py; sourceTree = ""; }; + C0828CA1112461C0003D5807 /* MSUMainWindowController.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = MSUMainWindowController.py; sourceTree = ""; }; C0828D0E11247A37003D5807 /* FoundationPlist.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = FoundationPlist.py; sourceTree = ""; }; C0828D1111247B3A003D5807 /* munki.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = munki.py; sourceTree = ""; }; + C09D9A2C11E6DC7800B3E573 /* MSUupdatesViewController.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = MSUupdatesViewController.py; sourceTree = ""; }; + C0E9E82311EFB1EB003CE81A /* Solid Aqua Blue.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Solid Aqua Blue.png"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -75,8 +89,11 @@ isa = PBXGroup; children = ( C0828C7F1123DBC5003D5807 /* MSUWebViewPolicyDelegate.py */, - 7790198E0C07548A00326F66 /* Managed_Software_UpdateAppDelegate.py */, - C0828CA1112461C0003D5807 /* MSUWindowController.py */, + 7790198E0C07548A00326F66 /* MSUAppDelegate.py */, + C0458B5011EB88C0001F1172 /* MSUStatusWindowController.py */, + C0828CA1112461C0003D5807 /* MSUMainWindowController.py */, + C062868811E677820009B44B /* MSUOptionalInstallsViewController.py */, + C09D9A2C11E6DC7800B3E573 /* MSUupdatesViewController.py */, ); name = Classes; sourceTree = ""; @@ -123,6 +140,10 @@ 29B97315FDCFA39411CA2CEA /* Other Sources */ = { isa = PBXGroup; children = ( + C0458B4E11EB88AD001F1172 /* BorderlessWindow.h */, + C0458B4F11EB88AD001F1172 /* ScaledImageView.h */, + C0458B4C11EB8899001F1172 /* ScaledImageView.m */, + C0458B4A11EB888C001F1172 /* BorderlessWindow.m */, C0828D0E11247A37003D5807 /* FoundationPlist.py */, 32CA4F630368D1EE00C91783 /* Managed_Software_Update_Prefix.pch */, 29B97316FDCFA39411CA2CEA /* main.m */, @@ -142,6 +163,7 @@ C0828C8B1123DCFF003D5807 /* Empty.png */, C0828C8C1123DCFF003D5807 /* RestartReq.tif */, C0828C8D1123DCFF003D5807 /* Restart.tif */, + C0E9E82311EFB1EB003CE81A /* Solid Aqua Blue.png */, C0828C8E1123DCFF003D5807 /* package.tiff */, C0828C8F1123DCFF003D5807 /* Installer.tiff */, 77C8C1F70C07829500965286 /* MainMenu.xib */, @@ -205,7 +227,7 @@ files = ( 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, 77631A3F0C0748CF005415CB /* main.py in Resources */, - 7790198F0C07548A00326F66 /* Managed_Software_UpdateAppDelegate.py in Resources */, + 7790198F0C07548A00326F66 /* MSUAppDelegate.py in Resources */, 77C8C1F90C07829500965286 /* MainMenu.xib in Resources */, C0828C801123DBC5003D5807 /* MSUWebViewPolicyDelegate.py in Resources */, C0828C901123DCFF003D5807 /* ShutDownReq.tif in Resources */, @@ -217,9 +239,13 @@ C0828C961123DCFF003D5807 /* Restart.tif in Resources */, C0828C971123DCFF003D5807 /* package.tiff in Resources */, C0828C981123DCFF003D5807 /* Installer.tiff in Resources */, - C0828CA2112461C0003D5807 /* MSUWindowController.py in Resources */, + C0828CA2112461C0003D5807 /* MSUMainWindowController.py in Resources */, C0828D1011247A37003D5807 /* FoundationPlist.py in Resources */, C0828D1211247B3A003D5807 /* munki.py in Resources */, + C062868911E677820009B44B /* MSUOptionalInstallsViewController.py in Resources */, + C09D9A2D11E6DC7800B3E573 /* MSUupdatesViewController.py in Resources */, + C0458B5111EB88C0001F1172 /* MSUStatusWindowController.py in Resources */, + C0E9E82411EFB1EB003CE81A /* Solid Aqua Blue.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -231,6 +257,8 @@ buildActionMask = 2147483647; files = ( 8D11072D0486CEB800E47090 /* main.m in Sources */, + C0458B4B11EB888C001F1172 /* BorderlessWindow.m in Sources */, + C0458B4D11EB8899001F1172 /* ScaledImageView.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/code/Managed Software Update/Managed_Software_UpdateAppDelegate.py b/code/Managed Software Update/Managed_Software_UpdateAppDelegate.py deleted file mode 100644 index 094a7ff5..00000000 --- a/code/Managed Software Update/Managed_Software_UpdateAppDelegate.py +++ /dev/null @@ -1,184 +0,0 @@ -# -# Managed_Software_UpdateAppDelegate.py -# Managed Software Update -# -# Created by Greg Neagle on 2/10/10. -# 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. - -from Foundation import * -from AppKit import * -import munki -import PyObjCTools - -class Managed_Software_UpdateAppDelegate(NSObject): - - window_controller = objc.IBOutlet() - array_controller = objc.IBOutlet() - - _emptyImage = NSImage.imageNamed_("Empty.png") - _restartImage = NSImage.imageNamed_("RestartReq.tif") - _logoutImage = NSImage.imageNamed_("LogOutReq.tif") - _listofupdates = [] - - restart_required = False - logout_required = False - - def applicationDidFinishLaunching_(self, sender): - # display updates if available; if no available updates - # trigger an update check - if not self._listofupdates: - self.getAvailableUpdates() - if self._listofupdates: - self.buildTableData() - self.window_controller.theWindow.makeKeyAndOrderFront_(self) - NSApp.requestUserAttention_(NSCriticalRequest) - else: - # no updates available. Should we check for some? - result = munki.checkForUpdates() - if result == 0: - self.window_controller.theWindow.makeKeyAndOrderFront_(self) - alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Your software is up to date.", u"Quit", objc.nil, objc.nil, "There is no new software for your computer at this time.") - alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.window_controller.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil) - elif result == -1: - self.window_controller.theWindow.makeKeyAndOrderFront_(self) - alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Cannot check for updates", u"Quit", objc.nil, objc.nil, "Managed Software Update cannot contact the update server at this time.\nIf this situtation continues, contact your systems administrator.") - alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.window_controller.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil) - elif result == -2: - self.window_controller.theWindow.makeKeyAndOrderFront_(self) - alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Update check failed", u"Quit", objc.nil, objc.nil, "There is a configuration problem with the managed software installer. Could not start the update check process. Contact your systems administrator.") - alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.window_controller.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil) - - def applicationDidBecomeActive_(self, sender): - pass - - def getAvailableUpdates(self): - updatelist = [] - installinfo = munki.getInstallInfo() - if installinfo: - updatelist = installinfo.get("managed_installs", []) - if installinfo.get("removals"): - removallist = installinfo.get("removals") - restartNeeded = False - showRemovalDetail = munki.getRemovalDetailPrefs() - for item in removallist: - if item.get("RestartAction") == "RequireRestart" or item.get("RestartAction") == "RecommendRestart": - restartNeeded = True - if showRemovalDetail: - if display_name in item: - item["display_name"] = item["display_name"] + " (will be removed)" - elif name in item: - item["display_name"] = item["name"] + " (will be removed)" - updatelist.append(item) - if not showRemovalDetail: - row = {} - row["display_name"] = "Software removals" - row["version"] = "" - row["description"] = "Scheduled removal of managed software." - if restartNeeded: - row["RestartAction"] = "RequireRestart" - updatelist.append(row) - - if updatelist: - self._listofupdates = updatelist - else: - appleupdates = munki.getAppleUpdates() - if appleupdates: - self._listofupdates = appleupdates.get("AppleUpdates", []) - - - def buildTableData(self): - table = [] - self.restart_required = False - self.logout_required = False - for item in self._listofupdates: - row = {} - if item.get("RestartAction") == "RequireRestart" or item.get("RestartAction") == "RecommendRestart": - row['image'] = self._restartImage - self.restart_required = True - elif item.get("RestartAction") == "RequireLogout" or item.get("RestartAction") == "RecommendLogout": - row['image'] = self._logoutImage - self.logout_required = True - else: - row['image'] = self._emptyImage - row['name'] = item.get("display_name") or item.get("name","") - row['version'] = munki.trimVersionString(item.get("version_to_install"),3) - row['description'] = item.get("description","") - row_dict = NSDictionary.dictionaryWithDictionary_(row) - table.append(row_dict) - - self.window_controller.setUpdatelist_(table) - self.window_controller.tableView.deselectAll_(self) - if self.restart_required: - self.window_controller.restartInfoFld.setStringValue_(u"Restart will be required.") - self.window_controller.restartImageFld.setImage_(self._restartImage) - elif self.logout_required: - self.window_controller.restartInfoFld.setStringValue_(u"Logout will be required.") - self.window_controller.restartImageFld.setImage_(self._logoutImage) - - - - def tableViewSelectionDidChange_(self, sender): - if self.array_controller.selectedObjects(): - row = self.array_controller.selectedObjects()[0] - self.window_controller.descriptionView.mainFrame().loadHTMLString_baseURL_(row.get("description",""), None) - else: - self.window_controller.descriptionView.mainFrame().loadHTMLString_baseURL_(u"", None) - - - def confirmInstallUpdates(self): - if len(munki.currentGUIusers()) > 1: - alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Other users logged in", u"Cancel", objc.nil, objc.nil, "There are other users logged into this computer.\nUpdating now could cause other users to lose their work.\n\nPlease try again later after the other users have logged out.") - alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.window_controller.theWindow, self, self.multipleUserAlertDidEnd_returnCode_contextInfo_, objc.nil) - elif self.restart_required: - alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Restart Required", u"Log out and update", u"Cancel", objc.nil, "A restart is required after updating. Log out and update now?") - alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.window_controller.theWindow, self, self.logoutAlertDidEnd_returnCode_contextInfo_, objc.nil) - elif self.logout_required or munki.installRequiresLogout(): - alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Logout Required", u"Log out and update", u"Cancel", objc.nil, "A logout is required before updating. Log out and update now?") - alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.window_controller.theWindow, self, self.logoutAlertDidEnd_returnCode_contextInfo_, objc.nil) - else: - alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Logout Recommended", u"Log out and update", u"Cancel", u"Update without logging out", "A logout is recommended before updating. Log out and update now?") - alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.window_controller.theWindow, self, self.logoutAlertDidEnd_returnCode_contextInfo_, objc.nil) - - - def installSessionErrorAlert(self): - alert = NSAlert.alertWithMessageText_defaultButton_alternateButton_otherButton_informativeTextWithFormat_(u"Cannot start installation session", u"Quit", objc.nil, objc.nil, "There is a configuration problem with the managed software installer. Could not start the install session. Contact your systems administrator.") - alert.beginSheetModalForWindow_modalDelegate_didEndSelector_contextInfo_(self.window_controller.theWindow, self, self.quitAlertDidEnd_returnCode_contextInfo_, objc.nil) - - - @PyObjCTools.AppHelper.endSheetMethod - def logoutAlertDidEnd_returnCode_contextInfo_(self, alert, returncode, contextinfo): - if returncode == 0: - NSLog("User cancelled") - elif returncode == 1: - NSLog("User chose to log out") - result = munki.logoutAndUpdate() - if result: - self.installSessionErrorAlert() - elif returncode == -1: - NSLog("User chose to update without logging out") - result = munki.justUpdate() - if result: - self.installSessionErrorAlert() - else: - NSApp.terminate_(self) - - @PyObjCTools.AppHelper.endSheetMethod - def multipleUserAlertDidEnd_returnCode_contextInfo_(self, alert, returncode, contextinfo): - pass - - @PyObjCTools.AppHelper.endSheetMethod - def quitAlertDidEnd_returnCode_contextInfo_(self, alert, returncode, contextinfo): - NSApp.terminate_(self) - diff --git a/code/Managed Software Update/ScaledImageView.h b/code/Managed Software Update/ScaledImageView.h new file mode 100644 index 00000000..d45b5e2b --- /dev/null +++ b/code/Managed Software Update/ScaledImageView.h @@ -0,0 +1,27 @@ +// +// ScaledImageViewView.h +// +// Created by Greg Neagle on 5/27/09. +// +// Copyright 2009 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 + + +@interface ScaledImageView : NSImageView + +@end diff --git a/code/Managed Software Update/ScaledImageView.m b/code/Managed Software Update/ScaledImageView.m new file mode 100644 index 00000000..92f16b7a --- /dev/null +++ b/code/Managed Software Update/ScaledImageView.m @@ -0,0 +1,76 @@ +// +// ScaledImageView.m +// +// Created by Greg Neagle on 5/27/09. +// +// Copyright 2009 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 "ScaledImageView.h" + + +@implementation ScaledImageView + +-(void)drawRect:(NSRect)rect { + + NSRect dstRect = [self bounds]; + + float sourceWidth = [[self image] size].width; + float sourceHeight = [[self image] size].height; + float targetWidth = dstRect.size.width; + float targetHeight = dstRect.size.height; + + // Calculate aspect ratios + float sourceRatio = sourceWidth / sourceHeight; + float targetRatio = targetWidth / targetHeight; + + // Determine what side of the source image to use for proportional scaling + BOOL scaleWidth = (sourceRatio <= targetRatio); + + // Proportionally scale source image + float scalingFactor, scaledWidth, scaledHeight; + if (scaleWidth) { + scalingFactor = 1.0 / sourceRatio; + scaledWidth = targetWidth; + scaledHeight = round(targetWidth * scalingFactor); + } else { + scalingFactor = sourceRatio; + scaledWidth = round(targetHeight * scalingFactor); + scaledHeight = targetHeight; + } + float scaleFactor = scaledHeight / sourceHeight; + + // Calculate compositing rectangles + NSRect sourceRect; + float destX, destY; + + // Crop from center + destX = round((scaledWidth - targetWidth) / 2.0); + destY = round((scaledHeight - targetHeight) / 2.0); + + sourceRect = NSMakeRect(destX / scaleFactor, destY / scaleFactor, + targetWidth / scaleFactor, targetHeight / scaleFactor); + + + [[self image] drawInRect:dstRect + fromRect:sourceRect + operation:NSCompositeSourceOver + fraction:1.0]; + +} + + +@end diff --git a/code/Managed Software Update/Solid Aqua Blue.png b/code/Managed Software Update/Solid Aqua Blue.png new file mode 100644 index 00000000..fc1660d7 Binary files /dev/null and b/code/Managed Software Update/Solid Aqua Blue.png differ diff --git a/code/Managed Software Update/main.py b/code/Managed Software Update/main.py index 7b18167b..a5dc28f1 100644 --- a/code/Managed Software Update/main.py +++ b/code/Managed Software Update/main.py @@ -26,9 +26,12 @@ import AppKit from PyObjCTools import AppHelper # import modules containing classes required to start application and load MainMenu.nib -import Managed_Software_UpdateAppDelegate -import MSUWindowController +import MSUAppDelegate +import MSUMainWindowController +import MSUOptionalInstallsViewController +import MSUupdatesViewController import MSUWebViewPolicyDelegate +import MSUStatusWindowController # pass control to AppKit AppHelper.runEventLoop() diff --git a/code/Managed Software Update/munki.py b/code/Managed Software Update/munki.py index 50e296a0..7dd6cf08 100644 --- a/code/Managed Software Update/munki.py +++ b/code/Managed Software Update/munki.py @@ -4,7 +4,7 @@ # Managed Software Update # # Created by Greg Neagle on 2/11/10. -# Copyright 2009-2010 Greg Neagle. +# Copyright 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. @@ -21,12 +21,21 @@ import os import subprocess import FoundationPlist -import time +#import time -from Foundation import NSDate, NSURL +#from Foundation import NSDate, NSURL _updatechecklaunchfile = "/private/tmp/.com.googlecode.munki.updatecheck.launchd" +def call(cmd): + # convenience function; works around an issue with subprocess.call + # in PyObjC in Snow Leopard + p = subprocess.Popen(cmd, bufsize=1, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + (output, err) = p.communicate() + return p.returncode + + def getManagedInstallsPrefs(): # define default values prefs = {} @@ -54,6 +63,13 @@ def getManagedInstallsPrefs(): return prefs +def writeSelfServiceManifest(optional_install_choices): + usermanifest = "/Users/Shared/.SelfServeManifest" + try: + FoundationPlist.writePlist(optional_install_choices, usermanifest) + except: + pass + def getRemovalDetailPrefs(): return getManagedInstallsPrefs().get('ShowRemovalDetail', False) @@ -76,88 +92,37 @@ def getInstallInfo(): def startUpdateCheck(): # does launchd magic to run managedsoftwareupdate as root - cmd = ["/usr/bin/touch", _updatechecklaunchfile] - if subprocess.call(cmd): - return -1 - else: - for i in range(7): - time.sleep(1) - # check to see if we were successful in starting the update - result = updateInProgress() - if result == 1: - return 1 - else: - # try again - pass - if result == -1: - try: - # this might fail if we don't own it - os.unlink(_updatechecklaunchfile) - except: - pass - return result - - -def updateInProgress(): - cmd = ['/usr/bin/killall', '-s', 'MunkiStatus'] - result = subprocess.call(cmd) - munkiStatusIsRunning = (result == 0) - if munkiStatusIsRunning: - # we're doing an update. Bring it back to the front - tellMunkiStatusToActivate() - return 1 - elif os.path.exists(_updatechecklaunchfile): - # we tried to trigger the update, but it failed? - return -1 - else: - # we're not updating right now - return 0 - - -def tellMunkiStatusToActivate(): - # uses oscascript to run an AppleScript - # ugly, but it works. - cmd = ['/usr/bin/osascript', '-e', - 'tell application "MunkiStatus" to activate'] - p = subprocess.Popen(cmd, bufsize=1, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - (output, err) = p.communicate() - + result = call(["/usr/bin/touch", _updatechecklaunchfile]) + return result + -def checkForUpdates(): - # returns 1 if we've kicked off an update check (or one is in progress), - # returns 0 if we're not going to check (because we just did) - # returns -1 if the munki server is unavailable - # returns -2 if there's an unexpected problem - - # are we checking right now (MunkiStatus.app is running)? - update = updateInProgress() - if update == 1: - return 1 - elif update == -1: - return -2 - - # when did we last check? - now = NSDate.new() - prefs = getManagedInstallsPrefs() - lastCheckedDateString = prefs.get("LastCheckDate") - if lastCheckedDateString: - lastCheckedDate = NSDate.dateWithString_(lastCheckedDateString) - if (not lastCheckedDateString) or now.timeIntervalSinceDate_(lastCheckedDate) > 10: - # we haven't checked in more than 10 seconds - result = startUpdateCheck() - if result == 1: - return 1 - else: - return -2 - else: - # we just finished checking - lastCheckResult = prefs.get("LastCheckResult") - if lastCheckResult == -1: - # check failed - return -1 - else: - return 0 +#def checkForUpdates(): +# # returns 1 if we've kicked off an update check (or one is in progress), +# # returns 0 if we're not going to check (because we just did) +# # returns -1 if the munki server is unavailable +# # returns -2 if there's an unexpected problem +# +# # when did we last check? +# now = NSDate.new() +# prefs = getManagedInstallsPrefs() +# lastCheckedDateString = prefs.get("LastCheckDate") +# if lastCheckedDateString: +# lastCheckedDate = NSDate.dateWithString_(lastCheckedDateString) +# if (not lastCheckedDateString) or now.timeIntervalSinceDate_(lastCheckedDate) > 5: +# # we haven't checked in more than 5 seconds +# result = startUpdateCheck() +# if result == 1: +# return 1 +# else: +# return -2 +# else: +# # we just finished checking +# lastCheckResult = prefs.get("LastCheckResult") +# if lastCheckResult == -1: +# # check failed +# return -1 +# else: +# return 0 def getAppleUpdates(): @@ -172,6 +137,15 @@ def getAppleUpdates(): pass return pl +def humanReadable(kbytes): + """Returns sizes in human-readable units.""" + units = [(" KB",2**10), (" MB",2**20), (" GB",2**30), (" TB",2**40)] + for suffix, limit in units: + if kbytes > limit: + continue + else: + return str(round(kbytes/float(limit/2**10),1))+suffix + def trimVersionString(versString,tupleCount): if versString == None or versString == "": return "" @@ -212,10 +186,7 @@ end ignoring if line: cmd.append("-e") cmd.append(line) - - p = subprocess.Popen(cmd, bufsize=1, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - (output, err) = p.communicate() + result = call(cmd) @@ -223,7 +194,7 @@ def logoutAndUpdate(): # touch a flag so the process that runs after # logout knows it's OK to install everything cmd = ["/usr/bin/touch", "/private/tmp/com.googlecode.munki.installatlogout"] - result = subprocess.call(cmd) + result = call(cmd) if result == 0: logoutNow() else: @@ -235,7 +206,7 @@ def justUpdate(): # we touch a file that launchd is is watching # launchd, in turn, launches managedsoftwareupdate --installwithnologout as root cmd = ["/usr/bin/touch", "/private/tmp/.com.googlecode.munki.managedinstall.launchd"] - return subprocess.call(cmd) + return call(cmd)