├── .gitignore ├── ADPassMon.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── ADPassMon.xccheckout │ └── xcuserdata │ │ └── bukowinskip.xcuserdatad │ │ ├── UserInterfaceState.xcuserstate │ │ └── WorkspaceSettings.xcsettings └── xcuserdata │ └── bukowinskip.xcuserdatad │ └── xcschemes │ ├── ADPassMon.xcscheme │ └── xcschememanagement.plist ├── ADPassMon ├── ADPassMon-Info.plist ├── ADPassMon-Prefix.pch ├── ADPassMonAppDelegate.applescript ├── Images.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512.png │ │ └── icon_512x512@2x.png ├── en.lproj │ ├── Credits.rtf │ ├── InfoPlist.strings │ └── MainMenu.xib └── main.m ├── LaunchAtLoginController.h ├── LaunchAtLoginController.m ├── README.md ├── StatusMenuController.h ├── StatusMenuController.m └── icon.icns /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.xcuserstate 3 | -------------------------------------------------------------------------------- /ADPassMon.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 39094F241338DBE4007821C2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39094F231338DBE4007821C2 /* Cocoa.framework */; }; 11 | 39094F261338DBE4007821C2 /* AppleScriptObjC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39094F251338DBE4007821C2 /* AppleScriptObjC.framework */; }; 12 | 39094F301338DBE4007821C2 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 39094F2E1338DBE4007821C2 /* InfoPlist.strings */; }; 13 | 39094F331338DBE4007821C2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 39094F321338DBE4007821C2 /* main.m */; }; 14 | 39094F361338DBE4007821C2 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 39094F341338DBE4007821C2 /* Credits.rtf */; }; 15 | 39094F381338DBE4007821C2 /* ADPassMonAppDelegate.applescript in Sources */ = {isa = PBXBuildFile; fileRef = 39094F371338DBE4007821C2 /* ADPassMonAppDelegate.applescript */; }; 16 | 39094F3B1338DBE4007821C2 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 39094F391338DBE4007821C2 /* MainMenu.xib */; }; 17 | 3910E5881341116300E7EE50 /* icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3910E5871341116300E7EE50 /* icon.icns */; }; 18 | 391FC4F21361276900D2E33C /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 391FC4F11361276900D2E33C /* README.md */; }; 19 | 39925B9F133CE6E8001C9566 /* LaunchAtLoginController.m in Sources */ = {isa = PBXBuildFile; fileRef = 39925B9E133CE6E8001C9566 /* LaunchAtLoginController.m */; }; 20 | 39952F35133BAD5800A8DD42 /* StatusMenuController.m in Sources */ = {isa = PBXBuildFile; fileRef = 39952F34133BAD5800A8DD42 /* StatusMenuController.m */; }; 21 | 39DC46FB1B6A6DF000AABB81 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 39DC46FA1B6A6DF000AABB81 /* Images.xcassets */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXCopyFilesBuildPhase section */ 25 | 39925BA9133D064F001C9566 /* CopyFiles */ = { 26 | isa = PBXCopyFilesBuildPhase; 27 | buildActionMask = 2147483647; 28 | dstPath = ""; 29 | dstSubfolderSpec = 10; 30 | files = ( 31 | ); 32 | runOnlyForDeploymentPostprocessing = 0; 33 | }; 34 | /* End PBXCopyFilesBuildPhase section */ 35 | 36 | /* Begin PBXFileReference section */ 37 | 39094F1F1338DBE4007821C2 /* ADPassMon.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ADPassMon.app; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | 39094F231338DBE4007821C2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 39 | 39094F251338DBE4007821C2 /* AppleScriptObjC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppleScriptObjC.framework; path = System/Library/Frameworks/AppleScriptObjC.framework; sourceTree = SDKROOT; }; 40 | 39094F281338DBE4007821C2 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 41 | 39094F291338DBE4007821C2 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 42 | 39094F2A1338DBE4007821C2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 43 | 39094F2D1338DBE4007821C2 /* ADPassMon-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ADPassMon-Info.plist"; sourceTree = ""; }; 44 | 39094F2F1338DBE4007821C2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 45 | 39094F311338DBE4007821C2 /* ADPassMon-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ADPassMon-Prefix.pch"; sourceTree = ""; }; 46 | 39094F321338DBE4007821C2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 47 | 39094F351338DBE4007821C2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; 48 | 39094F371338DBE4007821C2 /* ADPassMonAppDelegate.applescript */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.applescript; name = ADPassMonAppDelegate.applescript; path = ADPassMon/ADPassMonAppDelegate.applescript; sourceTree = ""; }; 49 | 39094F3A1338DBE4007821C2 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; 50 | 3910E5871341116300E7EE50 /* icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = icon.icns; path = ../icon.icns; sourceTree = ""; }; 51 | 391FC4F11361276900D2E33C /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 52 | 39925B9D133CE6E8001C9566 /* LaunchAtLoginController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LaunchAtLoginController.h; sourceTree = ""; }; 53 | 39925B9E133CE6E8001C9566 /* LaunchAtLoginController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LaunchAtLoginController.m; sourceTree = ""; }; 54 | 39952F33133BAD5800A8DD42 /* StatusMenuController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StatusMenuController.h; sourceTree = ""; }; 55 | 39952F34133BAD5800A8DD42 /* StatusMenuController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StatusMenuController.m; sourceTree = ""; }; 56 | 39DC46FA1B6A6DF000AABB81 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 57 | /* End PBXFileReference section */ 58 | 59 | /* Begin PBXFrameworksBuildPhase section */ 60 | 39094F1C1338DBE4007821C2 /* Frameworks */ = { 61 | isa = PBXFrameworksBuildPhase; 62 | buildActionMask = 2147483647; 63 | files = ( 64 | 39094F241338DBE4007821C2 /* Cocoa.framework in Frameworks */, 65 | 39094F261338DBE4007821C2 /* AppleScriptObjC.framework in Frameworks */, 66 | ); 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | /* End PBXFrameworksBuildPhase section */ 70 | 71 | /* Begin PBXGroup section */ 72 | 39094F141338DBE4007821C2 = { 73 | isa = PBXGroup; 74 | children = ( 75 | 391FC4F11361276900D2E33C /* README.md */, 76 | 39F99903133A5F19002DAED5 /* Classes */, 77 | 39094F2B1338DBE4007821C2 /* ADPassMon */, 78 | 39094F221338DBE4007821C2 /* Frameworks */, 79 | 39094F201338DBE4007821C2 /* Products */, 80 | ); 81 | sourceTree = ""; 82 | }; 83 | 39094F201338DBE4007821C2 /* Products */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | 39094F1F1338DBE4007821C2 /* ADPassMon.app */, 87 | ); 88 | name = Products; 89 | sourceTree = ""; 90 | }; 91 | 39094F221338DBE4007821C2 /* Frameworks */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 39094F251338DBE4007821C2 /* AppleScriptObjC.framework */, 95 | 39094F231338DBE4007821C2 /* Cocoa.framework */, 96 | 39094F271338DBE4007821C2 /* Other Frameworks */, 97 | ); 98 | name = Frameworks; 99 | sourceTree = ""; 100 | }; 101 | 39094F271338DBE4007821C2 /* Other Frameworks */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 39094F281338DBE4007821C2 /* AppKit.framework */, 105 | 39094F291338DBE4007821C2 /* CoreData.framework */, 106 | 39094F2A1338DBE4007821C2 /* Foundation.framework */, 107 | ); 108 | name = "Other Frameworks"; 109 | sourceTree = ""; 110 | }; 111 | 39094F2B1338DBE4007821C2 /* ADPassMon */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 39094F391338DBE4007821C2 /* MainMenu.xib */, 115 | 39DC46FA1B6A6DF000AABB81 /* Images.xcassets */, 116 | 39094F2C1338DBE4007821C2 /* Supporting Files */, 117 | ); 118 | path = ADPassMon; 119 | sourceTree = ""; 120 | }; 121 | 39094F2C1338DBE4007821C2 /* Supporting Files */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 3910E5871341116300E7EE50 /* icon.icns */, 125 | 39094F2D1338DBE4007821C2 /* ADPassMon-Info.plist */, 126 | 39094F2E1338DBE4007821C2 /* InfoPlist.strings */, 127 | 39094F311338DBE4007821C2 /* ADPassMon-Prefix.pch */, 128 | 39094F321338DBE4007821C2 /* main.m */, 129 | 39094F341338DBE4007821C2 /* Credits.rtf */, 130 | ); 131 | name = "Supporting Files"; 132 | sourceTree = ""; 133 | }; 134 | 39F99903133A5F19002DAED5 /* Classes */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | 39094F371338DBE4007821C2 /* ADPassMonAppDelegate.applescript */, 138 | 39952F33133BAD5800A8DD42 /* StatusMenuController.h */, 139 | 39952F34133BAD5800A8DD42 /* StatusMenuController.m */, 140 | 39925B9D133CE6E8001C9566 /* LaunchAtLoginController.h */, 141 | 39925B9E133CE6E8001C9566 /* LaunchAtLoginController.m */, 142 | ); 143 | name = Classes; 144 | sourceTree = ""; 145 | }; 146 | /* End PBXGroup section */ 147 | 148 | /* Begin PBXNativeTarget section */ 149 | 39094F1E1338DBE4007821C2 /* ADPassMon */ = { 150 | isa = PBXNativeTarget; 151 | buildConfigurationList = 39094F3E1338DBE4007821C2 /* Build configuration list for PBXNativeTarget "ADPassMon" */; 152 | buildPhases = ( 153 | 39094F1B1338DBE4007821C2 /* Sources */, 154 | 39094F1C1338DBE4007821C2 /* Frameworks */, 155 | 39094F1D1338DBE4007821C2 /* Resources */, 156 | 39925BA9133D064F001C9566 /* CopyFiles */, 157 | ); 158 | buildRules = ( 159 | ); 160 | dependencies = ( 161 | ); 162 | name = ADPassMon; 163 | productName = ADPassMon; 164 | productReference = 39094F1F1338DBE4007821C2 /* ADPassMon.app */; 165 | productType = "com.apple.product-type.application"; 166 | }; 167 | /* End PBXNativeTarget section */ 168 | 169 | /* Begin PBXProject section */ 170 | 39094F161338DBE4007821C2 /* Project object */ = { 171 | isa = PBXProject; 172 | attributes = { 173 | LastUpgradeCheck = 0630; 174 | }; 175 | buildConfigurationList = 39094F191338DBE4007821C2 /* Build configuration list for PBXProject "ADPassMon" */; 176 | compatibilityVersion = "Xcode 3.2"; 177 | developmentRegion = English; 178 | hasScannedForEncodings = 0; 179 | knownRegions = ( 180 | en, 181 | ); 182 | mainGroup = 39094F141338DBE4007821C2; 183 | productRefGroup = 39094F201338DBE4007821C2 /* Products */; 184 | projectDirPath = ""; 185 | projectRoot = ""; 186 | targets = ( 187 | 39094F1E1338DBE4007821C2 /* ADPassMon */, 188 | ); 189 | }; 190 | /* End PBXProject section */ 191 | 192 | /* Begin PBXResourcesBuildPhase section */ 193 | 39094F1D1338DBE4007821C2 /* Resources */ = { 194 | isa = PBXResourcesBuildPhase; 195 | buildActionMask = 2147483647; 196 | files = ( 197 | 39094F301338DBE4007821C2 /* InfoPlist.strings in Resources */, 198 | 39094F361338DBE4007821C2 /* Credits.rtf in Resources */, 199 | 39094F3B1338DBE4007821C2 /* MainMenu.xib in Resources */, 200 | 39DC46FB1B6A6DF000AABB81 /* Images.xcassets in Resources */, 201 | 3910E5881341116300E7EE50 /* icon.icns in Resources */, 202 | 391FC4F21361276900D2E33C /* README.md in Resources */, 203 | ); 204 | runOnlyForDeploymentPostprocessing = 0; 205 | }; 206 | /* End PBXResourcesBuildPhase section */ 207 | 208 | /* Begin PBXSourcesBuildPhase section */ 209 | 39094F1B1338DBE4007821C2 /* Sources */ = { 210 | isa = PBXSourcesBuildPhase; 211 | buildActionMask = 2147483647; 212 | files = ( 213 | 39094F331338DBE4007821C2 /* main.m in Sources */, 214 | 39094F381338DBE4007821C2 /* ADPassMonAppDelegate.applescript in Sources */, 215 | 39952F35133BAD5800A8DD42 /* StatusMenuController.m in Sources */, 216 | 39925B9F133CE6E8001C9566 /* LaunchAtLoginController.m in Sources */, 217 | ); 218 | runOnlyForDeploymentPostprocessing = 0; 219 | }; 220 | /* End PBXSourcesBuildPhase section */ 221 | 222 | /* Begin PBXVariantGroup section */ 223 | 39094F2E1338DBE4007821C2 /* InfoPlist.strings */ = { 224 | isa = PBXVariantGroup; 225 | children = ( 226 | 39094F2F1338DBE4007821C2 /* en */, 227 | ); 228 | name = InfoPlist.strings; 229 | sourceTree = ""; 230 | }; 231 | 39094F341338DBE4007821C2 /* Credits.rtf */ = { 232 | isa = PBXVariantGroup; 233 | children = ( 234 | 39094F351338DBE4007821C2 /* en */, 235 | ); 236 | name = Credits.rtf; 237 | sourceTree = ""; 238 | }; 239 | 39094F391338DBE4007821C2 /* MainMenu.xib */ = { 240 | isa = PBXVariantGroup; 241 | children = ( 242 | 39094F3A1338DBE4007821C2 /* en */, 243 | ); 244 | name = MainMenu.xib; 245 | sourceTree = ""; 246 | }; 247 | /* End PBXVariantGroup section */ 248 | 249 | /* Begin XCBuildConfiguration section */ 250 | 39094F3C1338DBE4007821C2 /* Debug */ = { 251 | isa = XCBuildConfiguration; 252 | buildSettings = { 253 | CLANG_WARN_BOOL_CONVERSION = YES; 254 | CLANG_WARN_CONSTANT_CONVERSION = YES; 255 | CLANG_WARN_EMPTY_BODY = YES; 256 | CLANG_WARN_ENUM_CONVERSION = YES; 257 | CLANG_WARN_INT_CONVERSION = YES; 258 | CLANG_WARN_UNREACHABLE_CODE = YES; 259 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 260 | ENABLE_STRICT_OBJC_MSGSEND = YES; 261 | GCC_C_LANGUAGE_STANDARD = gnu99; 262 | GCC_NO_COMMON_BLOCKS = YES; 263 | GCC_OPTIMIZATION_LEVEL = 0; 264 | GCC_PREPROCESSOR_DEFINITIONS = DEBUG; 265 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 266 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 267 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 268 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 269 | GCC_WARN_UNDECLARED_SELECTOR = YES; 270 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 271 | GCC_WARN_UNUSED_FUNCTION = YES; 272 | GCC_WARN_UNUSED_VARIABLE = YES; 273 | INSTALL_PATH = /Applications/Utilities; 274 | MACOSX_DEPLOYMENT_TARGET = 10.8; 275 | ONLY_ACTIVE_ARCH = YES; 276 | SDKROOT = macosx; 277 | }; 278 | name = Debug; 279 | }; 280 | 39094F3D1338DBE4007821C2 /* Release */ = { 281 | isa = XCBuildConfiguration; 282 | buildSettings = { 283 | CLANG_WARN_BOOL_CONVERSION = YES; 284 | CLANG_WARN_CONSTANT_CONVERSION = YES; 285 | CLANG_WARN_EMPTY_BODY = YES; 286 | CLANG_WARN_ENUM_CONVERSION = YES; 287 | CLANG_WARN_INT_CONVERSION = YES; 288 | CLANG_WARN_UNREACHABLE_CODE = YES; 289 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 290 | ENABLE_STRICT_OBJC_MSGSEND = YES; 291 | GCC_C_LANGUAGE_STANDARD = gnu99; 292 | GCC_NO_COMMON_BLOCKS = YES; 293 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 294 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 295 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 296 | GCC_WARN_UNDECLARED_SELECTOR = YES; 297 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 298 | GCC_WARN_UNUSED_FUNCTION = YES; 299 | GCC_WARN_UNUSED_VARIABLE = YES; 300 | INSTALL_PATH = /Applications/Utilities; 301 | MACOSX_DEPLOYMENT_TARGET = 10.8; 302 | ONLY_ACTIVE_ARCH = YES; 303 | OSACOMPILE_EXECUTE_ONLY = YES; 304 | SDKROOT = macosx; 305 | }; 306 | name = Release; 307 | }; 308 | 39094F3F1338DBE4007821C2 /* Debug */ = { 309 | isa = XCBuildConfiguration; 310 | buildSettings = { 311 | ALWAYS_SEARCH_USER_PATHS = NO; 312 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 313 | CODE_SIGN_IDENTITY = "Mac Developer"; 314 | COMBINE_HIDPI_IMAGES = YES; 315 | COPY_PHASE_STRIP = NO; 316 | FRAMEWORK_SEARCH_PATHS = ( 317 | "$(inherited)", 318 | "\"$(SRCROOT)\"", 319 | "\"$(SRCROOT)/../../Desktop\"", 320 | ); 321 | GCC_DYNAMIC_NO_PIC = NO; 322 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 323 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 324 | GCC_PREFIX_HEADER = "ADPassMon/ADPassMon-Prefix.pch"; 325 | INFOPLIST_FILE = "ADPassMon/ADPassMon-Info.plist"; 326 | MACOSX_DEPLOYMENT_TARGET = 10.8; 327 | ONLY_ACTIVE_ARCH = YES; 328 | PRODUCT_NAME = "$(TARGET_NAME)"; 329 | WRAPPER_EXTENSION = app; 330 | }; 331 | name = Debug; 332 | }; 333 | 39094F401338DBE4007821C2 /* Release */ = { 334 | isa = XCBuildConfiguration; 335 | buildSettings = { 336 | ALWAYS_SEARCH_USER_PATHS = NO; 337 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 338 | CODE_SIGN_IDENTITY = "Mac Developer"; 339 | COMBINE_HIDPI_IMAGES = YES; 340 | COPY_PHASE_STRIP = YES; 341 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 342 | FRAMEWORK_SEARCH_PATHS = ( 343 | "$(inherited)", 344 | "\"$(SRCROOT)\"", 345 | "\"$(SRCROOT)/../../Desktop\"", 346 | ); 347 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 348 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 349 | GCC_PREFIX_HEADER = "ADPassMon/ADPassMon-Prefix.pch"; 350 | INFOPLIST_FILE = "ADPassMon/ADPassMon-Info.plist"; 351 | MACOSX_DEPLOYMENT_TARGET = 10.8; 352 | ONLY_ACTIVE_ARCH = YES; 353 | PRODUCT_NAME = "$(TARGET_NAME)"; 354 | WRAPPER_EXTENSION = app; 355 | }; 356 | name = Release; 357 | }; 358 | /* End XCBuildConfiguration section */ 359 | 360 | /* Begin XCConfigurationList section */ 361 | 39094F191338DBE4007821C2 /* Build configuration list for PBXProject "ADPassMon" */ = { 362 | isa = XCConfigurationList; 363 | buildConfigurations = ( 364 | 39094F3C1338DBE4007821C2 /* Debug */, 365 | 39094F3D1338DBE4007821C2 /* Release */, 366 | ); 367 | defaultConfigurationIsVisible = 0; 368 | defaultConfigurationName = Release; 369 | }; 370 | 39094F3E1338DBE4007821C2 /* Build configuration list for PBXNativeTarget "ADPassMon" */ = { 371 | isa = XCConfigurationList; 372 | buildConfigurations = ( 373 | 39094F3F1338DBE4007821C2 /* Debug */, 374 | 39094F401338DBE4007821C2 /* Release */, 375 | ); 376 | defaultConfigurationIsVisible = 0; 377 | defaultConfigurationName = Release; 378 | }; 379 | /* End XCConfigurationList section */ 380 | }; 381 | rootObject = 39094F161338DBE4007821C2 /* Project object */; 382 | } 383 | -------------------------------------------------------------------------------- /ADPassMon.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ADPassMon.xcodeproj/project.xcworkspace/xcshareddata/ADPassMon.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | F4285E85-B866-484E-BC76-19DED77E85AC 9 | IDESourceControlProjectName 10 | project 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 3E92D14539A59379C597C4FF4F77D5B7CEF3BCD7 14 | github.com:pmbuko/ADPassMon.git 15 | 16 | IDESourceControlProjectPath 17 | ADPassMon.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 3E92D14539A59379C597C4FF4F77D5B7CEF3BCD7 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | github.com:pmbuko/ADPassMon.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 3E92D14539A59379C597C4FF4F77D5B7CEF3BCD7 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 3E92D14539A59379C597C4FF4F77D5B7CEF3BCD7 36 | IDESourceControlWCCName 37 | ADPassMon 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /ADPassMon.xcodeproj/project.xcworkspace/xcuserdata/bukowinskip.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmbuko/ADPassMon/24057beebe7f3e93e5e52ec07bde13633203cd63/ADPassMon.xcodeproj/project.xcworkspace/xcuserdata/bukowinskip.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /ADPassMon.xcodeproj/project.xcworkspace/xcuserdata/bukowinskip.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ADPassMon.xcodeproj/xcuserdata/bukowinskip.xcuserdatad/xcschemes/ADPassMon.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 70 | 72 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /ADPassMon.xcodeproj/xcuserdata/bukowinskip.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ADPassMon.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 39094F1E1338DBE4007821C2 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /ADPassMon/ADPassMon-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en_US 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | org.pmbuko.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.11.4 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 6 25 | LSApplicationCategoryType 26 | public.app-category.utilities 27 | LSMinimumSystemVersion 28 | ${MACOSX_DEPLOYMENT_TARGET} 29 | LSUIElement 30 | 31 | NSMainNibFile 32 | MainMenu 33 | NSPrincipalClass 34 | NSApplication 35 | 36 | 37 | -------------------------------------------------------------------------------- /ADPassMon/ADPassMon-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'ADPassMon' target in the 'ADPassMon' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /ADPassMon/ADPassMonAppDelegate.applescript: -------------------------------------------------------------------------------- 1 | -- ADPassMonAppDelegate.applescript 2 | -- ADPassMon 3 | -- 4 | -- Created by Peter Bukowinski on 3/24/11 (and updated many times since) 5 | -- 6 | -- This software is released under the terms of the MIT license. 7 | -- Copyright (C) 2015 by Peter Bukowinski 8 | -- 9 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 10 | -- of this software and associated documentation files (the "Software"), to deal 11 | -- in the Software without restriction, including without limitation the rights 12 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | -- copies of the Software, and to permit persons to whom the Software is 14 | -- furnished to do so, subject to the following conditions: 15 | -- 16 | -- The above copyright notice and this permission notice shall be included in 17 | -- all copies or substantial portions of the Software. 18 | -- 19 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | -- THE SOFTWARE. 26 | --------------------------------------------------------------------------------- 27 | -- TO DO: 28 | -- 29 | -- FEATURE REQUESTS: 30 | -- - Enable mcx defaults hook for adding as login item. 31 | 32 | script ADPassMonAppDelegate 33 | 34 | --- PROPERTIES --- 35 | 36 | --- Classes 37 | property parent : class "NSObject" 38 | property NSMenu : class "NSMenu" 39 | property NSThread : class "NSThread" -- for 'sleep'-like feature 40 | property NSMenuItem : class "NSMenuItem" 41 | property NSTimer : class "NSTimer" -- so we can do stuff at regular intervals 42 | property NSUserNotificationCenter : class "NSUserNotificationCenter" -- for notification center 43 | property NSWorkspace : class "NSWorkspace" -- for sleep notification 44 | 45 | --- Objects 46 | property standardUserDefaults : missing value 47 | property statusMenu : missing value 48 | property statusMenuController : missing value 49 | property theWindow : missing value 50 | property defaults : missing value -- for saved prefs 51 | property theMessage : missing value -- for stats display in pref window 52 | property manualExpireDays : missing value 53 | property selectedMethod : missing value 54 | property thePassword : missing value 55 | property toggleNotifyButton : missing value 56 | property processTimer : missing value 57 | property domainTimer : missing value 58 | 59 | --- Booleans 60 | property first_run : true 61 | property isIdle : true 62 | property isHidden : false 63 | property isManualEnabled : false 64 | property enableNotifications : true 65 | property enableKerbMinder : false 66 | property prefsLocked : false 67 | property launchAtLogin : false 68 | property skipKerb : false 69 | property onDomain : false 70 | property passExpires : true 71 | property goEasy : false 72 | property showChangePass : false 73 | property KerbMinderInstalled : false 74 | 75 | --- Other Properties 76 | property warningDays : 14 77 | property menu_title : "[ ? ]" 78 | property accTest : 1 79 | property tooltip : "Waiting for data…" 80 | property osVersion : "" 81 | property kerb : "" 82 | property myLDAP : "" 83 | property mySearchBase : "" 84 | property expireAge : 0 85 | property expireAgeUnix : "" 86 | property expireDate: "" 87 | property expireDateUnix: "" 88 | property uAC : "" 89 | property pwdSetDate : "" 90 | property pwdSetDateUnix : 0 91 | property plistPwdSetDate : 0 92 | property pwPolicy : "" 93 | property pwPolicyButton : "OK" 94 | property today : "" 95 | property todayUnix : "" 96 | property daysUntilExp : "" 97 | property daysUntilExpNice : "" 98 | property expirationDate : "" 99 | property mavAccStatus : "" 100 | property checkInterval : 4 -- hours 101 | 102 | --- HANDLERS --- 103 | 104 | -- General error handler 105 | on errorOut_(theError, showErr) 106 | log "Script Error: " & theError 107 | --if showErr = 1 then set my theMessage to theError as text 108 | --set isIdle to false 109 | end errorOut_ 110 | 111 | -- Need to get the OS version so we can handle Kerberos differently in 10.7+ 112 | on getOS_(sender) 113 | set my osVersion to (do shell script "sw_vers -productVersion | awk -F. '{print $2}'") as integer 114 | log "Running on OS 10." & osVersion & ".x" 115 | end getOS_ 116 | 117 | -- Tests if Universal Access scripting service is enabled 118 | on accTest_(sender) 119 | log "Testing Universal Access settings…" 120 | if osVersion is less than 9 then 121 | tell application "System Events" 122 | set accStatus to get UI elements enabled 123 | end tell 124 | if accStatus is true then 125 | log " Enabled" 126 | else 127 | log " Disabled" 128 | accEnable_(me) 129 | end if 130 | else -- if we're running 10.9 or later, Accessibility is handled differently 131 | tell defaults to set my accTest to objectForKey_("accTest") 132 | if accTest as integer is 1 then 133 | if "80" is in (do shell script "/usr/bin/id -G") then -- checks if user is in admin group 134 | set accessDialog to (display dialog "ADPassMon's \"Change Password\" feature requires assistive access to open the password panel. 135 | 136 | Enable it now? (requires password)" with icon 2 buttons {"No", "Yes"} default button 2) 137 | if button returned of accessDialog is "Yes" then 138 | log " Prompting for password" 139 | try 140 | set mavAccStatus to (do shell script "sqlite3 '/Library/Application Support/com.apple.TCC/TCC.db' \"SELECT * FROM access WHERE client='org.pmbuko.ADPassMon';\"" with administrator privileges) 141 | end try 142 | if mavAccStatus is "" then 143 | log " Not enabled" 144 | try 145 | do shell script "sqlite3 '/Library/Application Support/com.apple.TCC/TCC.db' \"INSERT INTO access VALUES('kTCCServiceAccessibility','org.pmbuko.ADPassMon',0,1,1,NULL);\"" with administrator privileges 146 | set my accTest to 0 147 | tell defaults to setObject_forKey_(0, "accTest") 148 | on error theError 149 | log "Unable to set access. Error: " & theError 150 | end try 151 | else 152 | set my accTest to 0 153 | tell defaults to setObject_forKey_(0, "accTest") 154 | log " Enabled" 155 | end if 156 | end if 157 | else 158 | set my accTest to 0 159 | tell defaults to setObject_forKey_(0, "accTest") 160 | log " User not admin. Skipping." 161 | end if 162 | else 163 | log " Enabled" 164 | end if 165 | 166 | end if 167 | end accTest_ 168 | 169 | -- Prompts to enable Universal Access scripting service 170 | on accEnable_(sender) 171 | if "80" is in (do shell script "/usr/bin/id -G") then -- checks if user is in admin group 172 | activate 173 | set response to (display dialog "ADPassMon's \"Change Password\" feature requires assistive access to open the password panel. 174 | 175 | Enable it now?" with icon 2 buttons {"No", "Yes"} default button 2) 176 | if button returned of response is "Yes" then 177 | log " Prompting for password" 178 | try 179 | tell application "System Events" 180 | activate 181 | set UI elements enabled to true 182 | end tell 183 | log " Now enabled" 184 | --display dialog "Access for assistive devices is now enabled." buttons {"OK"} default button 1 185 | on error theError 186 | log " Error: " & theError 187 | activate 188 | display dialog "Could not enable access for assistive devices." buttons {"OK"} default button 1 189 | end try 190 | else -- if No is clicked 191 | log " User chose not to enable" 192 | end if 193 | else 194 | log " Skipping because user not an admin" 195 | end if 196 | end accEnable_ 197 | 198 | on KerbMinderTest_(sender) 199 | tell application "Finder" 200 | if exists "/Library/Application Support/crankd/KerbMinder.py" as POSIX file then 201 | set my KerbMinderInstalled to true 202 | else 203 | set my KerbMinderInstalled to false 204 | end if 205 | end tell 206 | end KerbMinderTest_ 207 | 208 | -- Register plist default settings 209 | on regDefaults_(sender) 210 | tell current application's NSUserDefaults to set defaults to standardUserDefaults() 211 | tell defaults to registerDefaults_({menu_title: "[ ? ]", ¬ 212 | tooltip:tooltip, ¬ 213 | fist_run:first_run, ¬ 214 | selectedMethod:0, ¬ 215 | isManualEnabled:isManualEnabled, ¬ 216 | enableNotifications:enableNotifications, ¬ 217 | checkInterval:checkInterval, ¬ 218 | expireAge:expireAge, ¬ 219 | expireDateUnix:expireDateUnix, ¬ 220 | pwdSetDate:pwdSetDate, ¬ 221 | warningDays:warningDays, ¬ 222 | prefsLocked:prefsLocked, ¬ 223 | myLDAP:myLDAP, ¬ 224 | pwPolicy:pwPolicy, ¬ 225 | pwPolicyButton:pwPolicyButton, ¬ 226 | accTest:accTest, ¬ 227 | enableKerbMinder:enableKerbMinder, ¬ 228 | launchAtLogin:launchAtLogin}) 229 | end regDefaults_ 230 | 231 | -- Get values from plist 232 | on retrieveDefaults_(sender) 233 | tell defaults to set my menu_title to objectForKey_("menu_title") 234 | tell defaults to set my first_run to objectForKey_("first_run") 235 | tell defaults to set my selectedMethod to objectForKey_("selectedMethod") as integer 236 | tell defaults to set my isManualEnabled to objectForKey_("isManualEnabled") as integer 237 | tell defaults to set my enableNotifications to objectForKey_("enableNotifications") as integer 238 | tell defaults to set my checkInterval to objectForKey_("checkInterval") as integer 239 | tell defaults to set my expireAge to objectForKey_("expireAge") as integer 240 | tell defaults to set my expireDateUnix to objectForKey_("expireDateUnix") as integer 241 | tell defaults to set my pwdSetDate to objectForKey_("pwdSetDate") as integer 242 | tell defaults to set my warningDays to objectForKey_("warningDays") 243 | tell defaults to set my prefsLocked to objectForKey_("prefsLocked") 244 | tell defaults to set my myLDAP to objectForKey_("myLDAP") 245 | tell defaults to set my pwPolicy to objectForKey_("pwPolicy") 246 | tell defaults to set my pwPolicyButton to objectForKey_("pwPolicyButton") 247 | tell defaults to set my accTest to objectForKey_("accTest") as integer 248 | tell defaults to set my enableKerbMinder to objectForKey_("enableKerbMinder") 249 | tell defaults to set my launchAtLogin to objectForKey_("launchAtLogin") 250 | end retrieveDefaults_ 251 | 252 | on notifySetup_(sender) 253 | if osVersion is less than 8 then 254 | set my enableNotifications to false 255 | --else 256 | -- set my enableNotifications to true 257 | end if 258 | end notifySetup_ 259 | 260 | -- This handler is sent daysUntilExpNice and will trigger an alert if ≤ warningDays 261 | on doNotify_(sender) 262 | if sender as integer ≤ my warningDays as integer then 263 | if osVersion is greater than 7 then 264 | if my enableNotifications as boolean is true then 265 | log "Triggering notification…" 266 | set ncTitle to "Password Expiration Warning" 267 | set ncMessage to "Your password will expire in " & sender & " days on " & expirationDate 268 | sendNotificationWithTitleAndMessage_(ncTitle, ncMessage) 269 | end if 270 | end if 271 | end if 272 | end doNotify_ 273 | 274 | on sendNotificationWithTitleAndMessage_(aTitle, aMessage) 275 | set myNotification to current application's NSUserNotification's alloc()'s init() 276 | set myNotification's title to aTitle 277 | set myNotification's informativeText to aMessage 278 | current application's NSUserNotificationCenter's defaultUserNotificationCenter's deliverNotification_(myNotification) 279 | end sendNotificationWithTitleAndMessage_ 280 | 281 | -- Trigger doProcess handler on wake from sleep 282 | on watchForWake_(sender) 283 | tell (NSWorkspace's sharedWorkspace())'s notificationCenter() to ¬ 284 | addObserver_selector_name_object_(me, "doProcessWithWait:", "NSWorkspaceDidWakeNotification", missing value) 285 | end watchForWake_ 286 | 287 | on ticketViewer_(sender) 288 | tell application "Ticket Viewer" to activate 289 | end ticketViewer_ 290 | 291 | on domainTest_(sender) 292 | set domain to (do shell script "/usr/sbin/dsconfigad -show | /usr/bin/awk '/Active Directory Domain/{print $NF}'") as text 293 | try 294 | set digResult to (do shell script "/usr/bin/dig +time=2 +tries=1 -t srv _ldap._tcp." & domain) as text 295 | on error theError 296 | log "Domain test timed out." 297 | set my onDomain to false 298 | my statusMenu's itemWithTitle_("Refresh Kerberos Ticket")'s setEnabled_(0) 299 | my statusMenu's itemWithTitle_("Change Password…")'s setEnabled_(0) 300 | return 301 | end try 302 | if "ANSWER SECTION" is in digResult then 303 | set my onDomain to true 304 | my statusMenu's itemWithTitle_("Refresh Kerberos Ticket")'s setEnabled_(1) 305 | my statusMenu's itemWithTitle_("Change Password…")'s setEnabled_(1) 306 | else 307 | set my onDomain to false 308 | log "Domain not reachable." 309 | my statusMenu's itemWithTitle_("Refresh Kerberos Ticket")'s setEnabled_(0) 310 | my statusMenu's itemWithTitle_("Change Password…")'s setEnabled_(0) 311 | end if 312 | end domainTest_ 313 | 314 | on intervalDomainTest_(sender) 315 | domainTest_(me) 316 | end intervalDomainTest_ 317 | 318 | -- Check if password is set to never expire 319 | on canPassExpire_(sender) 320 | log "Testing if password can expire…" 321 | set my uAC to (do shell script "/usr/bin/dscl localhost read /Search/Users/$USER userAccountControl | /usr/bin/awk '/:userAccountControl:/{print $2}'") 322 | if (count words of uAC) is greater than 1 then 323 | set my uAC to last word of uAC 324 | end if 325 | try 326 | if first character of uAC is "6" then 327 | set passExpires to false 328 | log " Password does NOT expire." 329 | else 330 | log " Password does expire." 331 | end if 332 | on error 333 | log " Could not determine if password expires." 334 | end try 335 | end canPassExpire_ 336 | 337 | -- Checks for kerberos ticket, necessary for auto method. Also bound to Refresh Kerb menu item. 338 | on doKerbCheck_(sender) 339 | if my onDomain is true and my skipKerb is false then 340 | if selectedMethod = 0 then 341 | if osVersion is less than 7 then 342 | try 343 | log "Testing for kerberos ticket presence…" 344 | set kerb to do shell script "/usr/bin/klist -t" 345 | set renewKerb to do shell script "/usr/bin/kinit -R" 346 | log " Ticket found and renewed" 347 | set my isIdle to true 348 | retrieveDefaults_(me) 349 | doProcess_(me) 350 | on error theError 351 | set my theMessage to "Kerberos ticket expired or not found" 352 | log " No ticket found" 353 | activate 354 | set response to (display dialog "No Kerberos ticket for Active Directory was found. Do you want to renew it?" with icon 1 buttons {"No","Yes"} default button "Yes") 355 | if button returned of response is "Yes" then 356 | do shell script "/bin/echo '' | /usr/bin/kinit -l 24h -r 24h &" -- Displays a password dialog in 10.6 (and maybe 10.5?) 357 | log " Ticket acquired" 358 | doKerbCheck_(me) -- Rerun the handler to verify kerb ticket and call doProcess 359 | else -- if No is clicked 360 | log " User chose not to acquire" 361 | errorOut_(theError, 1) 362 | end if 363 | end try 364 | else -- if osVersion is 7 or greater 365 | doLionKerb_(me) 366 | end if 367 | else -- if selectedMethod = 1 368 | doProcess_(me) 369 | end if 370 | else -- if skipKerb is true 371 | doProcess_(me) 372 | end if 373 | end doKerbCheck_ 374 | 375 | -- Need to handle Lion's kerberos differently from older OSes 376 | on doLionKerb_(sender) 377 | try 378 | log "Testing for Kerberos ticket presence…" 379 | set kerb to do shell script "/usr/bin/klist -t" 380 | set renewKerb to do shell script "/usr/bin/kinit -R" 381 | log " Ticket found and renewed" 382 | set my isIdle to true 383 | retrieveDefaults_(me) 384 | doProcess_(me) 385 | on error theError 386 | set my theMessage to "Kerberos ticket expired or not found" 387 | log " No ticket found" 388 | activate 389 | set response to (display dialog "No Kerberos ticket for Active Directory was found. Do you want to renew it?" with icon 2 buttons {"No","Yes"} default button "Yes") 390 | if button returned of response is "Yes" then 391 | renewLionKerb_(me) 392 | else -- if No is clicked 393 | log " User chose not to acquire" 394 | errorOut_(theError, 1) 395 | end if 396 | end try 397 | end doLionKerb_ 398 | 399 | -- Runs when Yes of Lion kerberos renewal dialog (from above) is clicked. 400 | on renewLionKerb_(sender) 401 | try 402 | set thePassword to text returned of (display dialog "Enter your Active Directory password:" default answer "" with hidden answer) 403 | do shell script "/bin/echo '" & thePassword & "' | /usr/bin/kinit -l 10h -r 10h --password-file=STDIN" 404 | log " Ticket acquired" 405 | display dialog "Kerberos ticket acquired." with icon 1 buttons {"OK"} default button 1 406 | doLionKerb_(me) 407 | on error 408 | try 409 | set thePassword to text returned of (display dialog "Password incorrect. Please try again:" default answer "" with icon 2 with hidden answer) 410 | do shell script "/bin/echo '" & thePassword & "' | /usr/bin/kinit -l 24h -r 24h --password-file=STDIN" 411 | display dialog "Kerboros ticket acquired." with icon 1 buttons {"OK"} default button 1 412 | doLionKerb_(me) 413 | on error 414 | log " Incorrect password. Skipping." 415 | display dialog "Too many incorrect attempts. Stopping to avoid account lockout." with icon 2 buttons {"OK"} default button 1 416 | end try 417 | end try 418 | end renewLionKerb_ 419 | 420 | -- ad node with scutil fallback to get AD DNS info 421 | on getDNS_(sender) 422 | try 423 | -- find source of user node 424 | set originalNodeName to (do shell script "/usr/bin/dscl localhost read /Search/Users/$USER OriginalNodeName | grep -o -e '/.*'") as text 425 | if (count words of originalNodeName) > 0 426 | set my myLDAP to (do shell script "/usr/bin/dscl localhost read '" & originalNodeName & "' ServerConnection | /usr/bin/awk '/ServerConnection/{print $2}'") as text 427 | set my mySearchBase to (do shell script "/usr/bin/dscl localhost read '" & originalNodeName & "' LDAPSearchBaseSuffix | /usr/bin/awk '/LDAPSearchBaseSuffix/{print $2}'") as text 428 | end if 429 | 430 | if (count words of myLDAP) = 0 431 | -- "first word of" added for 10.7 compatibility, which may return more than one item 432 | set my myLDAP to first word of (do shell script "/usr/sbin/scutil --dns | /usr/bin/awk '/nameserver\\[0\\]/{print $3}'") as text 433 | end if 434 | on error theError 435 | errorOut_(theError) 436 | end try 437 | log " myLDAP: " & myLDAP 438 | end getDNS_ 439 | 440 | -- Use dsconfigad to get domain name 441 | -- Use dig to get AD LDAP server from domain name 442 | on getADLDAP_(sender) 443 | try 444 | set myDomain to (do shell script "/usr/sbin/dsconfigad -show | /usr/bin/awk '/Active Directory Domain/{print $NF}'") as text 445 | try 446 | set myLDAPresult to (do shell script "/usr/bin/dig +time=2 +tries=1 -t srv _ldap._tcp." & myDomain) as text 447 | on error theError 448 | log "Domain test timed out." 449 | set my onDomain to false 450 | end try 451 | if "ANSWER SECTION" is in myLDAPresult then 452 | set my onDomain to true 453 | -- using "first paragraph" to return only the first ldap server returned by the query 454 | set myLDAP to last paragraph of (do shell script "/usr/bin/dig -t srv _ldap._tcp." & myDomain & "| /usr/bin/awk '/^_ldap/{print $NF}'") as text 455 | log " myDomain: " & myDomain 456 | log " myADLDAP: " & myLDAP 457 | else 458 | set my onDomain to false 459 | log " Can't reach " & myDomain & " domain" 460 | end if 461 | on error theError 462 | errorOut_(theError) 463 | end try 464 | end getADLDAP_ 465 | 466 | -- Use ldapsearch to get search base if OriginalNodeName method didn't work 467 | on getSearchBase_(sender) 468 | if (count of words of my mySearchBase) > 0 469 | return 470 | end if 471 | 472 | try 473 | set my mySearchBase to (do shell script "/usr/bin/ldapsearch -LLL -Q -s base -H ldap://" & myLDAP & " defaultNamingContext | /usr/bin/awk '/defaultNamingContext/{print $2}'") as text 474 | -- awk -F, '/rootDomainNamingContext/{print $(NF-1)","$NF}' to take only last two search base fields 475 | log " mySearchBase: " & mySearchBase 476 | on error theError 477 | errorOut_(theError, 1) 478 | end try 479 | end getSearchBase_ 480 | 481 | -- Use ldapsearch to get password expiration age 482 | on getExpireAge_(sender) 483 | try 484 | set my expireAgeUnix to (do shell script "/usr/bin/ldapsearch -LLL -Q -s base -H ldap://" & myLDAP & " -b " & mySearchBase & " maxPwdAge | /usr/bin/awk -F- '/maxPwdAge/{print $NF/10000000}'") as integer 485 | if expireAgeUnix is equal to 0 then 486 | log " Couldn't get expireAge. Trying using Manual method." 487 | else 488 | set my expireAge to expireAgeUnix / 86400 as integer 489 | log " Got expireAge: " & expireAge 490 | tell defaults to setObject_forKey_(expireAge, "expireAge") 491 | end if 492 | on error theError 493 | errorOut_(theError, 1) 494 | end try 495 | end getExpireAge_ 496 | 497 | -- Determine when the password was last changed 498 | on getPwdSetDate_(sender) 499 | -- number formatter for truncated decimal places 500 | set fmt to current application's NSNumberFormatter's alloc()'s init() 501 | fmt's setUsesSignificantDigits_(true) 502 | fmt's setMaximumSignificantDigits_(7) 503 | fmt's setMinimumSignificantDigits_(1) 504 | fmt's setDecimalSeparator_(".") 505 | 506 | set my pwdSetDateUnix to (do shell script "/usr/bin/dscl localhost read /Search/Users/\"$USER\" SMBPasswordLastSet | /usr/bin/awk '/LastSet:/{print $2}'") 507 | if (count words of pwdSetDateUnix) is greater than 0 then 508 | set my pwdSetDateUnix to last word of pwdSetDateUnix 509 | set my pwdSetDateUnix to ((pwdSetDateUnix as integer) / 10000000 - 11644473600) 510 | set my pwdSetDate to fmt's stringFromNumber_(pwdSetDateUnix / 86400) 511 | else if (count words of pwdSetDateUnix) is equal to 0 then 512 | set my pwdSetDate to -1 513 | end if 514 | log " New pwdSetDate (" & pwdSetDate & ")" 515 | 516 | 517 | -- Now we compare the plist's value for pwdSetDate to the one we just calculated so 518 | -- we avoid using an old or bad value (i.e. when SMBPasswordLastSet can't be found by dscl) 519 | tell defaults to set plistPwdSetDate to objectForKey_("pwdSetDate") as real 520 | statusMenu's setAutoenablesItems_(false) 521 | if plistPwdSetDate is equal to 0 then 522 | set my skipKerb to true 523 | log " will be saved to plist." 524 | tell defaults to setObject_forKey_(pwdSetDate, "pwdSetDate") 525 | statusMenu's itemWithTitle_("Refresh Kerberos Ticket")'s setEnabled_(not skipKerb) 526 | statusMenu's itemWithTitle_("Change Password…")'s setEnabled_(not skipKerb) 527 | else if plistPwdSetDate is less than or equal to pwdSetDate then 528 | log " ≥ plist value (" & plistPwdSetDate & ") so we use it" 529 | tell defaults to setObject_forKey_(pwdSetDate, "pwdSetDate") 530 | -- If we can get a valid pwdSetDate, then we're on the network, so enable kerb features 531 | set my skipKerb to false 532 | statusMenu's itemWithTitle_("Refresh Kerberos Ticket")'s setEnabled_(not skipKerb) 533 | statusMenu's itemWithTitle_("Change Password…")'s setEnabled_(not skipKerb) 534 | else if plistPwdSetDate is greater than pwdSetDate then 535 | log " < plist value (" & plistPwdSetDate & ") so we ignore it" 536 | set my pwdSetDate to plistPwdSetDate 537 | -- If we can't get a valid pwdSetDate, then we're off the network, so disable kerb features 538 | set my skipKerb to true 539 | statusMenu's itemWithTitle_("Refresh Kerberos Ticket")'s setEnabled_(not skipKerb) 540 | statusMenu's itemWithTitle_("Change Password…")'s setEnabled_(not skipKerb) 541 | end if 542 | end getPwdSetDate_ 543 | 544 | -- Uses 'msDS-UserPasswordExpiryTimeComputed' value from AD to get expiration date. 545 | on easyMethod_(sender) 546 | try 547 | set userName to short user name of (system info) 548 | set expireDateResult to (do shell script "/usr/bin/dscl localhost read /Search/Users/" & userName & " msDS-UserPasswordExpiryTimeComputed") 549 | if "msDS-UserPasswordExpiryTimeComputed" is in expireDateResult then 550 | set my goEasy to true 551 | set my expireDate to last word of expireDateResult 552 | else 553 | set my goEasy to false 554 | return 555 | end if 556 | set my expireDateUnix to do shell script "echo '(" & expireDate & "/10000000)-11644473600' | /usr/bin/bc" 557 | log " Got expireDateUnix: " & expireDateUnix 558 | tell defaults to setObject_forKey_(expireDateUnix, "expireDateUnix") 559 | on error theError 560 | errorOut_(theError, 1) 561 | end try 562 | end easyMethod_ 563 | 564 | on easyDate_(timestamp) 565 | set my expirationDate to do shell script "/bin/date -r " & timestamp 566 | set todayUnix to do shell script "/bin/date +%s" 567 | set my daysUntilExp to ((timestamp - todayUnix) / 86400) 568 | log " daysUntilExp: " & daysUntilExp 569 | set my daysUntilExpNice to round daysUntilExp rounding toward zero 570 | --log " daysUntilExpNice: " & daysUntilExpNice 571 | end easyDate_ 572 | 573 | 574 | -- Calculate the number of days until password expiration 575 | on compareDates_(sender) 576 | -- number formatter for truncated decimal places 577 | set fmt to current application's NSNumberFormatter's alloc()'s init() 578 | fmt's setUsesSignificantDigits_(true) 579 | fmt's setMaximumSignificantDigits_(7) 580 | fmt's setMinimumSignificantDigits_(1) 581 | fmt's setDecimalSeparator_(".") 582 | try 583 | set todayUnix to (do shell script "/bin/date +%s") 584 | set today to (todayUnix / 86400) 585 | set my daysUntilExp to fmt's stringFromNumber_(expireAge - (today - pwdSetDate)) as real -- removed 'as integer' to avoid rounding issue 586 | log " daysUntilExp: " & daysUntilExp 587 | set my daysUntilExpNice to round daysUntilExp rounding toward zero 588 | --log " daysUntilExpNice: " & daysUntilExpNice 589 | on error theError 590 | errorOut_(theError, 1) 591 | end try 592 | end compareDates_ 593 | 594 | -- Get the full date of password expiration. daysUntilExp is input. 595 | on getExpirationDate_(remaining) 596 | set fullDate to (current date) + (remaining * days) as text 597 | --set my expirationDate to text 1 thru ((offset of ":" in fullDate) - 3) of fullDate -- this truncates the time 598 | set my expirationDate to fullDate 599 | log " expirationDate: " & expirationDate 600 | end getExpirationDate_ 601 | 602 | -- Updates the menu's title and tooltip 603 | on updateMenuTitle_(menu_title, tooltip) 604 | tell defaults to setObject_forKey_(menu_title, "menu_title") 605 | tell defaults to setObject_forKey_(tooltip, "tooltip") 606 | statusMenuController's updateDisplay() 607 | end updateMenuTitle_ 608 | 609 | -- The meat of the app; gets the data and does the calculations 610 | on doProcess_(sender) 611 | domainTest_(me) 612 | if selectedMethod = 0 then 613 | log "Starting auto process…" 614 | else 615 | log "Starting manual process…" 616 | end if 617 | 618 | try 619 | if my onDomain is true then 620 | theWindow's displayIfNeeded() 621 | set my isIdle to false 622 | set my theMessage to "Working…" 623 | 624 | -- Do this if we haven't run before, or the defaults have been reset. 625 | if my expireDateUnix = 0 and my selectedMethod = 0 then 626 | getADLDAP_(me) 627 | easyMethod_(me) 628 | if my goEasy is false then 629 | getSearchBase_(me) 630 | getExpireAge_(me) 631 | end if 632 | else 633 | log " Found expireDateUnix in plist: " & expireDateUnix 634 | easyMethod_(me) 635 | end if 636 | 637 | if my goEasy is true and my selectedMethod = 0 then 638 | log " Using msDS method" 639 | easyDate_(expireDateUnix) 640 | else 641 | log " Using alt method" 642 | getPwdSetDate_(me) 643 | compareDates_(me) 644 | getExpirationDate_(daysUntilExp) 645 | end if 646 | 647 | updateMenuTitle_((daysUntilExpNice as string) & "d", "Your password expires\n" & expirationDate) 648 | 649 | set my theMessage to "Your password expires in " & daysUntilExpNice & " days\non " & expirationDate 650 | set my isIdle to true 651 | 652 | doNotify_(daysUntilExpNice) 653 | 654 | else 655 | log " Stopping." 656 | end if 657 | on error theError 658 | errorOut_(theError, 1) 659 | end try 660 | end doProcess_ 661 | 662 | on doProcessWithWait_(sender) 663 | tell current application's NSThread to sleepForTimeInterval_(15) 664 | doProcess_(me) 665 | end doProcessWithWait_ 666 | 667 | on intervalDoProcess_(sender) 668 | doProcess_(me) 669 | end intervalDoProcess_ 670 | 671 | --- INTERFACE BINDING HANDLERS --- 672 | 673 | -- Bound to About item 674 | on about_(sender) 675 | activate 676 | current application's NSApp's orderFrontStandardAboutPanel_(null) 677 | end about_ 678 | 679 | -- Bound to Change Password menu item 680 | on changePassword_(sender) 681 | tell defaults to set my pwPolicy to objectForKey_("pwPolicy") as string 682 | tell defaults to set my pwPolicyButton to objectForKey_("pwPolicyButton") as string 683 | if my pwPolicy is not "" then 684 | tell application "System Events" 685 | display dialog pwPolicy with icon 2 buttons {pwPolicyButton} 686 | end tell 687 | end if 688 | tell application "System Preferences" 689 | try -- to use UI scripting 690 | set current pane to pane id "com.apple.preferences.users" 691 | activate 692 | tell application "System Events" 693 | tell application process "System Preferences" 694 | if my osVersion is less than or equal to 6 then 695 | tell current application's NSThread to sleepForTimeInterval_(1) 696 | click radio button "Password" of tab group 1 of window "Accounts" 697 | click button "Change Password…" of tab group 1 of window "Accounts" 698 | end if 699 | if my osVersion is greater than 6 then 700 | tell current application's NSThread to sleepForTimeInterval_(1) 701 | click radio button "Password" of tab group 1 of window "Users & Groups" 702 | click button "Change Password…" of tab group 1 of window "Users & Groups" 703 | end if 704 | end tell 705 | end tell 706 | on error theError 707 | errorOut_(theError, 1) 708 | end try 709 | end tell 710 | end changePassword_ 711 | 712 | -- Bound to Prefs menu item 713 | on showMainWindow_(sender) 714 | activate 715 | theWindow's makeKeyAndOrderFront_(null) 716 | end showMainWindow_ 717 | 718 | -- Bound to Quit menu item 719 | on quit_(sender) 720 | quit 721 | end quit_ 722 | 723 | -- Bound to Auto radio buttons and Manual text field in Prefs window 724 | on useManualMethod_(sender) 725 | log "selectedMethod: " & sender's intValue() 726 | if sender's intValue() is not 1 then -- Auto sends value 1 (on), so Manual is selected 727 | set my isHidden to true 728 | set my isManualEnabled to true 729 | set my selectedMethod to 1 730 | set my expireAge to manualExpireDays as integer 731 | tell defaults to setObject_forKey_(1, "selectedMethod") 732 | tell defaults to setObject_forKey_(manualExpireDays, "expireAge") 733 | doProcess_(me) 734 | else -- Auto is selected 735 | set my isHidden to false 736 | set my isManualEnabled to false 737 | set my selectedMethod to 0 738 | set my expireAge to "" 739 | set my expireDateUnix to 0 740 | set my manualExpireDays to "" 741 | tell defaults to removeObjectForKey_("expireAge") 742 | tell defaults to removeObjectForKey_("expireDateUnix") 743 | tell defaults to setObject_forKey_(0, "selectedMethod") 744 | tell defaults to setObject_forKey_("", "expireAge") 745 | tell defaults to setObject_forKey_(0, "expireDateUnix") 746 | doKerbCheck_(me) 747 | end if 748 | end useManualMethod_ 749 | 750 | -- Bound to warningDays box in Prefs window 751 | on setWarningDays_(sender) 752 | set my warningDays to sender's intValue() as integer 753 | tell defaults to setObject_forKey_(warningDays, "warningDays") 754 | log "Set warning days to " & warningDays 755 | end setWarningDays_ 756 | 757 | -- Bound to checkInterval box in Prefs window 758 | on setCheckInterval_(sender) 759 | processTimer's invalidate() -- kills the existing timer 760 | set my checkInterval to sender's intValue() as integer 761 | tell defaults to setObject_forKey_(checkInterval, "checkInterval") 762 | -- start a timer with the new interval 763 | set processTimer to current application's NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_((my checkInterval * 3600), me, "intervalDoProcess:", missing value, true) 764 | set unit to " hours" 765 | if checkInterval is equal to 1 then 766 | set unit to " hour" 767 | end if 768 | log "Set check interval to " & checkInterval & unit 769 | end setCheckInterval_ 770 | 771 | -- Bound to Notify items in menu and Prefs window 772 | on toggleNotify_(sender) 773 | if my enableNotifications as boolean is true then 774 | set my enableNotifications to false 775 | my statusMenu's itemWithTitle_("Use Notifications")'s setState_(0) 776 | tell defaults to setObject_forKey_(enableNotifications, "enableNotifications") 777 | log "Disabled notifications." 778 | else 779 | set my enableNotifications to true 780 | my statusMenu's itemWithTitle_("Use Notifications")'s setState_(1) 781 | tell defaults to setObject_forKey_(enableNotifications, "enableNotifications") 782 | log "Enabled notifications." 783 | end if 784 | end toggleNotify_ 785 | 786 | on toggleKerbMinder_(sender) 787 | if my enableKerbMinder as boolean is true then 788 | set my enableKerbMinder to false 789 | my statusMenu's itemWithTitle_("Use KerbMinder")'s setState_(0) 790 | tell defaults to setObject_forKey_(enableKerbMinder, "enableKerbMinder") 791 | log "Disabled KerbMinder." 792 | else 793 | set my enableKerbMinder to true 794 | my statusMenu's itemWithTitle_("Use KerbMinder")'s setState_(1) 795 | tell defaults to setObject_forKey_(enableKerbMinder, "enableKerbMinder") 796 | log "Enabled KerbMinder." 797 | end if 798 | end toggleKerbMinder_ 799 | 800 | -- Bound to Revert button in Prefs window 801 | on revertDefaults_(sender) 802 | tell defaults to removeObjectForKey_("menu_title") 803 | tell defaults to removeObjectForKey_("first_run") 804 | tell defaults to removeObjectForKey_("tooltip") 805 | tell defaults to removeObjectForKey_("selectedMethod") 806 | tell defaults to removeObjectForKey_("enableNotifications") 807 | tell defaults to removeObjectForKey_("checkInterval") 808 | tell defaults to removeObjectForKey_("expireAge") 809 | tell defaults to removeObjectForKey_("expireDateUnix") 810 | tell defaults to removeObjectForKey_("pwdSetDate") 811 | tell defaults to removeObjectForKey_("warningDays") 812 | tell defaults to removeObjectForKey_("prefsLocked") 813 | tell defaults to removeObjectForKey_("myLDAP") 814 | tell defaults to removeObjectForKey_("pwPolicy") 815 | tell defaults to removeObjectForKey_("pwPolicyButton") 816 | tell defaults to removeObjectForKey_("accTest") 817 | tell defaults to removeObjectForKey_("enableKerbMinder") 818 | do shell script "defaults delete org.pmbuko.ADPassMon" 819 | retrieveDefaults_(me) 820 | statusMenuController's updateDisplay() 821 | set my theMessage to "ADPassMon has been reset. 822 | Please choose your configuration options." 823 | end revertDefaults_ 824 | 825 | --- INITIAL LOADING SECTION --- 826 | 827 | -- Creates the status menu and its items, using some values determined by other handlers 828 | on createMenu_(sender) 829 | set statusMenu to (my NSMenu's alloc)'s initWithTitle_("statusMenu") 830 | statusMenu's setAutoenablesItems_(false) 831 | 832 | set menuItem to (my NSMenuItem's alloc)'s init 833 | menuItem's setTitle_("About ADPassMon…") 834 | menuItem's setTarget_(me) 835 | menuItem's setAction_("about:") 836 | menuItem's setEnabled_(true) 837 | statusMenu's addItem_(menuItem) 838 | menuItem's release() 839 | 840 | set menuItem to (my NSMenuItem's alloc)'s init 841 | menuItem's setTitle_("Use Notifications") 842 | menuItem's setTarget_(me) 843 | menuItem's setAction_("toggleNotify:") 844 | menuItem's setEnabled_(true) 845 | menuItem's setState_(enableNotifications as integer) 846 | statusMenu's addItem_(menuItem) 847 | menuItem's release() 848 | 849 | set menuItem to (my NSMenuItem's alloc)'s init 850 | menuItem's setTitle_("Use KerbMinder") 851 | menuItem's setTarget_(me) 852 | menuItem's setAction_("toggleKerbMinder:") 853 | menuItem's setEnabled_(true) 854 | menuItem's setHidden_(not KerbMinderInstalled) 855 | menuItem's setState_(enableKerbMinder as integer) 856 | statusMenu's addItem_(menuItem) 857 | menuItem's release() 858 | 859 | set menuItem to (my NSMenuItem's alloc)'s init 860 | menuItem's setTitle_("Preferences…") 861 | menuItem's setTarget_(me) 862 | menuItem's setAction_("showMainWindow:") 863 | menuItem's setEnabled_(not prefsLocked) 864 | statusMenu's addItem_(menuItem) 865 | menuItem's release() 866 | 867 | statusMenu's addItem_(my NSMenuItem's separatorItem) 868 | 869 | set menuItem to (my NSMenuItem's alloc)'s init 870 | menuItem's setTitle_("Refresh Kerberos Ticket") 871 | menuItem's setTarget_(me) 872 | menuItem's setAction_("doKerbCheck:") 873 | menuItem's setEnabled_(onDomain as boolean) 874 | statusMenu's addItem_(menuItem) 875 | menuItem's release() 876 | 877 | set menuItem to (my NSMenuItem's alloc)'s init 878 | menuItem's setTitle_("Launch Ticket Viewer") 879 | menuItem's setTarget_(me) 880 | menuItem's setAction_("ticketViewer:") 881 | menuItem's setEnabled_(true) 882 | statusMenu's addItem_(menuItem) 883 | menuItem's release() 884 | 885 | set menuItem to (my NSMenuItem's alloc)'s init 886 | menuItem's setTitle_("Re-check Expiration") 887 | menuItem's setTarget_(me) 888 | menuItem's setAction_("doProcess:") 889 | menuItem's setEnabled_(true) 890 | statusMenu's addItem_(menuItem) 891 | menuItem's release() 892 | 893 | set menuItem to (my NSMenuItem's alloc)'s init 894 | menuItem's setTitle_("Change Password…") 895 | menuItem's setTarget_(me) 896 | menuItem's setAction_("changePassword:") 897 | menuItem's setEnabled_(onDomain as boolean) 898 | statusMenu's addItem_(menuItem) 899 | menuItem's release() 900 | 901 | statusMenu's addItem_(my NSMenuItem's separatorItem) 902 | 903 | set menuItem to (my NSMenuItem's alloc)'s init 904 | menuItem's setTitle_("Exit") 905 | menuItem's setTarget_(me) 906 | menuItem's setAction_("quit:") 907 | menuItem's setEnabled_(true) 908 | statusMenu's addItem_(menuItem) 909 | menuItem's release() 910 | 911 | -- Instantiate the statusItemController object and set it to use the statusMenu we just created 912 | set statusMenuController to (current application's class "StatusMenuController"'s alloc)'s init 913 | statusMenuController's createStatusItemWithMenu_(statusMenu) 914 | statusMenu's release() 915 | end createMenu_ 916 | 917 | -- Do processes necessary for app initiation 918 | on applicationWillFinishLaunching_(aNotification) 919 | getOS_(me) 920 | regDefaults_(me) -- populate plist file with defaults (will not overwrite non-default settings)) 921 | accTest_(me) 922 | KerbMinderTest_(me) 923 | notifySetup_(me) 924 | retrieveDefaults_(me) -- load defaults 925 | createMenu_(me) -- build and display the status menu item 926 | domainTest_(me) -- test domain connectivity 927 | if my onDomain is false then 928 | return -- stop the process if no domain connectivity 929 | end if 930 | canPassExpire_(me) 931 | if passExpires then 932 | -- if we're using Auto and we don't have the password expiration age, check for kerberos ticket 933 | if my expireDateUnix = 0 and my selectedMethod = 0 then 934 | doKerbCheck_(me) 935 | if first_run then -- only display prefs window if running for first time 936 | if prefsLocked as integer is equal to 0 then -- only display the window if prefs are not locked 937 | log "First launch, waiting for settings..." 938 | theWindow's makeKeyAndOrderFront_(null) 939 | set my theMessage to "Welcome!\nPlease choose your configuration options." 940 | set first_run to false 941 | end if 942 | end if 943 | else if my selectedMethod is 1 then 944 | set my manualExpireDays to expireAge 945 | set my isHidden to true 946 | set my isManualEnabled to true 947 | doProcess_(me) 948 | else if my selectedMethod is 0 then 949 | set my isHidden to false 950 | set my isManualEnabled to false 951 | set my manualExpireDays to "" 952 | doProcess_(me) 953 | end if 954 | 955 | watchForWake_(me) 956 | 957 | -- Set a timer to check for domain connectivity every five minutes. (300) 958 | set domainTimer to NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(300, me, "intervalDomainTest:", missing value, true) 959 | 960 | -- Set a timer to trigger doProcess handler on an interval and spawn notifications (if enabled). 961 | set processTimer to NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_((my checkInterval * 3600), me, "intervalDoProcess:", missing value, true) 962 | else 963 | log "Password does not exipire. Stopping." 964 | updateMenuTitle_("[--]", "Your password does not expire.") 965 | set my theMessage to "Your password does not expire." 966 | end if 967 | end applicationWillFinishLaunching_ 968 | 969 | on applicationShouldTerminate_(sender) 970 | return current application's NSTerminateNow 971 | end applicationShouldTerminate_ 972 | 973 | -- This will immediately release the space in the menubar on quit 974 | on applicationWillTerminate_(notification) 975 | statusMenuController's releaseStatusItem() 976 | statusMenuController's release() 977 | end applicationWillTerminate_ 978 | end script -------------------------------------------------------------------------------- /ADPassMon/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "icon_16x16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "icon_16x16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "icon_32x32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "icon_32x32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "icon_128x128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "icon_128x128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "icon_256x256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "icon_256x256@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "icon_512x512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "icon_512x512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /ADPassMon/Images.xcassets/AppIcon.appiconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmbuko/ADPassMon/24057beebe7f3e93e5e52ec07bde13633203cd63/ADPassMon/Images.xcassets/AppIcon.appiconset/icon_128x128.png -------------------------------------------------------------------------------- /ADPassMon/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmbuko/ADPassMon/24057beebe7f3e93e5e52ec07bde13633203cd63/ADPassMon/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /ADPassMon/Images.xcassets/AppIcon.appiconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmbuko/ADPassMon/24057beebe7f3e93e5e52ec07bde13633203cd63/ADPassMon/Images.xcassets/AppIcon.appiconset/icon_16x16.png -------------------------------------------------------------------------------- /ADPassMon/Images.xcassets/AppIcon.appiconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmbuko/ADPassMon/24057beebe7f3e93e5e52ec07bde13633203cd63/ADPassMon/Images.xcassets/AppIcon.appiconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /ADPassMon/Images.xcassets/AppIcon.appiconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmbuko/ADPassMon/24057beebe7f3e93e5e52ec07bde13633203cd63/ADPassMon/Images.xcassets/AppIcon.appiconset/icon_256x256.png -------------------------------------------------------------------------------- /ADPassMon/Images.xcassets/AppIcon.appiconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmbuko/ADPassMon/24057beebe7f3e93e5e52ec07bde13633203cd63/ADPassMon/Images.xcassets/AppIcon.appiconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /ADPassMon/Images.xcassets/AppIcon.appiconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmbuko/ADPassMon/24057beebe7f3e93e5e52ec07bde13633203cd63/ADPassMon/Images.xcassets/AppIcon.appiconset/icon_32x32.png -------------------------------------------------------------------------------- /ADPassMon/Images.xcassets/AppIcon.appiconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmbuko/ADPassMon/24057beebe7f3e93e5e52ec07bde13633203cd63/ADPassMon/Images.xcassets/AppIcon.appiconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /ADPassMon/Images.xcassets/AppIcon.appiconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmbuko/ADPassMon/24057beebe7f3e93e5e52ec07bde13633203cd63/ADPassMon/Images.xcassets/AppIcon.appiconset/icon_512x512.png -------------------------------------------------------------------------------- /ADPassMon/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmbuko/ADPassMon/24057beebe7f3e93e5e52ec07bde13633203cd63/ADPassMon/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /ADPassMon/en.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1348\cocoasubrtf170 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;} 3 | {\colortbl;\red255\green255\blue255;} 4 | \vieww9600\viewh8400\viewkind0 5 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 6 | 7 | \f0\b\fs24 \cf0 Engineering & UI Design: 8 | \b0 \ 9 | Peter Bukowinski\ 10 | \ 11 | 12 | \b Testing: 13 | \b0 \ 14 | Joe Chilcote\ 15 | Brian LaShomb\ 16 | Francois Levaux-Tiffreau\ 17 | Joel Moses\ 18 | Rusty Myers\ 19 | Stephen Rayda\ 20 | Tom Rodgers\ 21 | Rich Trouton\ 22 | \ 23 | 24 | \b Code Contributions:\ 25 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 26 | 27 | \b0 \cf0 Dan Tsosie\ 28 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 29 | \cf0 \ 30 | 31 | \b Documentation: 32 | \b0 \ 33 | {\field{\*\fldinst{HYPERLINK "http://yourmacguy.wordpress.com/ADPassMon/"}}{\fldrslt http://yourmacguy.wordpress.com}}\ 34 | \ 35 | 36 | \b With special thanks to: 37 | \b0 \ 38 | Jonathan Nathan, JNSoftware\ 39 | for his free {\field{\*\fldinst{HYPERLINK "http://jonn8.com/html/MenuApp_ASOC.html"}}{\fldrslt MenuApp ASOC code}}\ 40 | \ 41 | Shane Stanley\ 42 | for his excellent eBook, 43 | \i \ 44 | {\field{\*\fldinst{HYPERLINK "http://macosxautomation.com/applescript/apps/"}}{\fldrslt AppleScriptObjC Explored}}\ 45 | 46 | \i0 \ 47 | Andrew Thomson\ 48 | for his work on the app this is based on\ 49 | {\field{\*\fldinst{HYPERLINK "http://thomsontown.com/pwdmon.htm"}}{\fldrslt http://thomsontown.com/pwdmon.htm}}\ 50 | \ 51 | John Welch\ 52 | for recommending Shane's book} -------------------------------------------------------------------------------- /ADPassMon/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ADPassMon/en.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | NSNegateBoolean 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 126 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | -------------------------------------------------------------------------------- /ADPassMon/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ADPassMon 4 | // 5 | // Created by Peter Bukowinski on 3/24/11. 6 | // Copyright (C) 2015 Peter Bukowinski. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | [[NSBundle mainBundle] loadAppleScriptObjectiveCScripts]; 16 | return NSApplicationMain(argc, (const char **)argv); 17 | } 18 | -------------------------------------------------------------------------------- /LaunchAtLoginController.h: -------------------------------------------------------------------------------- 1 | // 2 | // LaunchAtLoginController.h 3 | // 4 | // Created by Ben Clark-Robinson on 24/03/10. 5 | // Copyright 2010 Mozketo. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining 8 | // a copy of this software and associated documentation files (the 9 | // 'Software'), to deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, merge, publish, 11 | // distribute, sublicense, and/or sell copies of the Software, and to 12 | // permit persons to whom the Software is furnished to do so, subject to 13 | // the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be 16 | // included in all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | 26 | #import 27 | 28 | 29 | @interface LaunchAtLoginController : NSObject { 30 | 31 | } 32 | 33 | @property BOOL launchAtLogin; 34 | 35 | - (BOOL)willLaunchAtLogin:(NSURL *)itemUrl; 36 | - (void)setLaunchAtLogin:(BOOL)enabled; 37 | - (void)setLaunchAtLogin:(NSURL *)itemURL enabled:(BOOL)enabled; 38 | 39 | @end -------------------------------------------------------------------------------- /LaunchAtLoginController.m: -------------------------------------------------------------------------------- 1 | // 2 | // LaunchAtLoginController.m 3 | // 4 | // Created by Ben Clark-Robinson on 24/03/10. 5 | // Copyright 2010 Ben Clark-Robinson. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining 8 | // a copy of this software and associated documentation files (the 9 | // 'Software'), to deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, merge, publish, 11 | // distribute, sublicense, and/or sell copies of the Software, and to 12 | // permit persons to whom the Software is furnished to do so, subject to 13 | // the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be 16 | // included in all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | 26 | #import "LaunchAtLoginController.h" 27 | 28 | 29 | @implementation LaunchAtLoginController 30 | 31 | - (NSURL *)appURL { 32 | return [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]; 33 | } 34 | 35 | - (BOOL)launchAtLogin { 36 | return [self willLaunchAtLogin:[self appURL]]; 37 | } 38 | 39 | - (BOOL)willLaunchAtLogin:(NSURL *)itemURL { 40 | Boolean foundIt=false; 41 | LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); 42 | if (loginItems) { 43 | UInt32 seed = 0U; 44 | NSArray *currentLoginItems = [NSMakeCollectable(LSSharedFileListCopySnapshot(loginItems, &seed)) autorelease]; 45 | for (id itemObject in currentLoginItems) { 46 | LSSharedFileListItemRef item = (LSSharedFileListItemRef)itemObject; 47 | 48 | UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes; 49 | CFURLRef URL = NULL; 50 | OSStatus err = LSSharedFileListItemResolve(item, resolutionFlags, &URL, /*outRef*/ NULL); 51 | if (err == noErr) { 52 | foundIt = CFEqual(URL, itemURL); 53 | CFRelease(URL); 54 | 55 | if (foundIt) 56 | break; 57 | } 58 | } 59 | CFRelease(loginItems); 60 | } 61 | return (BOOL)foundIt; 62 | } 63 | 64 | - (void)setLaunchAtLogin:(BOOL)enabled { 65 | [self willChangeValueForKey:@"startAtLogin"]; 66 | [self setLaunchAtLogin:[self appURL] enabled:enabled]; 67 | [self didChangeValueForKey:@"startAtLogin"]; 68 | } 69 | 70 | 71 | - (void)setLaunchAtLogin:(NSURL *)itemURL enabled:(BOOL)enabled { 72 | LSSharedFileListItemRef existingItem = NULL; 73 | 74 | LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); 75 | if (loginItems) { 76 | UInt32 seed = 0U; 77 | NSArray *currentLoginItems = [NSMakeCollectable(LSSharedFileListCopySnapshot(loginItems, &seed)) autorelease]; 78 | for (id itemObject in currentLoginItems) { 79 | LSSharedFileListItemRef item = (LSSharedFileListItemRef)itemObject; 80 | 81 | UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes; 82 | CFURLRef URL = NULL; 83 | OSStatus err = LSSharedFileListItemResolve(item, resolutionFlags, &URL, /*outRef*/ NULL); 84 | if (err == noErr) { 85 | Boolean foundIt = CFEqual(URL, itemURL); 86 | CFRelease(URL); 87 | 88 | if (foundIt) { 89 | existingItem = item; 90 | break; 91 | } 92 | } 93 | } 94 | 95 | if (enabled && (existingItem == NULL)) { 96 | LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, 97 | NULL, NULL, (CFURLRef)itemURL, NULL, NULL); 98 | 99 | } else if (!enabled && (existingItem != NULL)) 100 | LSSharedFileListItemRemove(loginItems, existingItem); 101 | 102 | CFRelease(loginItems); 103 | } 104 | } 105 | 106 | 107 | @end 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Note: this project is deprecated! 2 | 3 | Please visit [macmule's ADPassMon fork](https://github.com/macmule/ADPassMon) to find the latest code. My latest code has been merged with that project and I am committing all my new updates to it. 4 | -------------------------------------------------------------------------------- /StatusMenuController.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatusMenuController.h 3 | // ADPassMon 4 | // 5 | // Created by Peter Bukowinski on 3/24/11. 6 | // Copyright 2015 Peter Bukowinski. All rights reserved. 7 | // 8 | // I feel it is important to give credit for portions of this code, attributed below. 9 | // 10 | // Created by Jonathan Nathan, JNSoftware LLC on 1/12/11. 11 | // Copyright 2011 JNSoftware LLC. All rights reserved. 12 | // 13 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this 14 | // software and associated documentation files (the "Software"), to deal in the Software 15 | // without restriction, including without limitation the rights to use, copy, modify, 16 | // merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 17 | // permit persons to whom the Software is furnished to do so, subject to the following conditions: 18 | // 19 | // The above copyright notice and this permission notice shall be included in all copies or 20 | // substantial portions of the Software. 21 | // 22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 23 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 25 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | 28 | 29 | #import 30 | 31 | 32 | @interface StatusMenuController : NSObject { 33 | @private 34 | NSStatusItem *statusItem; 35 | NSMenu *menu; 36 | } 37 | 38 | - (void)createStatusItemWithMenu:(NSMenu *)_menu; 39 | - (void)updateDisplay; 40 | - (void)releaseStatusItem; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /StatusMenuController.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatusMenuController.m 3 | // ADPassMon 4 | // 5 | // Created by Peter Bukowinski on 3/24/11. 6 | // Copyright (C) 2015 Peter Bukowinski. All rights reserved. 7 | // 8 | // I feel it is important to give credit for portions of this code, attributed below. 9 | // 10 | // Created by Jonathan Nathan, JNSoftware LLC on 1/12/11. 11 | // Copyright 2011 JNSoftware LLC. All rights reserved. 12 | // 13 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this 14 | // software and associated documentation files (the "Software"), to deal in the Software 15 | // without restriction, including without limitation the rights to use, copy, modify, 16 | // merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 17 | // permit persons to whom the Software is furnished to do so, subject to the following conditions: 18 | // 19 | // The above copyright notice and this permission notice shall be included in all copies or 20 | // substantial portions of the Software. 21 | // 22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 23 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 25 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | 28 | #import "StatusMenuController.h" 29 | 30 | static NSFont *menuBarFont = nil; 31 | static NSDictionary *attributes = nil; 32 | 33 | @implementation StatusMenuController 34 | 35 | + (void)initialize { 36 | static BOOL isInitialzed = NO; 37 | if (!isInitialzed) { 38 | menuBarFont = [[NSFont menuBarFontOfSize:14.0] retain]; 39 | attributes = [[NSDictionary alloc] initWithObjectsAndKeys:menuBarFont, NSFontAttributeName, [NSParagraphStyle defaultParagraphStyle], NSParagraphStyleAttributeName, nil]; 40 | isInitialzed = YES; 41 | } 42 | } 43 | 44 | - (id)init 45 | { 46 | self = [super init]; 47 | if (self) { 48 | } 49 | return self; 50 | } 51 | 52 | - (void)dealloc 53 | { 54 | [self releaseStatusItem]; 55 | [super dealloc]; 56 | } 57 | 58 | // Actually create the status item and assign the menu. 59 | - (void)createStatusItemWithMenu:(NSMenu *)_menu { 60 | menu = [_menu retain]; 61 | statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength] retain]; 62 | [statusItem setHighlightMode:YES]; 63 | [statusItem setMenu:menu]; 64 | [statusItem setEnabled:YES]; 65 | [self updateDisplay]; 66 | } 67 | 68 | // Allows updating the title as desired. 69 | - (void)updateDisplay { 70 | NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults]; 71 | NSString *title = [standardUserDefaults stringForKey:@"menu_title"]; 72 | NSString *tip = [standardUserDefaults stringForKey:@"tooltip"]; 73 | NSAttributedString *titleAttributedString = [[[NSAttributedString alloc] initWithString:title attributes:attributes] autorelease]; 74 | [statusItem setLength:NSVariableStatusItemLength]; 75 | [statusItem setAttributedTitle:titleAttributedString]; 76 | [statusItem setToolTip:tip]; 77 | } 78 | 79 | // Get rid of the menu when we're done. removeStatusItem: is key so that the space allocated for 80 | // the title & icon in the menubar is immediately reclaimed. Most apps fail to do this and leave 81 | // an unsightly gap in the menubar until another application becomes active. Let's be a good Cocoa 82 | // citizen and not do that. 83 | - (void)releaseStatusItem { 84 | if (menu) [menu release]; menu = nil; 85 | if (statusItem) { 86 | [[NSStatusBar systemStatusBar] removeStatusItem:statusItem]; 87 | [statusItem release]; 88 | statusItem = nil; 89 | } 90 | } 91 | 92 | @end 93 | -------------------------------------------------------------------------------- /icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmbuko/ADPassMon/24057beebe7f3e93e5e52ec07bde13633203cd63/icon.icns --------------------------------------------------------------------------------