From 9c2029e9a8340b17a6335467bda2bff9b0bd3d22 Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Sun, 28 Sep 2008 22:16:09 +0000 Subject: [PATCH] Flesh out KerberosAgent Select Identity dialog. Can now add, edit, and remove favorite identities Also, make formatters in KerberosFormatters.[hm] localizable. Still need to add principal validation and prevent duplicates. ticket: 6055 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@20771 dc483132-0cff-0310-8789-dd5450dbe970 --- src/kim/agent/mac/Identities.h | 60 +- src/kim/agent/mac/Identities.m | 904 +++++- src/kim/agent/mac/KIMUtilities.h | 16 + src/kim/agent/mac/KIMUtilities.m | 29 + src/kim/agent/mac/KerberosFormatters.h | 21 +- src/kim/agent/mac/KerberosFormatters.m | 170 +- src/kim/agent/mac/SelectIdentityController.h | 29 +- src/kim/agent/mac/SelectIdentityController.m | 195 +- .../English.lproj/SelectIdentity.xib | 2456 +++++++++++++---- .../mac/resources/KerberosFormatters.strings | Bin 0 -> 3446 bytes 10 files changed, 3194 insertions(+), 686 deletions(-) create mode 100644 src/kim/agent/mac/KIMUtilities.h create mode 100644 src/kim/agent/mac/KIMUtilities.m create mode 100644 src/kim/agent/mac/resources/KerberosFormatters.strings diff --git a/src/kim/agent/mac/Identities.h b/src/kim/agent/mac/Identities.h index 82819f8ee..cdb3167ac 100644 --- a/src/kim/agent/mac/Identities.h +++ b/src/kim/agent/mac/Identities.h @@ -23,24 +23,51 @@ */ #import +#import +#import "KIMUtilities.h" @interface Identity : NSObject { kim_identity kimIdentity; - int state; - cc_time_t expirationTime; - int favorite; - + kim_options kimOptions; + kim_credential_state state; + cc_time_t expiration_time; + BOOL favorite; } -@property(readonly) NSString *principal; -@property(readonly) NSString *timeRemaining; -@property int state; -@property cc_time_t expirationTime; -@property(readonly) int favorite; -- (id) initWithIdentity: (kim_identity) identity; -- (id) initWithFavoriteIdentity: (kim_identity) identity; +@property kim_identity kimIdentity; +@property kim_options kimOptions; +@property kim_credential_state state; +@property BOOL favorite; +@property cc_time_t expiration_time; + +// derived properties +@property(readonly) NSString *principalString; +@property(readonly) NSString *componentsString; +@property(readonly) NSString *realmString; +@property(readonly) NSDate *expirationDate; +@property(readonly) NSString *expirationString; +@property(readonly) NSString *validLifetimeString; +@property(readonly) NSString *renewableLifetimeString; +@property(readonly) BOOL hasCCache; +@property(readwrite) BOOL isRenewable; +@property(readwrite) BOOL isForwardable; +@property(readwrite) BOOL isAddressless; +@property(readwrite) BOOL isProxiable; +@property(readwrite) NSUInteger validLifetime; +@property(readwrite) NSUInteger renewableLifetime; + +- (id) initWithIdentity: (kim_identity) identity options: (kim_options) options; +- (id) initWithFavoriteIdentity: (kim_identity) identity options: (kim_options) options; - (BOOL) isEqualToKIMIdentity: (kim_identity) identity; +- (BOOL) isEqual: (Identity *)otherIdentity; + +- (kim_error) setPrincipalComponents: (NSString *) componentsString realm: (NSString *) realmString; + +- (void) resetOptions; +- (void) toggleFavorite; +- (BOOL) addToFavorites; +- (BOOL) removeFromFavorites; @end @@ -49,10 +76,17 @@ NSArray *favoriteIdentities; NSArray *identities; NSConnection *threadConnection; - } -@property(readonly, copy) NSArray *identities; +@property(readonly, retain) NSArray *identities; +@property(readonly) NSUInteger minimumValidLifetime; +@property(readonly) NSUInteger maximumValidLifetime; +@property(readonly) NSUInteger minimumRenewableLifetime; +@property(readonly) NSUInteger maximumRenewableLifetime; + +- (void) reload; - (int) update; +- (kim_error) addIdentity: (Identity *) anIdentity; +- (void) synchronizePreferences; @end diff --git a/src/kim/agent/mac/Identities.m b/src/kim/agent/mac/Identities.m index 211d980ee..e7cd31ae9 100644 --- a/src/kim/agent/mac/Identities.m +++ b/src/kim/agent/mac/Identities.m @@ -23,23 +23,89 @@ */ #import "Identities.h" -#import +#import + +#define VALID_LIFETIME_INCREMENT (5 * 60) +#define RENEWABLE_LIFETIME_INCREMENT (15 * 60) + +@interface Identity () + +- (NSString *)stringForLifetime:(NSUInteger)lifetime; + +@end + @implementation Identity @synthesize state; -@synthesize expirationTime; +@synthesize expiration_time; @synthesize favorite; +#pragma mark Initialization & Comparison + // --------------------------------------------------------------------------- -- (id) initWithIdentity: (kim_identity) identity ++ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key +{ + NSMutableSet *result = [[super keyPathsForValuesAffectingValueForKey:key] mutableCopy]; + NSSet *otherKeys = nil; + + if ([key isEqualToString:@"principalString"]) { + otherKeys = [NSSet setWithObjects:@"kimIdentity", nil]; + } + else if ([key isEqualToString:@"expirationDate"]) { + otherKeys = [NSSet setWithObjects:@"kimOptions", @"state", @"expirationTime", nil]; + } + else if ([key isEqualToString:@"expirationString"]) { + otherKeys = [NSSet setWithObjects:@"kimOptions", @"state", @"expirationTime", nil]; + } + else if ([key isEqualToString:@"isProxiable"]) { + otherKeys = [NSSet setWithObjects:@"kimOptions", nil]; + } + else if ([key isEqualToString:@"isForwardable"]) { + otherKeys = [NSSet setWithObjects:@"kimOptions", nil]; + } + else if ([key isEqualToString:@"isAddressless"]) { + otherKeys = [NSSet setWithObjects:@"kimOptions", nil]; + } + else if ([key isEqualToString:@"isRenewable"]) { + otherKeys = [NSSet setWithObjects:@"kimOptions", nil]; + } + else if ([key isEqualToString:@"validLifetime"]) { + otherKeys = [NSSet setWithObjects:@"kimOptions", nil]; + } + else if ([key isEqualToString:@"renewableLifetime"]) { + otherKeys = [NSSet setWithObjects:@"kimOptions", nil]; + } + else if ([key isEqualToString:@"validLifetimeString"]) { + otherKeys = [NSSet setWithObjects:@"kimOptions", @"validLifetime", nil]; + } + else if ([key isEqualToString:@"renewableLifetimeString"]) { + otherKeys = [NSSet setWithObjects:@"kimOptions", @"renewableLifetime", nil]; + } + + [result unionSet:otherKeys]; + + return [result autorelease]; +} + +// --------------------------------------------------------------------------- + +- (id) init +{ + return [self initWithIdentity: NULL options: NULL]; +} + +// --------------------------------------------------------------------------- + +- (id) initWithIdentity: (kim_identity) identity options: (kim_options) options { if ((self = [super init])) { - kimIdentity = identity; - state = kim_credentials_state_not_yet_valid; - expirationTime = 0; - favorite = FALSE; + self.kimIdentity = identity; + self.kimOptions = options; + self.state = kim_credentials_state_not_yet_valid; + self.expiration_time = 0; + self.favorite = FALSE; } return self; @@ -47,10 +113,10 @@ // --------------------------------------------------------------------------- -- (id) initWithFavoriteIdentity: (kim_identity) identity +- (id) initWithFavoriteIdentity: (kim_identity) identity options: (kim_options) options { - if ((self = [self initWithIdentity: identity])) { - favorite = TRUE; + if ((self = [self initWithIdentity: identity options: options])) { + self.favorite = TRUE; } return self; @@ -70,39 +136,451 @@ // --------------------------------------------------------------------------- -- (NSString *)principal +- (BOOL) isEqual: (Identity *)otherIdentity +{ + return ([self isEqualToKIMIdentity:otherIdentity.kimIdentity]); +} + +// --------------------------------------------------------------------------- + +- (NSUInteger)hash +{ + return [self.principalString hash]; +} + +// --------------------------------------------------------------------------- + +- (NSComparisonResult) compare: (Identity *)otherIdentity +{ + return ([self.principalString compare:otherIdentity.principalString]); +} + +#pragma mark Actions + +// --------------------------------------------------------------------------- + +- (void) resetOptions +{ + // property setter converts NULL into actual kim_options with default settings + self.kimOptions = NULL; +} + +// --------------------------------------------------------------------------- + +- (void) toggleFavorite +{ + if (self.favorite) { + [self removeFromFavorites]; + } else { + [self addToFavorites]; + } +} + +// --------------------------------------------------------------------------- + +- (BOOL) addToFavorites +{ + kim_error err = KIM_NO_ERROR; + kim_preferences preferences = NULL; + kim_options options = NULL; + kim_string error_string = NULL; + err = kim_preferences_create(&preferences); + + if (!err) { + err = kim_options_create(&options); + } + + if (!err) { + err = kim_preferences_add_favorite_identity(preferences, self.kimIdentity, options); + } + if (!err) { + err = kim_preferences_synchronize(preferences); + } + if (options) { + kim_options_free(&options); + } + kim_preferences_free(&preferences); + if (!err) { + self.favorite = true; + } else { + kim_string_create_for_last_error(&error_string, err); + NSLog(@"%s failed with %s", _cmd, error_string); + } + return (err != KIM_NO_ERROR); +} + +// --------------------------------------------------------------------------- + +- (BOOL) removeFromFavorites +{ + kim_error err = KIM_NO_ERROR; + kim_preferences preferences = NULL; + kim_options options = NULL; + kim_string error_string = NULL; + err = kim_preferences_create(&preferences); + + if (!err) { + err = kim_options_create(&options); + } + + if (!err) { + err = kim_preferences_remove_favorite_identity(preferences, self.kimIdentity); + } + if (!err) { + err = kim_preferences_synchronize(preferences); + } + if (options) { + kim_options_free(&options); + } + kim_preferences_free(&preferences); + if (!err) { + self.favorite = false; + } else { + kim_string_create_for_last_error(&error_string, err); + NSLog(@"%s failed with %s", _cmd, error_string); + } + return (err != KIM_NO_ERROR); +} + +#pragma mark Accessors + +// --------------------------------------------------------------------------- + +- (NSDate *) expirationDate +{ + return [NSDate dateWithTimeIntervalSince1970:expiration_time]; +} + +// --------------------------------------------------------------------------- + +- (BOOL) hasCCache +{ + kim_error err = KIM_NO_ERROR; + kim_ccache ccache = NULL; + + err = kim_ccache_create_from_client_identity(&ccache, self.kimIdentity); + + if (!err && ccache) { + return TRUE; + } + + return FALSE; +} + + +// --------------------------------------------------------------------------- + +- (kim_identity) kimIdentity +{ + return kimIdentity; +} + +// --------------------------------------------------------------------------- + +- (void) setKimIdentity:(kim_identity)newKimIdentity +{ + kim_error err = KIM_NO_ERROR; + kim_string string = NULL; + + if (!kimIdentity || kimIdentity != newKimIdentity) { + [self willChangeValueForKey:@"kimOptions"]; + + kim_identity_free(&kimIdentity); + kimIdentity = NULL; + if (newKimIdentity != NULL) { + kim_identity_get_display_string(newKimIdentity, &string); + err = kim_identity_copy(&kimIdentity, newKimIdentity); + } + + [self didChangeValueForKey:@"kimOptions"]; + } + + if (err) { + NSLog(@"%s got error %s", _cmd, error_message(err)); + } +} + +// --------------------------------------------------------------------------- + +- (kim_options) kimOptions +{ + return kimOptions; +} + +// --------------------------------------------------------------------------- + +- (void) setKimOptions:(kim_options)newKimOptions +{ + // Passing NULL resets to default options + kim_error err = KIM_NO_ERROR; + + if (!kimOptions || kimOptions != newKimOptions) { + [self willChangeValueForKey:@"kimOptions"]; + + kim_options_free(&kimOptions); + kimOptions = NULL; + + if (newKimOptions == NULL) { + err = kim_options_create(&kimOptions); + } else { + err = kim_options_copy(&kimOptions, newKimOptions); + } + + [self didChangeValueForKey:@"kimOptions"]; + } +} + +// --------------------------------------------------------------------------- + +- (BOOL) isRenewable +{ + kim_error err = KIM_NO_ERROR; + kim_boolean result = FALSE; + kim_options options = self.kimOptions; + + err = kim_options_get_renewable(options, &result); + + return (result != 0); +} + +// --------------------------------------------------------------------------- + +- (void) setIsRenewable: (BOOL) value +{ + kim_error err = KIM_NO_ERROR; + kim_options options = self.kimOptions; + + err = kim_options_set_renewable(options, value); +} + +// --------------------------------------------------------------------------- + +- (BOOL) isForwardable +{ + kim_error err = KIM_NO_ERROR; + kim_boolean result = FALSE; + kim_options options = self.kimOptions; + + err = kim_options_get_forwardable(options, &result); + + return (result != 0); +} + +// --------------------------------------------------------------------------- + +- (void) setIsForwardable: (BOOL) value +{ + kim_error err = KIM_NO_ERROR; + kim_options options = self.kimOptions; + + err = kim_options_set_forwardable(options, value); +} + +// --------------------------------------------------------------------------- + +- (BOOL) isAddressless +{ + kim_error err = KIM_NO_ERROR; + kim_boolean result = FALSE; + kim_options options = self.kimOptions; + + err = kim_options_get_addressless(options, &result); + + return (result != 0); +} + +// --------------------------------------------------------------------------- + +- (void) setIsAddressless: (BOOL) value +{ + kim_error err = KIM_NO_ERROR; + kim_options options = self.kimOptions; + + err = kim_options_set_addressless(options, value); +} + +// --------------------------------------------------------------------------- + +- (BOOL) isProxiable +{ + kim_error err = KIM_NO_ERROR; + kim_boolean result = FALSE; + kim_options options = self.kimOptions; + + err = kim_options_get_proxiable(options, &result); + + return (result != 0); +} + +// --------------------------------------------------------------------------- + +- (void) setIsProxiable: (BOOL) value +{ + kim_error err = KIM_NO_ERROR; + kim_options options = self.kimOptions; + + err = kim_options_set_proxiable(options, value); +} + +// --------------------------------------------------------------------------- + +- (NSUInteger) validLifetime +{ + kim_error err = KIM_NO_ERROR; + kim_lifetime value = 0; + kim_options options = self.kimOptions; + + err = kim_options_get_lifetime(options, &value); + + return (NSUInteger) value; +} + +// --------------------------------------------------------------------------- + +- (void) setValidLifetime: (NSUInteger) newLifetime +{ + kim_error err = KIM_NO_ERROR; + kim_options options = self.kimOptions; + + // round to nearest five minutes + newLifetime = (newLifetime / VALID_LIFETIME_INCREMENT) * VALID_LIFETIME_INCREMENT; + + err = kim_options_set_lifetime(options, (kim_lifetime) newLifetime); +} + +// --------------------------------------------------------------------------- + +- (NSUInteger) renewableLifetime +{ + kim_error err = KIM_NO_ERROR; + kim_lifetime value = 0; + kim_options options = self.kimOptions; + + err = kim_options_get_renewal_lifetime(options, &value); + + return (NSUInteger) value; +} + +// --------------------------------------------------------------------------- + +- (void) setRenewableLifetime: (NSUInteger) newLifetime +{ + kim_error err = KIM_NO_ERROR; + kim_options options = self.kimOptions; + + // round to nearest five minutes + newLifetime = (newLifetime / RENEWABLE_LIFETIME_INCREMENT) * RENEWABLE_LIFETIME_INCREMENT; + + err = kim_options_set_renewal_lifetime(options, (kim_lifetime) newLifetime); +} + +#pragma mark String representations + +// --------------------------------------------------------------------------- + +- (NSString *) principalString { kim_error err = KIM_NO_ERROR; kim_string display_string = NULL; NSString *result = nil; - err = kim_identity_get_display_string(kimIdentity, &display_string); + if (self.kimIdentity) { + err = kim_identity_get_display_string(self.kimIdentity, &display_string); + } - if (!err) { - result = [NSString stringWithCString:display_string encoding:NSUTF8StringEncoding]; + if (!err && display_string) { + result = [NSString stringWithUTF8String:display_string]; } else { result = @"-"; } + + if (err) { + NSLog(@"%s got error %s", _cmd, error_message(err)); + } + + kim_string_free(&display_string); + return result; } // --------------------------------------------------------------------------- -- (NSDate *)expirationDate +- (NSString *) componentsString { - return [NSDate dateWithTimeIntervalSince1970:expirationTime]; + kim_error err = KIM_NO_ERROR; + kim_string display_string = NULL; + NSString *result = @""; + + err = kim_identity_get_display_string(kimIdentity, &display_string); + // err = kim_identity_get_components(kimIdentity, &display_string); + + if (!err) { + NSRange atRange; + + result = [NSString stringWithUTF8String:display_string]; + atRange = [result rangeOfString:@"@" options:NSBackwardsSearch]; + result = [result substringToIndex:atRange.location]; + } + + kim_string_free(&display_string); + + return result; } // --------------------------------------------------------------------------- -- (NSString *)timeRemaining +- (NSString *) realmString +{ + kim_error err = KIM_NO_ERROR; + kim_string display_string = NULL; + NSString *result = @""; + + err = kim_identity_get_realm(kimIdentity, &display_string); + + if (!err) { + result = [NSString stringWithUTF8String:display_string]; + } + + kim_string_free(&display_string); + + return result; +} + +// --------------------------------------------------------------------------- + +- (kim_error) setPrincipalComponents: (NSString *) componentsString realm: (NSString *) realmString +{ + kim_error err = KIM_NO_ERROR; + kim_identity new_identity = NULL; + char *principal_string = NULL; + + asprintf(&principal_string, "%s@%s", + [componentsString UTF8String], [realmString UTF8String]); + + if (principal_string) { + err = kim_identity_create_from_string(&new_identity, principal_string); + } + + self.kimIdentity = new_identity; + + kim_identity_free(&new_identity); + if (principal_string) { + free(principal_string); + } + + return err; +} + +// --------------------------------------------------------------------------- + +- (NSString *) expirationString { NSString *result = nil; - if (expirationTime > 0) { + if (expiration_time > 0) { time_t now = time(NULL); - time_t lifetime = expirationTime - now; + time_t lifetime = expiration_time - now; time_t seconds = (lifetime % 60); time_t minutes = (lifetime / 60 % 60); time_t hours = (lifetime / 3600 % 24); @@ -114,38 +592,77 @@ result = [NSString stringWithFormat:@"%02ld:%02ld", hours, minutes]; } else { - result = @"Expired"; + result = @"--:--"; } - - NSLog(@"timeRemaining = %@ (expirationTime == %ld)", result, expirationTime); return result; } -- (NSString *)description +// --------------------------------------------------------------------------- + +- (NSString *) validLifetimeString +{ + return [self stringForLifetime:self.validLifetime]; +} + +// --------------------------------------------------------------------------- + +- (NSString *) renewableLifetimeString { - NSString *result = nil; - kim_error err = KIM_NO_ERROR; - kim_string display_name = NULL; + return [self stringForLifetime:self.renewableLifetime]; +} + +// --------------------------------------------------------------------------- - err = kim_identity_get_display_string(kimIdentity, &display_name); +- (NSString *)stringForLifetime:(NSUInteger)lifetime +{ + NSMutableArray *parts = nil; + NSUInteger days, hours, minutes, seconds; - if (!err) { - result = [NSString stringWithCString:display_name encoding:NSUTF8StringEncoding]; + days = (lifetime / 86400); + hours = (lifetime / (60 * 60) % 24); + minutes = (lifetime / 60 % 60); + seconds = (lifetime % 60); + + if (seconds > 0) { seconds = 0; minutes++; } + if (minutes > 59) { minutes = 0; hours++; } + if (hours > 23) { hours = 0; days++; } + + parts = [NSMutableArray arrayWithCapacity:3]; + if (days > 0) { + [parts addObject:[NSString stringWithFormat:@"%d days", days]]; } - return result; + if (hours > 0) { + [parts addObject:[NSString stringWithFormat:@"%d hours", hours]]; + } + if (minutes > 0) { + [parts addObject:[NSString stringWithFormat:@"%d minutes", minutes]]; + } + if ([parts count] == 0) { + [parts addObject:@"0 lifetime"]; + } + return [parts componentsJoinedByString:@", "]; +} + +// --------------------------------------------------------------------------- + +- (NSString *) description +{ + return [NSString stringWithFormat:@"%@ (%@) %@", self.principalString, self.expirationString, super.description]; } @end @interface Identities () -@property(readwrite, copy) NSArray *identities; +@property(readwrite, retain) NSArray *favoriteIdentities; +@property(readwrite, retain) NSArray *identities; @end @implementation Identities +@synthesize favoriteIdentities; @synthesize identities; // --------------------------------------------------------------------------- @@ -194,63 +711,10 @@ { if ((self = [super init])) { int err = 0; - NSMutableArray *newFavoriteIdentities = NULL; - + threadConnection = NULL; - identities = NULL; - favoriteIdentities = NULL; - - if (!err) { - newFavoriteIdentities = [[[NSMutableArray alloc] init] autorelease]; - if (!newFavoriteIdentities) { err = ENOMEM; } - } - - if (!err) { - kim_preferences kimPreferences = NULL; - kim_options kimOptions = NULL; - kim_count i; - kim_count count = 0; - - err = kim_preferences_create(&kimPreferences); - - if (!err) { - err = kim_preferences_get_number_of_favorite_identities(kimPreferences, - &count); - } - - for (i = 0; !err && i < count; i++) { - kim_identity kimIdentity = NULL; - Identity *identity = NULL; - - err = kim_preferences_get_favorite_identity_at_index(kimPreferences, - i, - &kimIdentity, - &kimOptions); - - if (!err) { - identity = [[[Identity alloc] initWithFavoriteIdentity: kimIdentity] autorelease]; - if (!identity) { err = ENOMEM; } - } - - if (!err) { - kimIdentity = NULL; /* take ownership */ - [newFavoriteIdentities addObject: identity]; - } - - kim_identity_free (&kimIdentity); - } - kim_preferences_free(&kimPreferences); - } - - if (!err) { - favoriteIdentities = [[NSArray alloc] initWithArray: newFavoriteIdentities]; - if (!favoriteIdentities) { err = ENOMEM; } - } - - if (!err) { - err = [self update]; - } + [self reload]; if (!err) { NSPort *port1 = [NSPort port]; @@ -294,14 +758,89 @@ // --------------------------------------------------------------------------- +- (void) reload +{ + kim_error err = KIM_NO_ERROR; + + NSMutableArray *newFavoriteIdentities = NULL; + + favoriteIdentities = NULL; + + if (!err) { + newFavoriteIdentities = [[NSMutableArray alloc] init]; + if (!newFavoriteIdentities) { err = ENOMEM; } + } + + if (!err) { + kim_preferences preferences = NULL; + kim_options kimOptions = NULL; + kim_count i; + kim_count count = 0; + + err = kim_preferences_create(&preferences); + + if (!err) { + err = kim_preferences_get_number_of_favorite_identities(preferences, + &count); + } + + for (i = 0; !err && i < count; i++) { + kim_identity kimIdentity = NULL; + Identity *identity = NULL; + + err = kim_preferences_get_favorite_identity_at_index(preferences, + i, + &kimIdentity, + &kimOptions); + + if (!err) { + identity = [[Identity alloc] initWithFavoriteIdentity: kimIdentity options: kimOptions]; + if (!identity) { err = ENOMEM; } + } + + if (!err) { + kimIdentity = NULL; /* take ownership */ + [newFavoriteIdentities addObject: identity]; + } + + if (identity) { + [identity release]; + identity = nil; + } + + kim_identity_free (&kimIdentity); + } + + kim_preferences_free(&preferences); + } + + if (!err) { + self.favoriteIdentities = newFavoriteIdentities; + if (!favoriteIdentities) { err = ENOMEM; } + } + + if (newFavoriteIdentities) { + [newFavoriteIdentities release]; + newFavoriteIdentities = nil; + } + + if (!err) { + [identities release]; + identities = nil; + err = [self update]; + } +} + +// --------------------------------------------------------------------------- + - (int) update { kim_error err = KIM_NO_ERROR; - NSMutableArray *newIdentities = NULL; + NSMutableSet *newIdentities = NULL; kim_ccache_iterator iterator = NULL; if (!err) { - newIdentities = [NSMutableArray arrayWithArray: favoriteIdentities]; + newIdentities = [NSMutableSet set]; if (!newIdentities) { err = ENOMEM; } } @@ -309,11 +848,15 @@ err = kim_ccache_iterator_create (&iterator); } + // Build list of identities with existing ccaches + while (!err) { kim_ccache ccache = NULL; kim_identity kimIdentity = NULL; + kim_options kimOptions = NULL; kim_credential_state state = kim_credentials_state_valid; kim_time expirationTime = 0; + kim_lifetime lifetime = 0; err = kim_ccache_iterator_next (iterator, &ccache); if (!err && !ccache) { break; } @@ -330,26 +873,29 @@ err = kim_ccache_get_expiration_time (ccache, &expirationTime); } + if (!err) { + err = kim_ccache_get_options(ccache, &kimOptions); + } + if (!err) { - Identity *identity = NULL; - - for (Identity *i in newIdentities) { - if ([i isEqualToKIMIdentity: kimIdentity]) { identity = i; } - } - - if (!identity) { - identity = [[[Identity alloc] initWithIdentity: kimIdentity] autorelease]; - if (!identity) { err = ENOMEM; } - - if (!err) { - kimIdentity = NULL; /* take ownership */ - [newIdentities addObject: identity]; - } - } + err = kim_options_get_lifetime(kimOptions, &lifetime); + } + + if (!err) { + Identity *identity = [[Identity alloc] initWithIdentity: kimIdentity options: kimOptions]; + if (!identity) { err = ENOMEM; } if (!err) { + kimIdentity = NULL; /* take ownership */ + identity.kimOptions = kimOptions; identity.state = state; - identity.expirationTime = expirationTime; + identity.expiration_time = expirationTime; + [newIdentities addObject: identity]; + } + + if (identity) { + [identity release]; + identity = nil; } } @@ -358,25 +904,165 @@ err = KIM_NO_ERROR; } + if (err) { + NSLog(@"%s got error %s", _cmd, error_message(err)); + } + + kim_options_free (&kimOptions); kim_identity_free (&kimIdentity); kim_ccache_free (&ccache); } - + + kim_ccache_iterator_free (&iterator); + + // Copy ccache state to favorites + for (Identity *identity in self.favoriteIdentities) { + Identity *matchingIdentity = [newIdentities member:identity]; + if (matchingIdentity) { + identity.state = matchingIdentity.state; + identity.expiration_time = matchingIdentity.expiration_time; + [newIdentities removeObject:matchingIdentity]; + } else { + identity.state = kim_credentials_state_expired; + identity.expiration_time = 0; + } + } + + // Add unused favorites + [newIdentities unionSet:[NSSet setWithArray:self.favoriteIdentities]]; + if (!err) { /* Use @property setter to trigger KVO notifications */ - self.identities = newIdentities; + self.identities = [[newIdentities allObjects] sortedArrayUsingSelector:@selector(compare:)]; if (!identities) { err = ENOMEM; } + } else { + NSLog (@"Got error %s", error_message (err)); } + return err; +} + +// --------------------------------------------------------------------------- + +- (kim_error) addIdentity: (Identity *) anIdentity +{ + kim_error err = KIM_NO_ERROR; + NSMutableArray *newIdentities = nil; + + if (![self.identities containsObject:anIdentity]) { + newIdentities = [self.identities mutableCopy]; + [newIdentities addObject:anIdentity]; + self.identities = newIdentities; + [newIdentities release]; + } else { + err = KIM_IDENTITY_ALREADY_IN_LIST_ERR; + } - kim_ccache_iterator_free (&iterator); + return err; +} + +// --------------------------------------------------------------------------- + +- (void) synchronizePreferences +{ + // Saves the kim_options for all identities in the list to disk, then rebuilds the Identities array from scratch + kim_error err = KIM_NO_ERROR; + kim_preferences prefs = NULL; + + err = kim_preferences_create(&prefs); + + if (!err) { + err = kim_preferences_remove_all_favorite_identities(prefs); + } + + for (Identity *identity in self.identities) { + if (!err && identity.favorite == TRUE) { + err = kim_preferences_add_favorite_identity(prefs, identity.kimIdentity, identity.kimOptions); + } + } + + if (!err) { + err = kim_preferences_synchronize(prefs); + } + + kim_preferences_free(&prefs); + if (err) { - NSLog (@"Got error %s", error_message (err)); + NSLog(@"%s received error %s", _cmd, error_message(err)); + } + + if (!err) { + [self reload]; } +} + +// --------------------------------------------------------------------------- + +- (NSUInteger)minimumValidLifetime +{ + kim_error err = KIM_NO_ERROR; + kim_preferences prefs = NULL; + kim_lifetime value = 0; - return err; + err = kim_preferences_create(&prefs); + + if (!err) { + kim_preferences_get_minimum_lifetime(prefs, &value); + } + + return (NSUInteger) value; +} + +// --------------------------------------------------------------------------- + +- (NSUInteger)maximumValidLifetime +{ + kim_error err = KIM_NO_ERROR; + kim_preferences prefs = NULL; + kim_lifetime value = 0; + + err = kim_preferences_create(&prefs); + + if (!err) { + kim_preferences_get_maximum_lifetime(prefs, &value); + } + + return (NSUInteger) value; +} + +// --------------------------------------------------------------------------- + +- (NSUInteger)minimumRenewableLifetime +{ + kim_error err = KIM_NO_ERROR; + kim_preferences prefs = NULL; + kim_lifetime value = 0; + + err = kim_preferences_create(&prefs); + + if (!err) { + kim_preferences_get_minimum_renewal_lifetime(prefs, &value); + } + + return (NSUInteger) value; } +// --------------------------------------------------------------------------- + +- (NSUInteger)maximumRenewableLifetime +{ + kim_error err = KIM_NO_ERROR; + kim_preferences prefs = NULL; + kim_lifetime value = 0; + + err = kim_preferences_create(&prefs); + + if (!err) { + kim_preferences_get_maximum_renewal_lifetime(prefs, &value); + } + + return (NSUInteger) value; +} @end diff --git a/src/kim/agent/mac/KIMUtilities.h b/src/kim/agent/mac/KIMUtilities.h new file mode 100644 index 000000000..790d238e6 --- /dev/null +++ b/src/kim/agent/mac/KIMUtilities.h @@ -0,0 +1,16 @@ +// +// KIMUtilities.h +// Kerberos5 +// +// Created by Justin Anderson on 9/28/08. +// Copyright 2008 MIT. All rights reserved. +// + +#import +#import + +@interface NSString (KIMUtilities) + ++ (NSString *) stringForLastKIMError: (kim_error) in_err; + +@end diff --git a/src/kim/agent/mac/KIMUtilities.m b/src/kim/agent/mac/KIMUtilities.m new file mode 100644 index 000000000..f8c7b8508 --- /dev/null +++ b/src/kim/agent/mac/KIMUtilities.m @@ -0,0 +1,29 @@ +// +// KIMUtilities.m +// Kerberos5 +// +// Created by Justin Anderson on 9/28/08. +// Copyright 2008 MIT. All rights reserved. +// + +#import "KIMUtilities.h" + + +@implementation NSString (KIMUtilities) + ++ (NSString *) stringForLastKIMError: (kim_error) in_err +{ + kim_error err = KIM_NO_ERROR; + kim_string string = NULL; + NSString *result = nil; + + err = kim_string_create_for_last_error(&string, in_err); + if (!err) { + result = [NSString stringWithUTF8String:string]; + } + kim_string_free(&string); + + return result; +} + +@end diff --git a/src/kim/agent/mac/KerberosFormatters.h b/src/kim/agent/mac/KerberosFormatters.h index 2d5336fce..104ea5f42 100644 --- a/src/kim/agent/mac/KerberosFormatters.h +++ b/src/kim/agent/mac/KerberosFormatters.h @@ -26,14 +26,27 @@ @interface KerberosTimeFormatter : NSFormatter { - + BOOL displaySeconds; + BOOL displayShortFormat; } +@property BOOL displaySeconds; +@property BOOL displayShortFormat; + - (NSString *)stringForObjectValue:(id)anObject; -- (BOOL)getObjectValue:(id *)anObject - forString:(NSString *)string - errorDescription:(NSString **)error; +- (NSAttributedString *)attributedStringForObjectValue:(id)anObject + withDefaultAttributes:(NSDictionary *)attributes; + +- (NSString *) stringForLifetime: (time_t) lifetime; + +@end + +@interface KerberosFavoriteFormatter : NSFormatter { + +} + +- (NSString *)stringForObjectValue:(id)anObject; - (NSAttributedString *)attributedStringForObjectValue:(id)anObject withDefaultAttributes:(NSDictionary *)attributes; diff --git a/src/kim/agent/mac/KerberosFormatters.m b/src/kim/agent/mac/KerberosFormatters.m index e1675bb70..b8a5b3aa4 100644 --- a/src/kim/agent/mac/KerberosFormatters.m +++ b/src/kim/agent/mac/KerberosFormatters.m @@ -24,10 +24,22 @@ #import "KerberosFormatters.h" -#define EXPIRED_STRING @"Expired" - @implementation KerberosTimeFormatter +@synthesize displaySeconds; +@synthesize displayShortFormat; + +- (id) init +{ + self = [super init]; + if (self != nil) { + // default to --:-- style + self.displaySeconds = NO; + self.displayShortFormat = YES; + } + return self; +} + /* * For display of Kerberos expiration times. * Converts an NSDate into an NSString like "09:53" for 9 hours and 53 minutes @@ -36,75 +48,125 @@ - (NSString *)stringForObjectValue:(id)anObject { NSString *result = nil; - if (anObject == nil || ![anObject respondsToSelector:@selector(timeIntervalSince1970)]) { - result = [NSString stringWithFormat:@"%s given invalid object %@", - _cmd, NSStringFromClass([anObject class])]; + + if (anObject == nil || ![anObject respondsToSelector:@selector(timeIntervalSinceNow)]) { + result = @""; } else { - time_t lifetime = [(NSDate *)anObject timeIntervalSince1970] - time(NULL); - - if (lifetime > 0) { - time_t seconds = (lifetime % 60); - time_t minutes = (lifetime / 60 % 60); - time_t hours = (lifetime / 3600 % 24); - time_t days = (lifetime / 86400); - - if (seconds > 0) { seconds = 0; minutes++; } - if (minutes > 59) { minutes = 0; hours++; } - if (hours > 23) { hours = 0; days++; } - - result = [NSString stringWithFormat:@"%02ld:%02ld", hours, minutes]; - } else { - result = EXPIRED_STRING; - } + result = [self stringForLifetime:(time_t)[(NSDate *)anObject timeIntervalSinceNow]]; } return result; } -/* - * Converts NSStrings like @"09:53" into NSDate representation of that point - * in the future. If string is @"Expired", NSDate is set to 1970. - */ +- (NSAttributedString *)attributedStringForObjectValue:(id)anObject + withDefaultAttributes:(NSDictionary *)attributes +{ + return [[[NSAttributedString alloc] initWithString:[self stringForObjectValue:anObject] + attributes:attributes] autorelease]; +} -- (BOOL)getObjectValue:(id *)anObject - forString:(NSString *)string - errorDescription:(NSString **)error +- (NSString *) stringForLifetime: (time_t) lifetime { - NSArray *tokens = [string componentsSeparatedByString:@":"]; - *anObject = nil; + NSMutableString *string = [NSMutableString string]; + NSString *separatorKey = (self.displayShortFormat) ? @"LifetimeStringSeparatorShortFormat" : + @"LifetimeStringSeparatorLongFormat"; + NSString *separator = NSLocalizedStringFromTable (separatorKey, @"KerberosFormatters", NULL); + NSString *key = NULL; + + // Break the lifetime up into time units + time_t days = (lifetime / 86400); + time_t hours = (lifetime / 3600 % 24); + time_t minutes = (lifetime / 60 % 60); + time_t seconds = (lifetime % 60); - if ([tokens count] == 2) { - NSInteger hours = [[tokens objectAtIndex:0] longValue]; - NSInteger minutes = [[tokens objectAtIndex:1] longValue]; - *anObject = [NSDate dateWithTimeIntervalSince1970:(hours * 60 * 60) + (minutes * 60)]; - } else if ([string isEqualToString:EXPIRED_STRING]) { - *anObject = [NSDate dateWithTimeIntervalSince1970:0]; + if (lifetime > 0) { + // If we aren't going to display seconds, round up + if (!self.displaySeconds) { + if (seconds > 0) { seconds = 0; minutes++; } + if (minutes > 59) { minutes = 0; hours++; } + if (hours > 23) { hours = 0; days++; } + } + + if (days > 0 && !self.displayShortFormat) { + if (self.displayShortFormat) { + key = (days > 1) ? @"LifetimeStringDaysShortFormat" : @"LifetimeStringDayShortFormat"; + } else { + key = (days > 1) ? @"LifetimeStringDaysLongFormat" : @"LifetimeStringDayLongFormat"; + } + [string appendFormat: NSLocalizedStringFromTable (key, @"KerberosFormatters", NULL), days]; + } + + if ((hours > 0) || self.displayShortFormat) { + if (self.displayShortFormat) { + key = (hours > 1) ? @"LifetimeStringHoursShortFormat" : @"LifetimeStringHourShortFormat"; + hours += days * 24; + days = 0; + } else { + key = (hours > 1) ? @"LifetimeStringHoursLongFormat" : @"LifetimeStringHourLongFormat"; + } + if ([string length] > 0) { [string appendString: separator]; } + [string appendFormat: NSLocalizedStringFromTable (key, @"KerberosFormatters", NULL), hours]; + } + + if ((minutes > 0) || self.displayShortFormat) { + if (self.displayShortFormat) { + key = (minutes > 1) ? @"LifetimeStringMinutesShortFormat" : @"LifetimeStringMinuteShortFormat"; + } else { + key = (minutes > 1) ? @"LifetimeStringMinutesLongFormat" : @"LifetimeStringMinuteLongFormat"; + } + if ([string length] > 0) { [string appendString: separator]; } + [string appendFormat: NSLocalizedStringFromTable (key, @"KerberosFormatters", NULL), minutes]; + } + + if (self.displaySeconds && ((seconds > 0) || self.displayShortFormat)) { + if (self.displayShortFormat) { + key = (seconds > 1) ? @"LifetimeStringSecondsShortFormat" : @"LifetimeStringSecondShortFormat"; + } else { + key = (seconds > 1) ? @"LifetimeStringSecondsLongFormat" : @"LifetimeStringSecondLongFormat"; + } + if ([string length] > 0) { [string appendString: separator]; } + [string appendFormat: NSLocalizedStringFromTable (key, @"KerberosFormatters", NULL), seconds]; + } + } else { + key = @"LifetimeStringExpired"; + [string appendString: NSLocalizedStringFromTable (key, @"KerberosFormatters", NULL)]; } - if (*anObject == nil) { - return false; + // Return an NSString (non-mutable) from our mutable temporary + return [NSString stringWithString: string]; +} + +@end + +@implementation KerberosFavoriteFormatter + +/* + * For displaying favorite status of KIM identities. + * Converts an NSNumber containing a boolean value into an NSString. + * If true, returns a heart character, /u2665. + * If false, returns empty string @"". + */ +- (NSString *)stringForObjectValue:(id)anObject +{ + NSString *key = nil; + if (anObject == nil || + ![anObject respondsToSelector:@selector(boolValue)] || + ([(NSNumber *)anObject boolValue] == FALSE)) { + key = @"FavoriteStringNotFavorite"; } - return true; + else { + key = @"FavoriteStringIsFavorite"; + } + + return NSLocalizedStringFromTable (key, @"KerberosFormatters", NULL); } - (NSAttributedString *)attributedStringForObjectValue:(id)anObject withDefaultAttributes:(NSDictionary *)attributes { - NSAttributedString *resultString = nil; - NSString *plainString = [self stringForObjectValue:anObject]; - NSMutableDictionary *newAttributes = [attributes mutableCopy]; - - if ([plainString isEqualToString:EXPIRED_STRING]) { - [newAttributes setObject:[NSColor redColor] - forKey:NSForegroundColorAttributeName]; - [newAttributes setObject: [NSNumber numberWithFloat: 0.3] - forKey: NSObliquenessAttributeName]; - } - - resultString = [[NSAttributedString alloc] initWithString:plainString attributes:newAttributes]; - [newAttributes release]; - - return [resultString autorelease]; + return [[[NSAttributedString alloc] initWithString:[self stringForObjectValue:anObject] + attributes:attributes] autorelease]; } + @end diff --git a/src/kim/agent/mac/SelectIdentityController.h b/src/kim/agent/mac/SelectIdentityController.h index 741f897f6..01bcd9228 100644 --- a/src/kim/agent/mac/SelectIdentityController.h +++ b/src/kim/agent/mac/SelectIdentityController.h @@ -28,31 +28,48 @@ @interface SelectIdentityController : NSWindowController { + IBOutlet NSObjectController *identitiesController; IBOutlet NSArrayController *identityArrayController; - + IBOutlet BadgedImageView *kerberosIconImageView; IBOutlet NSTextField *headerTextField; IBOutlet NSTextField *explanationTextField; IBOutlet NSTableView *identityTableView; IBOutlet NSTableColumn *identityTableColumn; - IBOutlet NSTableColumn *timeRemainingTableColumn; IBOutlet NSButton *addIdentityButton; - IBOutlet NSButton *removeIdentityButton; + IBOutlet NSPopUpButton *actionPopupButton; IBOutlet NSButton *selectIdentityButton; IBOutlet NSButton *cancelButton; - + Identities *identities; NSTimer *refreshTimer; + + IBOutlet NSWindow *identityOptionsWindow; + IBOutlet NSObjectController *identityOptionsController; + IBOutlet NSTextField *nameField; + IBOutlet NSTextField *realmField; } -- (IBAction) add: (id) sender; -- (IBAction) remove: (id) sender; +- (IBAction) newIdentity: (id) sender; +- (IBAction) addToFavorites: (id) sender; +- (IBAction) removeFromFavorites: (id) sender; + +- (IBAction) editOptions: (id) sender; +- (IBAction) resetOptions: (id) sender; +- (IBAction) cancelOptions: (id) sender; +- (IBAction) doneOptions: (id) sender; - (IBAction) select: (id) sender; - (IBAction) cancel: (id) sender; - (int) runWindow; +- (void) showOptions: (NSString *) contextInfo; +- (void) didEndSheet: (NSWindow *) sheet returnCode: (int) returnCode contextInfo: (void *) contextInfo; +- (void) saveOptions; + +- (void) reloadData; +- (void) refreshTable; - (void) timedRefresh:(NSTimer *)timer; diff --git a/src/kim/agent/mac/SelectIdentityController.m b/src/kim/agent/mac/SelectIdentityController.m index e7453a906..b26eaaa00 100644 --- a/src/kim/agent/mac/SelectIdentityController.m +++ b/src/kim/agent/mac/SelectIdentityController.m @@ -24,6 +24,7 @@ #import "SelectIdentityController.h" +#define identities_key_path @"identities" @implementation SelectIdentityController @@ -32,12 +33,11 @@ - (id) initWithWindowNibName: (NSString *) windowNibName { if ((self = [super initWithWindowNibName: windowNibName])) { - NSLog (@"SelectIdentityController initializing"); identities = [[Identities alloc] init]; [identities addObserver:self - forKeyPath:@"identities" + forKeyPath:identities_key_path options:NSKeyValueObservingOptionNew - context:@"SelectIdentityController"]; + context:@"selectIdentityController"]; refreshTimer = [NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:@selector(timedRefresh:) userInfo:nil repeats:true]; } @@ -56,7 +56,7 @@ - (void) dealloc { [refreshTimer release]; - [identities removeObserver:self forKeyPath:@"identities"]; + [identities removeObserver:self forKeyPath:identities_key_path]; [identities release]; [super dealloc]; } @@ -65,36 +65,64 @@ - (void) awakeFromNib { - [headerTextField setStringValue: @"Some header text"]; + [headerTextField setStringValue: @"Some header text"]; + [identityTableView setDoubleAction:@selector(select:)]; } // --------------------------------------------------------------------------- - (void) windowDidLoad { - [explanationTextField setStringValue: @"Some explanation text"]; - + [identitiesController setContent:identities]; } // --------------------------------------------------------------------------- -- (IBAction) add: (id) sender +- (IBAction) newIdentity: (id) sender { - NSLog(@"Add identity"); + Identity *newIdentity = [[Identity alloc] init]; + + newIdentity.favorite = TRUE; + identityOptionsController.content = newIdentity; + [newIdentity release]; + + NSLog(@"New identity %@", [newIdentity description]); + [self showOptions:@"new"]; } // --------------------------------------------------------------------------- -- (IBAction) remove: (id) sender +- (IBAction) addToFavorites: (id) sender { - NSLog(@"Remove identity"); + Identity *anIdentity = [identityArrayController.selectedObjects lastObject]; + identityOptionsController.content = nil; + NSLog(@"Add %@ to favorites", [anIdentity description]); + anIdentity.favorite = TRUE; + + [self saveOptions]; +} + +// --------------------------------------------------------------------------- + +- (IBAction) removeFromFavorites: (id) sender +{ + Identity *anIdentity = [identityArrayController.selectedObjects lastObject]; + identityOptionsController.content = anIdentity; + NSLog(@"Remove %@ from favorites", [anIdentity description]); + anIdentity.favorite = FALSE; + + [self saveOptions]; } // --------------------------------------------------------------------------- - (IBAction) select: (id) sender { + // ignore double-click on header + if ([sender respondsToSelector:@selector(clickedRow)] && [sender clickedRow] < 0) { + return; + } NSLog(@"Select identity: %@", identityArrayController.selectedObjects.description); } @@ -107,6 +135,49 @@ // --------------------------------------------------------------------------- +- (IBAction) editOptions: (id) sender +{ + Identity *anIdentity = [identityArrayController.selectedObjects lastObject]; + anIdentity.favorite = TRUE; + [identityOptionsController setContent: anIdentity]; + + [self showOptions:@"edit"]; +} + +// --------------------------------------------------------------------------- + +- (IBAction) resetOptions: (id) sender +{ + Identity *anIdentity = identityOptionsController.content; + // reset options to default settings + [anIdentity resetOptions]; +} + +// --------------------------------------------------------------------------- + +- (IBAction) cancelOptions: (id) sender +{ + identityOptionsController.content = nil; + [NSApp endSheet:identityOptionsWindow returnCode:NSUserCancelledError]; + + // dump changed settings + [identities reload]; +} + +// --------------------------------------------------------------------------- + +- (IBAction) doneOptions: (id) sender +{ + Identity *anIdentity = identityOptionsController.content; + + [anIdentity setPrincipalComponents: [nameField stringValue] + realm: [realmField stringValue]]; + + [NSApp endSheet: identityOptionsWindow]; +} + +// --------------------------------------------------------------------------- + - (int) runWindow { //[[NSApp delegate] addActiveWindow: [self window]]; @@ -124,21 +195,115 @@ // --------------------------------------------------------------------------- +- (void) showOptions: (NSString *) contextInfo +{ + Identity *anIdentity = identityOptionsController.content; + + [nameField setStringValue:anIdentity.componentsString]; + [realmField setStringValue:anIdentity.realmString]; + + [NSApp beginSheet: identityOptionsWindow + modalForWindow: [self window] + modalDelegate: self + didEndSelector: @selector(didEndSheet:returnCode:contextInfo:) + contextInfo: contextInfo]; +} + +// --------------------------------------------------------------------------- + +- (void) didEndSheet: (NSWindow *) sheet returnCode: (int) returnCode contextInfo: (void *) contextInfo +{ + kim_error err = KIM_NO_ERROR; + if (returnCode != NSUserCancelledError) { + if ([(NSString *)contextInfo isEqualToString:@"new"]) { + Identity *newIdentity = identityOptionsController.content; + err = [identities addIdentity:newIdentity]; + +#warning Add validation to prevent the addition of existing principals and invalid principals + if (err) { + NSLog(@"%s received error %@ trying to add identity %@", _cmd, [NSString stringForLastKIMError:err], [newIdentity description]); + } + [self saveOptions]; + } + else if ([(NSString *)contextInfo isEqualToString:@"edit"]) { + [self saveOptions]; + } + } + [sheet orderOut:self]; +} + +// --------------------------------------------------------------------------- + +- (void) saveOptions +{ + // attempt to preserve the selection + Identity *anIdentity = [[identityArrayController selectedObjects] lastObject]; + NSUInteger a, b, c; + + a = [identityArrayController.content indexOfObject: anIdentity]; + b = NSNotFound; + + [identities synchronizePreferences]; + + /* + * select same object as before if it's still in the array + * if not, select same index as before or end of array, whichever is less + */ + + b = [identityArrayController.content indexOfObject:anIdentity]; + c = [identityArrayController.content count] - 1; + + [identityArrayController setSelectionIndex: (b == NSNotFound) ? (a > c) ? c : a : b]; +} + +// --------------------------------------------------------------------------- + - (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - if ([(NSString *)context isEqualToString:@"SelectIdentityController"]) { - NSLog(@"========== identities array changed =========="); - identityArrayController.content = [[identities.identities mutableCopy] autorelease]; + if ([(NSString *) context isEqualToString:@"selectIdentityController"]) { + if ([keyPath isEqualToString:identities_key_path]) { +// [self reloadData]; + } } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } -- (void) timedRefresh:(NSTimer *)timer +// --------------------------------------------------------------------------- + +- (void) reloadData +{ + // Preserve selection + Identity *selectedIdentity = [[identityArrayController.selectedObjects lastObject] retain]; + NSUInteger a, b, c; + a = [identityArrayController selectionIndex]; + b = [[identityArrayController content] count]; + c = NSNotFound; + + NSLog(@"== updating table == %s", _cmd); + identityArrayController.content = identities.identities; + + c = [identityArrayController.content indexOfObject:selectedIdentity]; + if ([[identityArrayController content] count] >= a) + [identityArrayController setSelectionIndex:(c == NSNotFound) ? (a > b) ? b : a : c]; + + [selectedIdentity release]; +} + +// --------------------------------------------------------------------------- + +- (void) refreshTable { [identityArrayController rearrangeObjects]; } +// --------------------------------------------------------------------------- + +- (void) timedRefresh:(NSTimer *)timer +{ + // refetch data to update expiration times + [self refreshTable]; +} @end diff --git a/src/kim/agent/mac/resources/English.lproj/SelectIdentity.xib b/src/kim/agent/mac/resources/English.lproj/SelectIdentity.xib index 8e912b203..bf65e894d 100644 --- a/src/kim/agent/mac/resources/English.lproj/SelectIdentity.xib +++ b/src/kim/agent/mac/resources/English.lproj/SelectIdentity.xib @@ -8,7 +8,8 @@ 352.00 YES - + + YES @@ -28,7 +29,7 @@ 13 2 - {{279, 513}, {491, 315}} + {{279, 512}, {491, 316}} 1886913536 Select a Kerberos Identity @@ -47,7 +48,7 @@ 266 - {{101, 264}, {373, 17}} + {{101, 265}, {373, 17}} YES @@ -83,7 +84,7 @@ 266 - {{101, 219}, {373, 37}} + {{101, 220}, {373, 37}} YES @@ -100,48 +101,121 @@ - + + + 289 + {{390, 13}, {87, 32}} + + YES + + 67239424 + 134217728 + Select + + + -2038284033 + 1 + + + DQ + 200 + 25 + + + + + 289 + {{308, 13}, {82, 32}} + + YES + + 67239424 + 134217728 + Cancel + + + -2038284033 + 1 + + + Gw + 200 + 25 + + + + + 268 + {{20, 232}, {64, 64}} + + BadgedImageView + + + + 292 + {{20, 19}, {28, 24}} + + YES + + -2080244224 + 134217728 + + + + -2030812929 + 162 + + NSImage + NSAddTemplate + + + + 400 + 75 + + + 274 YES - - + + 2304 YES - - + + 256 {449, 133} - + YES - - + + 256 {449, 17} - - + + - - + + -2147483392 {{-26, 0}, {16, 17}} - + YES - - principal - 3.429741e+02 - 1.499741e+02 + + identityColumn + 2.670000e+02 + 4.000000e+01 1.000000e+03 75628032 0 Identity - + 3 MC4zMzMzMzI5OQA @@ -152,30 +226,64 @@ - - 1411513920 - 272761856 + + 337772096 + 2048 Text Cell - - - + + LucidaGrande + 1.100000e+01 + 16 + + + + 6 + System + controlBackgroundColor + + 3 YES - YES - + - - timeRemaining - 1.003135e+02 + + timeRemainingColumn + 1.500000e+02 1.000000e+02 - 1.500000e+02 + 2.000000e+02 - 67239424 + 75628032 67108864 Time Remaining + + + + + 67239488 + 67110912 + Text Cell + + + + + + 2 + YES + + + + favoriteColumn + 2.300000e+01 + 1.000000e+01 + 2.800000e+01 + + 75628032 + 134217728 + 4pmlA + 6 System @@ -187,19 +295,16 @@ - - 1140981312 - -2076048384 + + 67239488 + 134219776 Text Cell - - - + + + - 3 - YES - YES - + 3.000000e+00 @@ -215,203 +320,628 @@ 1.700000e+01 - 1119879168 - 5 + -1010827264 + SelectIdentityTable + 2 15 0 YES {{1, 17}, {449, 133}} - - - - - 6 - System - controlBackgroundColor - - + + + + 4 - - + + -2147483392 - {{-30, 17}, {15, 285}} - - + {{224, 17}, {15, 117}} + + _doScroller: - 9.684210e-01 + 3.700000e+01 + 1.947368e-01 - - - -2147483392 - {{-100, -100}, {362, 15}} - + + + 256 + {{-100, -100}, {223, 15}} + 1 - + _doScroller: - 9.040768e-01 + 7.689655e-01 - - + + 2304 YES - + {{1, 0}, {449, 17}} - - - + + + 4 - + - {{20, 60}, {451, 151}} + {{20, 61}, {451, 151}} - + 530 - - - - - + + + + + QSAAAEEgAABBmAAAQZgAAA - + - 289 - {{390, 12}, {87, 32}} + 292 + {{47, 19}, {54, 24}} YES - + + -2076049856 + 134219776 + + + -2034220801 + 162 + + + 400 + 75 + + + YES + + + 1048576 + 2147483647 + 1 + + NSImage + NSActionTemplate + + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + _popUpItemAction: + + + YES + + OtherViews + + YES + + + + YES + Remember Identity + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + Forget Identity + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + VGlja2V0IE9wdGlvbnPigKY + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + 1 + YES + 2 + YES + YES + 2 + + + + {491, 316} + + + {{0, 0}, {1920, 1178}} + {419, 320} + {600, 622} + SelectIdentityWindow + + + + YES + timeRemaining + isFavorite + principalString + favorite + + Identity + YES + + YES + YES + YES + YES + + + KerberosTimeFormatter + + + KerberosFavoriteFormatter + + + 7 + 2 + {{196, 132}, {427, 378}} + 603979776 + Window + NSWindow + + {3.40282e+38, 3.40282e+38} + + + 258 + + YES + + + 266 + {{69, 336}, {338, 22}} + + YES + + -1804468671 + 272630784 + + + user + + YES + + 6 + System + textBackgroundColor + + + + 6 + System + textColor + + + + + + + 268 + {{19, 338}, {45, 17}} + + YES + + 68288064 + 71304192 + Name: + + + + + + + + + 266 + {{69, 306}, {338, 22}} + + YES + + -1804468671 + 272630784 + + + REALM.ORG + + YES + + + + + + + 268 + {{17, 308}, {47, 17}} + + YES + + 68288064 + 71304192 + Realm: + + + + + + + + + 266 + + YES + + + 256 + + YES + + + 266 + {{24, 179}, {337, 25}} + + YES + + 67501824 + 0 + + + + + + 1.000000e+02 + 0.000000e+00 + 0.000000e+00 + 0.000000e+00 + 11 + 0 + NO + NO + + + + + 268 + {{13, 211}, {185, 17}} + + YES + + 67239424 + 4194304 + Get tickets that are valid for: + + + + + + + + + 266 + {{23, 157}, {339, 14}} + + YES + + 67239424 + 4325376 + 10 hours + + + + + + + + + 268 + {{13, 132}, {133, 17}} + + YES + + 67239424 + 71303168 + Kerberos 5 Options: + + + + + + + + + 266 + {{42, 34}, {301, 25}} + + YES + + 67501824 + 0 + + + + + Helvetica + 1.200000e+01 + 16 + + + 1.000000e+05 + 0.000000e+00 + 2.484663e+04 + 0.000000e+00 + 8 + 0 + NO + NO + + + + + 268 + {{24, 86}, {303, 18}} + + YES + + 67239424 + 0 + Get tickets without IP addresses (NAT mode) + + + 1211912703 + 2 + + NSSwitch + + + + 200 + 25 + + + + + 268 + {{24, 108}, {351, 18}} + + YES + + 67239424 + 0 + Get tickets that can be forwarded to other machines + + + 1211912703 + 2 + + + + 200 + 25 + + + + + 268 + {{24, 64}, {248, 18}} + + YES + + 67239424 + 0 + Get tickets that can be renewed for: + + + 1211912703 + 2 + + + + 200 + 25 + + + + + 266 + {{41, 12}, {303, 14}} + + YES + + 67239424 + 4325376 + 6 days, 17 hours, 45 minutes + + + + + + + + {{3, 3}, {387, 238}} + + + + {{17, 56}, {393, 244}} + + {0, 0} + + 67239424 + 0 + Ticket Options + + + + 3 + MCAwLjgwMDAwMDAxAA + + + + 2 + 1 + 0 + NO + + + + 289 + {{331, 12}, {82, 32}} + + YES + 67239424 134217728 - Select + OK - + -2038284033 - 1 - + 129 DQ 200 25 - - + + 289 - {{308, 12}, {82, 32}} - + {{249, 12}, {82, 32}} + YES - + 67239424 134217728 Cancel - + -2038284033 - 1 - + 129 Gw 200 25 - - - 292 - {{43, 30}, {22, 22}} - + + + 289 + {{129, 12}, {120, 32}} + YES - + 67239424 134217728 - + Use Defaults - - -2042347265 - 134 - - NSImage - Remove - - - NSImage - Remove_Pressed - + + -2038284033 + 129 - 400 - 75 + 200 + 25 - - - 292 - {{20, 30}, {23, 22}} - + + + -2147483380 + {{66, 338}, {344, 17}} + YES - - 67239424 - 134217728 - + + 68288064 + 272630784 + Label - - -2042347265 - 134 - - NSImage - Add - - - NSImage - Add_Pressed - - - - 400 - 75 + + + - - - 268 - {{20, 231}, {64, 64}} - - BadgedImageView + + + -2147483380 + {{66, 308}, {344, 17}} + + YES + + 68288064 + 272630784 + Label + + + + + - {491, 315} + {427, 378} - {{0, 0}, {1920, 1178}} - {419, 320} - {600, 622} + {{0, 0}, {1280, 778}} + {3.40282e+38, 3.40282e+38} - + YES - timeRemaining - principal - isFavorite - description - expirationDate + realmString + isForwardable + isProxiable + isRenewable + renewableLifetime + componentsString + favorite + isAddressless + validLifetime + renewableLifetimeString + validLifetimeString + hasCCache + Identity YES - YES - YES - YES - YES - YES - - KerberosTimeFormatter + + + YES + minimumValidLifetime + maximumValidLifetime + minimumRenewableLifetime + maximumRenewableLifetime + favorite + identities + + Identities + @@ -419,472 +949,1297 @@ YES - identityTableColumn + kerberosIconImageView - + - 300157 + 300158 - kerberosIconImageView + headerTextField - + - 300158 + 300163 - timeRemainingTableColumn + explanationTextField - + - 300159 + 300164 - removeIdentityButton + cancelButton - + - 300161 + 300165 - headerTextField + selectIdentityButton - + - 300163 + 300167 + + + + cancel: + + + + 300169 - explanationTextField + window - + - 300164 + 300181 - cancelButton + identityArrayController - + - 300165 + 300184 + + + + enabled: canAdd + + + + + + enabled: canAdd + enabled + canAdd + 2 + + + 300210 addIdentityButton - + + + 300214 + + + + content: arrangedObjects + + + + + + content: arrangedObjects + content + arrangedObjects + 2 + + + 300229 + + + + selectionIndexes: selectionIndexes + + + + + + selectionIndexes: selectionIndexes + selectionIndexes + selectionIndexes + + 2 + - 300166 + 300230 - selectIdentityButton - - + formatter + + - 300167 + 300242 - - select: + + formatter + + + + 300245 + + + + value: arrangedObjects.principalString + + + + + + value: arrangedObjects.principalString + value + arrangedObjects.principalString + + NSConditionallySetsEditable + + + 2 + + + 300246 + + + + delegate + + + + 300251 + + + + identityTableView - + - 300168 + 300252 cancel: - + - 300169 + 300253 - - identityTableView + + value: arrangedObjects.expirationDate + + + + + + value: arrangedObjects.expirationDate + value + arrangedObjects.expirationDate + + NSConditionallySetsEditable + + + 2 + + + 300255 + + + + sortDescriptors: sortDescriptors + + + + + + sortDescriptors: sortDescriptors + sortDescriptors + sortDescriptors + + 2 + + + 300259 + + + + select: - + - 300172 + 300293 delegate - - + + - 300174 + 300325 - window - - + delegate + + - 300181 + 300328 + + + + enabled: selection.isRenewable + + + + + + enabled: selection.isRenewable + enabled + selection.isRenewable + 2 + + + 300356 - identityArrayController + identityOptionsController - + - 300184 + 300357 - content: arrangedObjects - + value: selection.isRenewable + + + + + + value: selection.isRenewable + value + selection.isRenewable + 2 + + + 300366 + + + + value: arrangedObjects.favorite + - - + + - content: arrangedObjects - content - arrangedObjects + value: arrangedObjects.favorite + value + arrangedObjects.favorite + 2 + + + 300367 + + + + value: selection.isForwardable + + + + + + value: selection.isForwardable + value + selection.isForwardable + 2 + + + 300368 + + + + value: selection.isAddressless + + + + + + value: selection.isAddressless + value + selection.isAddressless + 2 + + + 300369 + + + + maxValue: selection.maximumValidLifetime + + + + + + maxValue: selection.maximumValidLifetime + maxValue + selection.maximumValidLifetime 2 - 300185 - - - - value: arrangedObjects.principal - - - - - - value: arrangedObjects.principal - value - arrangedObjects.principal - 2 - + 300372 + + + + minValue: selection.minimumValidLifetime + + + + + + minValue: selection.minimumValidLifetime + minValue + selection.minimumValidLifetime + + 2 + + + 300373 + + + + value: selection.validLifetime + + + + + + value: selection.validLifetime + value + selection.validLifetime + + 2 + + + 300378 + + + + identitiesController + + + + 300380 + + + + maxValue: selection.maximumRenewableLifetime + + + + + + maxValue: selection.maximumRenewableLifetime + maxValue + selection.maximumRenewableLifetime + 2 + + + 300381 + + + + minValue: selection.minimumRenewableLifetime + + + + + + minValue: selection.minimumRenewableLifetime + minValue + selection.minimumRenewableLifetime + + 2 + + + 300384 + + + + value: selection.renewableLifetime + + + + + + value: selection.renewableLifetime + value + selection.renewableLifetime + + 2 + + + 300385 + + + + value: selection.renewableLifetimeString + + + + + + value: selection.renewableLifetimeString + value + selection.renewableLifetimeString + 2 + + + 300386 + + + + value: selection.validLifetimeString + + + + + + value: selection.validLifetimeString + value + selection.validLifetimeString + 2 + + + 300388 + + + + nameField + + + + 300396 + + + + realmField + + + + 300397 + + + + value: selection.componentsString + + + + + + value: selection.componentsString + value + selection.componentsString + 2 + + + 300404 + + + + value: selection.realmString + + + + + + value: selection.realmString + value + selection.realmString + 2 + + + 300411 + + + + hidden: selection.hasCCache + + + + + + hidden: selection.hasCCache + hidden + selection.hasCCache + 2 + + + 300419 + + + + hidden: selection.hasCCache + + + + + + hidden: selection.hasCCache + hidden + selection.hasCCache + + NSValueTransformerName + NSNegateBoolean + + 2 + + + 300420 + + + + hidden: selection.hasCCache + + + + + + hidden: selection.hasCCache + hidden + selection.hasCCache + + NSValueTransformerName + NSNegateBoolean + + 2 + + + 300421 + + + + hidden: selection.hasCCache + + + + + + hidden: selection.hasCCache + hidden + selection.hasCCache + 2 + + + 300422 + + + + hidden: selection.favorite + + + + + + hidden: selection.favorite + hidden + selection.favorite + 2 + + + 300438 + + + + hidden: selection.favorite + + + + + + hidden: selection.favorite + hidden + selection.favorite + + NSValueTransformerName + NSNegateBoolean + + 2 + + + 300440 + + + + addToFavorites: + + + + 300441 + + + + removeFromFavorites: + + + + 300442 + + + + contentArray: selection.identities + + + + + + contentArray: selection.identities + contentArray + selection.identities + 2 + + + 300444 + + + + newIdentity: + + + + 300450 + + + + identityOptionsWindow + + + + 300451 + + + + editOptions: + + + + 300452 + + + + cancelOptions: + + + + 300453 + + + + resetOptions: + + + + 300454 + + + + doneOptions: + + + + 300455 + + + + + YES + + 0 + + YES + + + + + + -2 + + + RmlsZSdzIE93bmVyA + + + -1 + + + First Responder + + + 5 + + + YES + + + + Select a Kerberos Identity + + + 6 + + + YES + + + + + + + + + + + + + 8 + + + YES + + + + + + 15 + + + YES + + + + + + 16 + + + YES + + + + + + 100008 + + + + + 100015 + + + + + 100016 + + + + + -3 + + + Application + + + 300118 + + + YES + + + + + + 300119 + + + + + 300156 + + + + + 300183 + + + Identities Array Controller + + + 300196 + + + Time Formatter + + + 300206 + + + YES + + + + + + 300207 + + + + + 300216 + + + YES + + + + + + + + + 300217 + + + + + 300218 + + + + + 300219 + + + YES + + + + + + + + 300220 + + + + + 300221 + + + YES + + + + + + 300222 + + + YES + + + + + + 300223 + + + + + 300224 + + + + + 300225 + + + YES + + + + + + 300226 + + - 300187 - - - - remove: - - + + 300244 + + + Favorite Formatter - 300189 - - - - insert: - - + + 300294 + + + YES + + + + Ticket Options Sheet - 300191 - - - - formatter - - + + 300295 + + + YES + + + + + + + + + + + + - 300197 - - - - value: arrangedObjects.expirationDate - - - - - - value: arrangedObjects.expirationDate - value - arrangedObjects.expirationDate - - NSConditionallySetsEditable - - - 2 + + 300296 + + + YES + + + + + + + + + + - 300198 - - - - selectionIndexes: selectionIndexes - - - - - - selectionIndexes: selectionIndexes - selectionIndexes - selectionIndexes - - 2 + + 300298 + + + YES + + - 300199 - - - - enabled: canRemove - - - - - - enabled: canRemove - enabled - canRemove - 2 + + 300299 + + + YES + + - 300200 - - - - enabled: canInsert - - - - - - enabled: canInsert - enabled - canInsert - 2 + + 300300 + + + YES + + - 300201 - - - - - YES - 0 - + 300301 + + YES + - - + - -2 - - - RmlsZSdzIE93bmVyA + 300302 + + - -1 - - - First Responder + 300303 + + - 5 - + 300304 + + + + + 300305 + + + + + 300307 + YES - + - - Select a Kerberos Identity + - 6 - + 300308 + YES - - - - - - - - + - + - 8 - + 300309 + YES - + - + - 9 - + 300310 + YES - - - - + - + - 10 - + 300311 + YES - - + - + - 11 - + 300312 + YES - + - + - 18 - + 300313 + YES - + - + - 15 - + 300314 + YES - + - + - 16 - + 300315 + YES - + - + - 100008 - - + 300316 + + - 100015 - - + 300317 + + - 100016 - - + 300318 + + - 100009 - - + 300319 + + - 200009 - - + 300320 + + - 300009 - - + 300321 + + - -3 - + 300322 + + + + + 300323 + + + + + 300324 + + + + + 300329 + + + YES + + + + + + 300330 + + + + + 300331 + - Application + Identity Options Controller + + + 300334 + + + YES + + + - 300018 - - + 300335 + + - 300019 - + 300358 + YES + - + - 300118 - + 300359 + + + + + 300370 + + + Identities Controller + + + 300402 + YES - + - + - 300119 - - + 300403 + + - 300152 - + 300407 + YES - + - + - 300153 - - + 300408 + + - 300154 - + 300426 + YES - + - 300155 - - + 300427 + + + YES + + + - 300156 - - + 300428 + + + YES + + + + + + - 300183 - - - Identity Array Controller + 300429 + + - 300196 - - + 300430 + + + + + 300431 + + + + + 300432 + + @@ -894,30 +2249,86 @@ YES -1.IBPluginDependency -2.IBPluginDependency - 10.IBPluginDependency - 10.ImportedFromIB2 - 100009.IBShouldRemoveOnLegacySave - 11.IBPluginDependency - 11.ImportedFromIB2 15.IBPluginDependency 15.ImportedFromIB2 16.IBPluginDependency 16.ImportedFromIB2 - 18.IBPluginDependency - 18.ImportedFromIB2 - 200009.IBShouldRemoveOnLegacySave - 300009.IBShouldRemoveOnLegacySave - 300018.IBPluginDependency - 300019.IBPluginDependency 300118.IBPluginDependency 300118.ImportedFromIB2 - 300152.IBPluginDependency - 300153.IBPluginDependency - 300154.IBPluginDependency - 300155.IBPluginDependency 300156.IBPluginDependency 300183.IBPluginDependency 300196.IBPluginDependency + 300206.IBPluginDependency + 300207.IBPluginDependency + 300216.IBPluginDependency + 300217.IBPluginDependency + 300218.IBPluginDependency + 300219.IBPluginDependency + 300220.IBPluginDependency + 300220.IBViewIntegration.shadowBlurRadius + 300220.IBViewIntegration.shadowColor + 300220.IBViewIntegration.shadowOffsetHeight + 300220.IBViewIntegration.shadowOffsetWidth + 300221.IBPluginDependency + 300222.IBPluginDependency + 300223.IBPluginDependency + 300224.IBPluginDependency + 300244.IBPluginDependency + 300294.IBEditorWindowLastContentRect + 300294.IBPluginDependency + 300294.IBWindowTemplateEditedContentRect + 300294.NSWindowTemplate.visibleAtLaunch + 300294.windowTemplate.hasMaxSize + 300294.windowTemplate.maxSize + 300295.IBPluginDependency + 300296.IBPluginDependency + 300296.ImportedFromIB2 + 300298.IBPluginDependency + 300299.IBPluginDependency + 300300.IBPluginDependency + 300301.IBPluginDependency + 300302.IBPluginDependency + 300303.IBPluginDependency + 300304.IBPluginDependency + 300305.IBPluginDependency + 300307.IBPluginDependency + 300307.ImportedFromIB2 + 300308.IBPluginDependency + 300308.ImportedFromIB2 + 300309.IBPluginDependency + 300309.ImportedFromIB2 + 300310.IBPluginDependency + 300310.ImportedFromIB2 + 300311.IBPluginDependency + 300311.ImportedFromIB2 + 300312.IBPluginDependency + 300312.ImportedFromIB2 + 300313.IBPluginDependency + 300313.ImportedFromIB2 + 300314.IBPluginDependency + 300314.ImportedFromIB2 + 300315.IBPluginDependency + 300315.ImportedFromIB2 + 300329.IBPluginDependency + 300330.IBPluginDependency + 300331.IBPluginDependency + 300334.IBPluginDependency + 300335.IBPluginDependency + 300358.IBPluginDependency + 300359.IBPluginDependency + 300370.IBPluginDependency + 300402.IBPluginDependency + 300403.IBPluginDependency + 300407.IBPluginDependency + 300408.IBPluginDependency + 300426.IBPluginDependency + 300427.IBPluginDependency + 300428.IBEditorWindowLastContentRect + 300428.IBPluginDependency + 300429.IBPluginDependency + 300430.IBPluginDependency + 300431.IBPluginDependency + 300432.IBPluginDependency 5.IBEditorWindowLastContentRect 5.IBPluginDependency 5.IBWindowTemplateEditedContentRect @@ -932,53 +2343,105 @@ 6.ImportedFromIB2 8.IBPluginDependency 8.ImportedFromIB2 - 9.IBPluginDependency - 9.ImportedFromIB2 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.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 + {{360, 291}, {427, 378}} + com.apple.InterfaceBuilder.CocoaPlugin + {{360, 291}, {427, 378}} + + + {10000, 354} + 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 + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{606, 541}, {491, 315}} com.apple.InterfaceBuilder.CocoaPlugin - {{606, 541}, {491, 315}} - - + 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 + {{535, 102}, {198, 83}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{499, 142}, {491, 316}} + com.apple.InterfaceBuilder.CocoaPlugin + {{499, 142}, {491, 316}} + + {{503, 256}, {419, 465}} - - + + {600, 600} {419, 298} com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - + @@ -1001,7 +2464,7 @@ - 300201 + 300455 @@ -1023,13 +2486,18 @@ - KerberosTimeFormatter + KerberosFavoriteFormatter NSFormatter - + IBProjectSource ../Sources/kim/agent/mac/KerberosFormatters.h + + KerberosTimeFormatter + NSFormatter + + SelectIdentityController NSWindowController @@ -1037,9 +2505,14 @@ YES YES - add: + addToFavorites: cancel: - remove: + cancelOptions: + doneOptions: + editOptions: + newIdentity: + removeFromFavorites: + resetOptions: select: @@ -1048,37 +2521,50 @@ id id id + id + id + id + id + id YES YES + actionPopupButton addIdentityButton cancelButton explanationTextField headerTextField + identitiesController identityArrayController + identityOptionsController + identityOptionsWindow identityTableColumn identityTableView kerberosIconImageView - removeIdentityButton + nameField + realmField selectIdentityButton - timeRemainingTableColumn YES + NSPopUpButton NSButton NSButton NSTextField NSTextField + NSObjectController NSArrayController + NSObjectController + NSWindow NSTableColumn NSTableView BadgedImageView + NSTextField + NSTextField NSButton - NSButton - NSTableColumn diff --git a/src/kim/agent/mac/resources/KerberosFormatters.strings b/src/kim/agent/mac/resources/KerberosFormatters.strings new file mode 100644 index 0000000000000000000000000000000000000000..707ba534084948f0871afeef4e8dfc7485fa96b3 GIT binary patch literal 3446 zcmchaPfx-?5XI;0r`R;nlP1O^#)E$#5|Nmo-U%&26d@E;zP$Qo$4zG&vAY{XNZF>q zy!p+WZilbWjCwSsF%`7JI>S1^*%Ifk^h9m?passCxSmr+Ch~QL?`L#`SIfRLNbBIjlSO+w*>xw#do!L*eWh0s`sHAB1puprIN`^%1&{8(5T_Nucm61GE z%|&gWUT7Ue=k(&3e%CYbU$PIWt0>3$R_VIB#*(IT`g)Eug!3BRvPOrddg>fKrjuY- zE6p@sr^#Jp?42b9F}$hHI_(tRG}^kiypu3*2<@%i1=rYxiX?|qXnoCiW~V9c&OCxx z<`kEmevHGKIi9%gux1V+=I71G?)v%8T=q5NnO&8|<xM4D#4}id z>4Yb>A)Xgn@zGwHCQWHfD2h6Y%rni(!m5AiDi*eivP3bY@b zlYZmLbw&5^h^Ogh&xKz{G1gg$V^pNjjQY^!UMW>Id6u5qT`n}EDvEYR#|h2n0==2j zIgZ?Raf!^Dv#7d9D%7Pr^r;`k;J%n3I#2BK4~28$ouIjIAMmSZ9CLcddmG0HHQM06 YM~G|gj`5?IpEye!$5os?ba6SqZ;~tQ?f?J) literal 0 HcmV?d00001 -- 2.26.2