2 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 // File: AppController.m
6 // Created: Wed Aug 13 2003
8 // Copyright: 2003 Chaz McGarvey. All rights reserved.
9 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11 #import "AppController.h"
13 #include "cheat_shared.h"
15 #import "SessionController.h"
16 #import "AboutBoxController.h"
17 #import "PreferenceController.h"
18 #import "NetTrafficController.h"
20 #import "CheatListener.h"
21 #import "CheatServer.h"
23 #import "ServerHolder.h"
26 @implementation AppController
29 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
30 #pragma mark Initialization
31 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
36 NSMutableDictionary
*defaults
= [NSMutableDictionary dictionary
];
40 //#ifndef TC_SHOW_LOGS
44 // change the socket path to reside in the home directory of the current user
45 strncpy( temp
, [NSHomeDirectory() lossyCString
], 103 );
46 strncat( temp
, TCDefaultListenPath
, 103 - strlen(TCDefaultListenPath
) );
47 strncpy( TCDefaultListenPath
, temp
, 103 );
49 [defaults setObject
:[NSNumber numberWithBool
:TCGlobalPlaySounds
] forKey
:TCPlaySoundsPref
];
50 [defaults setObject
:[NSNumber numberWithBool
:TCGlobalWindowsOnTop
] forKey
:TCWindowsOnTopPref
];
51 [defaults setObject
:[NSNumber numberWithBool
:TCGlobalUpdateCheck
] forKey
:TCUpdateCheckPref
];
52 [defaults setObject
:[NSNumber numberWithBool
:TCGlobalAllowRemote
] forKey
:TCAllowRemotePref
];
53 [defaults setObject
:[NSNumber numberWithInt
:TCGlobalListenPort
] forKey
:TCListenPortPref
];
54 [defaults setObject
:[NSString stringWithFormat
:@
"%@'s Computer", NSFullUserName()] forKey
:TCBroadcastNamePref
];
55 [defaults setObject
:[NSNumber numberWithInt
:TCGlobalHitsDisplayed
] forKey
:TCHitsDisplayedPref
];
57 [[NSUserDefaults standardUserDefaults
] registerDefaults
:defaults
];
59 TCGlobalPlaySounds
= [[NSUserDefaults standardUserDefaults
] boolForKey
:TCPlaySoundsPref
];
60 TCGlobalWindowsOnTop
= [[NSUserDefaults standardUserDefaults
] boolForKey
:TCWindowsOnTopPref
];
61 TCGlobalUpdateCheck
= [[NSUserDefaults standardUserDefaults
] boolForKey
:TCUpdateCheckPref
];
62 TCGlobalAllowRemote
= [[NSUserDefaults standardUserDefaults
] boolForKey
:TCAllowRemotePref
];
63 TCGlobalListenPort
= [[NSUserDefaults standardUserDefaults
] integerForKey
:TCListenPortPref
];
64 TCGlobalHitsDisplayed
= [[NSUserDefaults standardUserDefaults
] integerForKey
:TCHitsDisplayedPref
];
69 if ( self = [super init
] )
71 servers
= [[NSMutableArray alloc
] init
];
73 // start the server with saved settings
74 [self listenOnPort
:TCGlobalListenPort remote
:TCGlobalAllowRemote
];
75 if ( TCGlobalAllowRemote
) [self broadcastWithName
:TCGlobalBroadcastName
];
77 // set up the network browser
78 browser
= [[NSNetServiceBrowser alloc
] init
];
79 [browser setDelegate
:self];
80 [browser searchForServicesOfType
:@
"_cheat._tcp." inDomain
:@
"local."];
82 serverList
= [[NSMutableArray alloc
] init
];
84 [self setDelegate
:self];
93 [[NSNotificationCenter defaultCenter
] removeObserver
:self];
101 [serverList release
];
107 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
108 #pragma mark NSApplication Delegate
109 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
112 - (void)applicationDidFinishLaunching
:(NSNotification
*)aNotification
114 if ( TCGlobalUpdateCheck
)
116 [CMUpdateCheck checkWithURL
:@
"http://www.brokenzipper.com/software.plist" verbose
:NO
];
119 [self newSessionWindow
:self];
122 - (void)applicationDidBecomeActive
:(NSNotification
*)aNotification
124 /*if ( TCGlobalSessionCount == 0 )
126 [self newSessionWindow:self];
131 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
132 #pragma mark Server Starting/Stopping
133 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
136 - (void)listenOnPort
:(int)port remote
:(BOOL)remote
142 waitingToListen
= YES
;
143 connectionPort
= port
;
144 connectionRemote
= remote
;
148 connection
= [[CheatListener listenerWithDelegate
:self port
:port remote
:remote
] retain
];
149 connectionPort
= port
;
150 connectionRemote
= remote
;
159 [connection release
], connection
= nil;
164 - (void)broadcastWithName
:(NSString
*)name
166 [self stopBroadcast
];
168 service
= [[NSNetService alloc
] initWithDomain
:@
"local." type
:@
"_cheat._tcp." name
:name port
:TCGlobalListenPort
];
169 [service setDelegate
:self];
173 - (void)stopBroadcast
175 [service stop
], service
= nil;
179 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
180 #pragma mark Interface Activation
181 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
184 - (IBAction
)newSessionWindow
:(id)sender
186 [[[SessionController alloc
] init
] showWindow
:self];
189 - (IBAction
)showAboutBoxWindow
:(id)sender
191 if ( !aboutBoxController
)
193 aboutBoxController
= [[AboutBoxController alloc
] init
];
196 [aboutBoxController showWindow
:self];
199 - (IBAction
)showPreferenceWindow
:(id)sender
201 if ( !preferenceController
)
203 preferenceController
= [[PreferenceController alloc
] initWithDelegate
:self];
206 [preferenceController showWindow
:self];
209 - (IBAction
)showNetTrafficWindow
:(id)sender
211 if ( !netTrafficController
)
213 netTrafficController
= [[NetTrafficController alloc
] initWithDelegate
:self];
216 [netTrafficController showWindow
:self];
220 - (IBAction
)launchHelpFile
:(id)sender
222 //[[NSWorkspace sharedWorkspace] openFile:[[NSBundle mainBundle] pathForResource:@"Read Me" ofType:@"html"] withApplication:@"Safari"];
223 [[NSWorkspace sharedWorkspace
] openURL
:[NSURL fileURLWithPath
:[[NSBundle mainBundle
] pathForResource
:@
"Read Me" ofType
:@
"rtf"]]];
226 - (IBAction
)launchEmailMenu
:(id)sender
231 - (IBAction
)launchWebsiteMenu
:(id)sender
237 - (IBAction
)checkForUpdate
:(id)sender
239 [CMUpdateCheck checkWithURL
:@
"http://www.brokenzipper.com/software.plist"];
243 - (NSArray
*)serverList
249 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
250 #pragma mark Controlling Preferences
251 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
254 - (void)preferenceSetWindowsOnTop
:(BOOL)windowsOnTop
256 if ( TCGlobalWindowsOnTop
!= windowsOnTop
)
258 [[NSNotificationCenter defaultCenter
] postNotificationName
:@
"TCWindowsOnTopChanged" object
:[NSNumber numberWithBool
:windowsOnTop
]];
262 - (void)preferenceSetAllowRemote
:(BOOL)allow listenPort
:(int)port broadcastName
:(NSString
*)name
264 if ( TCGlobalAllowRemote
!= allow || TCGlobalListenPort
!= port
)
266 [self listenOnPort
:port remote
:allow
];
270 if ( !TCGlobalAllowRemote ||
![TCGlobalBroadcastName isEqualToString
:name
] )
272 [self broadcastWithName
:name
];
277 [self stopBroadcast
];
279 [netTrafficController serverSetAllowRemote
:allow listenPort
:port broadcastName
:name
];
280 //[netTrafficController allowRemoteChanged:allow];
281 //[netTrafficController listenPortChanged:port];
282 //[netTrafficController broadcastNameChanged:name];
286 - (void)preferenceAllowRemoteChanged:(BOOL)allow
288 [self listenOnPort:TCGlobalListenPort remote:allow];
292 [self broadcastWithName:TCGlobalBroadcastName];
296 [self stopBroadcast];
299 [netTrafficController allowRemoteChanged:allow];
302 - (void)preferenceListenPortChanged:(int)port
304 [self listenOnPort:port remote:TCGlobalAllowRemote];
305 [self broadcastWithName:TCGlobalBroadcastName];
307 [netTrafficController listenPortChanged:port];
310 - (void)preferenceBroadcastNameChanged:(NSString *)name
312 [self broadcastWithName:name];
314 [netTrafficController broadcastNameChanged:name];
319 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
320 #pragma mark Controlling NetTraffic
321 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
324 - (int)netTrafficConnectionCount
326 return [servers count
];
329 - (NSArray
*)netTrafficConnectionList
334 - (void)netTrafficKillConnection
:(int)index
336 CMLog( @
"kill connection" );
338 close( [[servers objectAtIndex
:index
] sockfd
] );
342 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
343 #pragma mark Controlling Listener
344 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
347 - (void)listenerListeningWithSocket
:(int)sock
351 TCGlobalListening
= YES
;
352 [[NSNotificationCenter defaultCenter
] postNotificationName
:@
"TCListenerStarted" object
:nil];
355 - (void)listenerDisconnected
357 if ( waitingToListen
)
359 waitingToListen
= NO
;
360 connection
= [[CheatListener listenerWithDelegate
:self port
:connectionPort remote
:connectionRemote
] retain
];
367 TCGlobalListening
= NO
;
368 [[NSNotificationCenter defaultCenter
] postNotificationName
:@
"TCListenerStopped" object
:nil];
371 - (void)listenerError
:(NSString
*)error message
:(NSString
*)message
373 NSRunCriticalAlertPanel( error
, message
, @
"OK", nil, nil );
376 - (void)listenerReceivedNewConnection
:(int)sock
378 [servers addObject
:[ServerHolder holderWithConnection
:[CheatServer serverWithDelegate
:self socket
:sock
] socket
:sock
]];
382 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
383 #pragma mark Controlling Server
384 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
387 - (void)server
:(CheatServer
*)server connectedWithSocket
:(int)sock
389 int i
, top
= [servers count
];
391 for ( i
= 0; i
< top
; i
++ )
393 if ( [(ServerHolder
*)[servers objectAtIndex
:i
] sockfd
] == sock
)
395 [(ServerHolder
*)[servers objectAtIndex
:i
] setServer
:server
];
400 [netTrafficController connectionListChanged
];
403 - (void)serverDisconnected
:(CheatServer
*)server
405 int i
, top
= [servers count
];
407 for ( i
= 0; i
< top
; i
++ )
409 if ( [(ServerHolder
*)[servers objectAtIndex
:i
] server
] == server
)
411 [servers removeObjectAtIndex
:i
];
416 [netTrafficController connectionListChanged
];
419 - (void)server
:(CheatServer
*)server changedAddress
:(NSString
*)address
421 int i
, top
= [servers count
];
423 for ( i
= 0; i
< top
; i
++ )
425 if ( [(ServerHolder
*)[servers objectAtIndex
:i
] server
] == server
)
427 [(ServerHolder
*)[servers objectAtIndex
:i
] setAddress
:address
];
432 [netTrafficController connectionListChanged
];
435 - (void)server
:(CheatServer
*)server changedAction
:(NSString
*)action
437 int i
, top
= [servers count
];
439 for ( i
= 0; i
< top
; i
++ )
441 if ( [(ServerHolder
*)[servers objectAtIndex
:i
] server
] == server
)
443 [(ServerHolder
*)[servers objectAtIndex
:i
] setAction
:action
];
448 [netTrafficController connectionListChanged
];
451 - (NSArray
*)serverProcessList
453 return [[NSWorkspace sharedWorkspace
] launchedApplications
];
456 - (pid_t
)serverFirstProcess
458 return (pid_t
)[[[[[NSWorkspace sharedWorkspace
] launchedApplications
] objectAtIndex
:0] objectForKey
:@
"NSApplicationProcessIdentifier"] intValue
];
462 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
463 #pragma mark NetService Delegate
464 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
467 - (void)netServiceWillPublish
:(NSNetService
*)sender
469 CMLog( @
"service will publish" );
473 - (void)netService
:(NSNetService
*)sender didNotPublish
:(NSDictionary
*)errorDict
475 CMLog( @
"service did not publish" );
477 if ( [[errorDict objectForKey
:@
"NSNetServicesErrorCode"] intValue
] == NSNetServicesCollisionError
)
479 [self broadcastWithName
:[NSString stringWithFormat
:@
"%@ %i", [sender name
], TCGlobalAlternateBroadcastNameCount
++]];
483 NSRunCriticalAlertPanel( @
"Network Error", @
"Server couldn't broadcast. Local can't be cheated by remote computers.", @
"OK", nil, nil );
487 - (void)netServiceDidStop
:(NSNetService
*)sender
489 CMLog( @
"service stopped" );
494 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
495 #pragma mark NetServiceBrowser Delegate
496 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
499 - (void)netServiceBrowser
:(NSNetServiceBrowser
*)browser didFindService
:(NSNetService
*)aService moreComing
:(BOOL)more
501 // a server has broadcast; not much use until it's resolved.
502 [aService setDelegate
:self];
506 - (void)netServiceDidResolveAddress
:(NSNetService
*)aService
508 int i
, top
= [serverList count
];
510 // ignore if this is the local server.
511 if ( TCGlobalAllowRemote
&& [[aService name
] isEqualToString
:TCGlobalBroadcastName
] )
516 // ignore if the server name is already in the list.
517 for ( i
= 0; i
< top
; i
++ )
519 if ( [[aService name
] isEqualToString
:[(NSNetService
*)[serverList objectAtIndex
:i
] name
]] )
525 [serverList addObject
:aService
];
526 CMLog( @
"server added: %i", [serverList count
] );
528 [[NSNotificationCenter defaultCenter
] postNotificationName
:@
"TCServerFound" object
:aService
];
531 - (void)netServiceBrowser
:(NSNetServiceBrowser
*)browser didRemoveService
:(NSNetService
*)aService moreComing
:(BOOL)more
533 int i
, top
= [serverList count
];
535 for ( i
= 0; i
< top
; i
++ )
537 if ( [[aService name
] isEqualToString
:[(NSNetService
*)[serverList objectAtIndex
:i
] name
]] )
539 [serverList removeObjectAtIndex
:i
];
540 CMLog( @
"server deleted: %i", [serverList count
] );
545 [[NSNotificationCenter defaultCenter
] postNotificationName
:@
"TCServerLost" object
:aService
];