/* * Grouch.app Copyright (C) 2006 Andy Sveikauskas * ------------------------------------------------------------------------ * This program is free software under the GNU General Public License * -- * This is the main UI class that the OSCAR code can interact with. * In practice we may have several of these (1 for each user you are * logged in as) */ #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import static NSMutableArray *namelessClients = nil; static NSMutableDictionary *namedClients = nil; @interface ClientInstanceYesNoPrompt : NSObject { id p; } - initWithObject:o; - (void)gotResult:(int)res; @end @implementation ClientInstanceYesNoPrompt - initWithObject:o { p = o; return self; } - (void)gotResult:(int)res { [p gotResult:(res == NSAlertDefaultReturn) ? self : nil]; [self release]; } @end @protocol DWDel - (BOOL)windowShouldDetach:sender; @end @implementation ClientInstance + (ClientInstance*)clientByName:(NSString*)name { return namedClients ?[namedClients objectForKey:[name screenNameKey]] : nil; } + (NSArray*)clientInstances { NSMutableArray *r = [[NSMutableArray new] autorelease]; if( namedClients ) { NSEnumerator *e = [namedClients objectEnumerator]; NSObject *o; while( (o=[e nextObject]) ) [r addObject:o]; } return r; } - init { [super init]; if( !namelessClients ) namelessClients = [NSMutableArray new]; [namelessClients addObject:self]; users = [GrouchTimedDictionary new]; [users expireTime:60*20]; chatRooms = [GrouchTimedDictionary new]; [chatRooms expireTime:1]; dependentWindows = [NSMutableDictionary new]; return self; } - (void)dealloc { NSEnumerator *e; NSWindow *w; NSDictionary *deps; loggedOff = YES; awayWindow = nil; // this will get freed below e = [deps=dependentWindows objectEnumerator]; dependentWindows = nil; while( (w=[e nextObject]) ) { NSObject *del = [w delegate]; BOOL shouldClose = YES; if( [del respondsToSelector:@selector(windowShouldDetach:)] ) shouldClose = ![(id)del windowShouldDetach:self]; if( shouldClose ) [w performClose:self]; } [deps release]; if( nick ) [nick release]; if( users ) [users release]; if( chatRooms ) [chatRooms release]; if( listWindow ) [listWindow release]; if( autoResponses ) [autoResponses release]; if( awayMsg ) [awayMsg release]; [super dealloc]; } - (void)setSock:(id)s { sock = s; } - (void)addDependentWindow:(NSWindow*)wnd { NSString *key = [NSString stringWithFormat:@"%p", wnd]; [dependentWindows setObject:wnd forKey:key]; } - (void)removeDependentWindow:(NSWindow*)wnd { if( dependentWindows ) { NSString *key = [NSString stringWithFormat:@"%p", wnd]; [dependentWindows removeObjectForKey:key]; } } - (void)setAway:(NSString*)str { if( awayWindow ) { AwayMessageWindow *w = awayWindow; awayWindow = nil; [w closeWindow]; } if( sock ) [sock away:str]; if( autoResponses ) [autoResponses release]; if( awayMsg ) [awayMsg release]; autoResponses = str ? [NSMutableDictionary new] : nil; awayMsg = str; if( awayMsg ) [awayMsg retain]; awayWindow = str ? [AwayMessageWindow windowWithMessage:awayMsg forInstance:self] : nil; } - (void)returnFromAway { [self setAway:nil]; } - (BOOL)isAway { return awayMsg ? YES : NO; } - (void)processAutoReply:(NSString*)who { NSNumber *delay = [Defaults get:@"Auto-response Time-out"]; int di = [delay intValue]; if( autoResponses && di ) { NSDate *d, *now = [NSDate date]; who = [who screenNameKey]; d = [autoResponses objectForKey:who]; if( !d || [d compare:now] <= 0 ) { now = [now addTimeInterval:di]; [autoResponses setObject:now forKey:who]; [sock sendMessage:awayMsg to:who withFlags:GrouchMessageReflect|GrouchMessageAway]; } } } - (void)setProfile:(NSString*)profile { [sock profile:profile]; } - (void)reloadData:(BOOL)newList { if( listWindow ) [listWindow reloadData:newList]; } - (void)reloadData { [self reloadData:NO]; } - (id)getUser:(NSString*)str { NSString *key = [str screenNameKey]; User *u = [users objectForKey:key]; if( u ) [u setNick:str]; else { u = [User userWithName:str forClient:self]; [users setObject:u forKey:key]; } [[u retain] autorelease]; [users expireObjects]; return u; } - (id)getChannel:(NSString*)str { NSString *key = [str screenNameKey]; Channel *c = [chatRooms objectForKey:key]; if( c ) { [c retain]; [c autorelease]; [chatRooms expireObjects]; return c; } else { c = [Channel channelForRoom:str andClient:self]; [chatRooms setObject:c forKey:key]; return c; } } - (void)statusMessage:(NSString*)status { if( !statusDone ) { if( !statusWindow ) [NSBundle loadGSMarkupNamed:@"StatusWindow" owner:self]; [statusLabel setStringValue:status]; [statusWindow orderFront:nil]; [statusWindow makeKeyWindow]; [statusWindow setHidesOnDeactivate:NO]; } } - (void)error:(NSString*)error fatal:(BOOL)fatal { [ErrorWindow errorWithString:error]; if( statusWindow ) { [statusWindow close]; [statusWindow release]; [statusLabel release]; statusWindow = nil; statusLabel = nil; } if( fatal ) { finishing = YES; [self bye]; } } - (void)welcome:(NSString*)n { if( !namedClients ) namedClients = [NSMutableDictionary new]; [namelessClients removeObject:self]; [namedClients setObject:self forKey:[n screenNameKey]]; [nick=n retain]; statusDone = YES; [statusWindow close]; [statusWindow release]; [statusLabel release]; statusWindow = nil; statusLabel = nil; listWindow = [BuddyList windowWithInstance:self]; { NSString *profile = [Defaults getSavedUserInfo:@"Profile" forUser:nick]; [sock profile:profile]; } } - (void)bye { if( !finishing ) { [ErrorWindow errorWithString: [GrouchString getString:@"conn-closed"]]; } [self logOff]; } - (void)yesNoPrompt:(id)promptObject title:(NSString*)title message:(NSString*)msg { NonModalAlertPanel *panel = [NonModalAlertPanel new]; [panel setTarget:[[ClientInstanceYesNoPrompt alloc] initWithObject:promptObject]]; [panel setAction:@selector(gotResult:)]; [panel setTitle:title message:msg def:[GrouchString getString:@"accept"] alt:[GrouchString getString:@"decline"] other:nil]; } - (void)logOff { if(loggedOff) return; loggedOff = finishing = YES; [(NSObject*)sock release]; sock = nil; if( nick ) [namedClients removeObjectForKey:[nick screenNameKey]]; else [namelessClients removeObject:self]; [self release]; } - (NSAttributedString*)formatMessage:(NSString*)msg from:(NSString*)who withFlags:(GrouchMessageFlags)flags { static NSString *dateFmt = @"%H:%M:%S"; BOOL reflect = flags&GrouchMessageReflect, emote = flags&GrouchMessageEmote, away = flags&GrouchMessageAway; NSDateFormatter *fmt = [[NSDateFormatter alloc] initWithDateFormat: dateFmt allowNaturalLanguage:NO]; NSString *date = [fmt stringForObjectValue:[NSDate date]]; [fmt release]; return [[NSString stringWithFormat: @"%@[%@] %@%@%s %@", [Defaults defaultTextTags], reflect ? "red" : "blue", date, [[self getUser:(reflect ? nick : who)] alias], away ? [GrouchString getString:@"away"] : @"", emote ? "" : ":", msg] parseHtml]; } - (id)session { return sock; } - (NSArray*)getUsers { NSMutableArray *r = [NSMutableArray array]; NSEnumerator *e = [users objectEnumerator]; User *u; while( (u=[e nextObject]) ) [r addObject:u]; return r; } - (NSArray*)getGroups { return [listWindow getGroups]; } - (NSString*)nick { return nick; } @end