//
#import "AFSBackgrounderDelegate.h"
-
+#import "AFSMenuExtraView.h"
+#import "AFSPropertyManager.h"
+#import "TaskUtil.h"
+#import "TokenCredentialController.h"
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
@implementation AFSBackgrounderDelegate
+#pragma mark NSApp Delegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSLog(@"applicationDidFinishLaunching");
//Create the NSStatusBar and set its length
statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
//Used to detect where our files are
- NSBundle *bundle = [NSBundle mainBundle];
-
- //Allocates and loads the images into the application which will be used for our NSStatusItem
- statusImage = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"hasToken" ofType:@"png"]];
- statusHighlightImage = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"noToken" ofType:@"png"]];
+ //NSBundle *bundle = [NSBundle mainBundle];
//Sets the images in our NSStatusItem
- [statusItem setImage:statusImage];
- [statusItem setAlternateImage:statusHighlightImage];
-
- //Tells the NSStatusItem what menu to load
- [statusItem setMenu:backgrounderMenu];
- //Sets the tooptip for our item
- [statusItem setToolTip:@"Andrews Menu Item"];
- //Enables highlighting
- [statusItem setHighlightMode:YES];
+ statusItem = nil;
+
+
+ // Get the imge for menu
+ //Load image for menu rappresentation
+ hasTokenImage = [self getImageFromBundle:@"hasToken"
+ fileExt:@"png"];
+
+ noTokenImage = [self getImageFromBundle:@"noToken"
+ fileExt:@"png"];
+
+ //Start to read the afs path
+ [self readPreferenceFile:nil];
+ [self startTimer];
+
+
+
+ // Register for preference user change
+ [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(readPreferenceFile:)
+ name:kAFSMenuExtraID object:kPrefChangeNotification];
+
+ // Register for afs state change
+ [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(afsVolumeMountChange:)
+ name:kAFSMenuExtraID object:kMExtraAFSStateChange];
+
+ // Register for menu state change
+ [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(chageMenuVisibility:)
+ name:kAFSMenuExtraID object:kMExtraAFSMenuChangeState];
+
+ //Register for mount/unmount afs volume
+ [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
+ selector:@selector(afsVolumeMountChange:)
+ name:NSWorkspaceDidMountNotification object:nil];
+
+ [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
+ selector:@selector(afsVolumeMountChange:)
+ name:NSWorkspaceDidUnmountNotification object:nil];
+
+ //try to see if we need tho show the menu at startup
+ NSLog(@"showStatusMenu %d", [showStatusMenu intValue]);
+ [self setStatusItem:[showStatusMenu boolValue]];
+
+}
+
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
+ if(afsSysPath) [afsSysPath release];
+
+ //release the lock
+ [self stopTimer];
+
+ if(hasTokenImage) [hasTokenImage release];
+ if(noTokenImage) [noTokenImage release];
+
+ // Unregister for preference change
+ [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kAFSMenuExtraID object:kPrefChangeNotification];
+ [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kAFSMenuExtraID object:kMExtraAFSStateChange];
+ [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kAFSMenuExtraID object:kMExtraAFSMenuChangeState];
+ [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self name:NSWorkspaceDidMountNotification object:nil];
+ [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self name:NSWorkspaceDidUnmountNotification object:nil];
+
+
+ // send notify that menuextra has closed
+ [[NSDistributedNotificationCenter defaultCenter] postNotificationName:kAfsCommanderID object:kPrefChangeNotification];
+
+ return NSTerminateNow;
+}
+// -------------------------------------------------------------------------------
+// -(void) readPreferenceFile
+// -------------------------------------------------------------------------------
+- (void) readPreferenceFile:(NSNotification *)notification
+{
+ NSLog(@"Reading preference file");
+ if(afsSysPath) {
+ [afsSysPath release];
+ afsSysPath = nil;
+ }
+
+ afsSysPath = PREFERENCE_AFS_SYS_PAT_STATIC;
+
+ // read the preference for aklog use
+ useAklogPrefValue = (NSNumber*)CFPreferencesCopyValue((CFStringRef)PREFERENCE_USE_AKLOG,
+ (CFStringRef)kAfsCommanderID,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesAnyHost);
+
+ showStatusMenu = (NSNumber*)CFPreferencesCopyValue((CFStringRef)PREFERENCE_SHOW_STATUS_MENU,
+ (CFStringRef)kAfsCommanderID,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesAnyHost);
+ //set the menu name
+ [self updateAfsStatus:nil];
+}
+
+// -------------------------------------------------------------------------------
+// -(void) readPreferenceFile
+// -------------------------------------------------------------------------------
+- (void)chageMenuVisibility:(NSNotification *)notification {
+ NSLog(@"chageMenuVisibility");
+ [self readPreferenceFile:nil];
+ NSLog(@"showStatusMenu: %d", [showStatusMenu intValue]);
+ [self setStatusItem:[showStatusMenu boolValue]];
+}
+
+// -------------------------------------------------------------------------------
+// - (void)startStopAfs:(id)sender
+// -------------------------------------------------------------------------------
+- (void)startStopAfs:(id)sender
+{
+ NSLog(@"startStopAfs: %s",[afsSysPath UTF8String]);
+ if(!afsSysPath) return;
+
+ OSStatus status = noErr;
+ NSString *afsdPath = [TaskUtil searchExecutablePath:@"afsd"];
+ NSString *rootHelperApp = nil;
+ BOOL currentAfsState = NO;
+
+ @try {
+ if(afsdPath == nil) return;
+ AFSPropertyManager *afsMngr = [[AFSPropertyManager alloc] initWithAfsPath:afsSysPath];
+ currentAfsState = [afsMngr checkAfsStatus];
+ [afsMngr release];
+
+ rootHelperApp = [[NSBundle mainBundle] pathForResource:@"afshlp" ofType:@""];
+
+ //[startStopScript setString: resourcePath];
+ //NSLog(@"LAunch repair HelperTool");
+ //Check helper app
+ [self repairHelperTool];
+
+ // make the parameter to call the root helper app
+ //NSLog(@"Path installazione afs: %s",[afsSysPath UTF8String]);
+ //NSLog(@"Path installazione afsd: %s", [afsdPath UTF8String]);
+ status = [[AuthUtil shared] autorize];
+ if(status == noErr){
+ if(currentAfsState){
+ //shutdown afs
+ //NSLog(@"Shutting down afs");
+ NSMutableString *afsKextPath = [[NSMutableString alloc] initWithCapacity:256];
+ [afsKextPath setString:afsSysPath];
+ [afsKextPath appendString:@"/etc/afs.kext"];
+
+ //NSLog(@"executeTaskWithAuth");
+ const char *stopAfsArgs[] = {"stop_afs", [afsKextPath UTF8String], [afsdPath UTF8String], 0L};
+ [[AuthUtil shared] execUnixCommand:[rootHelperApp UTF8String]
+ args:stopAfsArgs
+ output:nil];
+ } else {
+ //NSLog(@"Starting up afs");
+ const char *startAfsArgs[] = {[[ [NSBundle mainBundle] pathForResource:@"start_afs" ofType:@"sh"] UTF8String], [afsSysPath UTF8String], [afsdPath UTF8String], 0L};
+ [[AuthUtil shared] execUnixCommand:[rootHelperApp UTF8String]
+ args:startAfsArgs
+ output:nil];
+ }
+ }
+ }
+ @catch (NSException * e) {
+ NSLog([e reason]);
+ }
+ @finally {
+ [[AuthUtil shared] deautorize];
+ [self updateAfsStatus:nil];
+ //Send notification to preferencepane
+ [[NSDistributedNotificationCenter defaultCenter] postNotificationName:kAfsCommanderID object:kMenuExtraEventOccured];
+ }
+
+}
+
+// -------------------------------------------------------------------------------
+// -(void) getToken
+// -------------------------------------------------------------------------------
+- (void)getToken:(id)sender
+{
+
+ NSRect globalRect;
+ globalRect.origin = [[[statusItem view] window] convertBaseToScreen:[[statusItem view] frame].origin];
+ globalRect.size = [[statusItem view] frame].size;
+ AFSPropertyManager *afsPropMngr = [[AFSPropertyManager alloc] initWithAfsPath:afsSysPath ];
+ [afsPropMngr loadConfiguration];
+
+
+ if([useAklogPrefValue intValue]==NSOnState ) {
+ NSLog(@"Use Aklog");
+ [afsPropMngr getTokens:false
+ usr:nil
+ pwd:nil];
+ [self klogUserEven:nil];
+ } else {
+ NSLog(@"Use Klog");
+ // register for user event
+ [[NSDistributedNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(klogUserEven:)
+ name:kAFSMenuExtraID
+ object:kLogWindowClosed];
+
+ credentialMenuController = [[AFSMenuCredentialContoller alloc] initWhitRec:globalRect
+ afsPropManager:afsPropMngr];
+ [credentialMenuController showWindow];
+ }
+
+ //Dispose afs manager
+ [afsPropMngr release];
+}
+
+// -------------------------------------------------------------------------------
+// -(void) releaseToken
+// -------------------------------------------------------------------------------
+- (void)releaseToken:(id)sender
+{
+ AFSPropertyManager *afsMngr = [[AFSPropertyManager alloc] initWithAfsPath:afsSysPath];
+ [afsMngr unlog:nil];
+ [afsMngr release];
+ [self updateAfsStatus:nil];
+}
+
+
+// -------------------------------------------------------------------------------
+// -(void) afsVolumeMountChange - Track for mount unmount afs volume
+// -------------------------------------------------------------------------------
+- (void) afsVolumeMountChange:(NSNotification *)notification{
+ [self updateAfsStatus:nil];
+}
+
+// -------------------------------------------------------------------------------
+// -(void) updateAfsStatus
+// -------------------------------------------------------------------------------
+- (void)updateAfsStatus:(NSTimer*)timer
+{
+ //Try to locking
+ if(![tokensLock tryLock]) return;
+
+ // check the afs state in esclusive mode
+ AFSPropertyManager *afsMngr = [[AFSPropertyManager alloc] initWithAfsPath:afsSysPath];
+ afsState = [afsMngr checkAfsStatus];
+
+ NSArray *tokens = [afsMngr getTokenList];
+ [afsMngr release];
+ gotToken = [tokens count] > 0;
+ [tokens release];
+ [self updateMenu];
+
+ //unlock
+ [tokensLock unlock];
+}
+
+// -------------------------------------------------------------------------------
+// -(void) klogUserEven
+// -------------------------------------------------------------------------------
+-(void) klogUserEven:(NSNotification *)notification
+{
+ if(credentialMenuController) {
+ [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kAFSMenuExtraID object:kLogWindowClosed];
+ [credentialMenuController closeWindow];
+ [credentialMenuController release];
+ credentialMenuController = nil;
+ }
+ //Send notification to PreferencePane
+ [[NSDistributedNotificationCenter defaultCenter] postNotificationName:kAfsCommanderID object:kMenuExtraEventOccured];
+
+ [self updateAfsStatus:nil];
+}
+#pragma mark Operational Function
+// -------------------------------------------------------------------------------
+// startTimer:
+// -------------------------------------------------------------------------------
+- (void)startTimer{
+ //start the time for check tokens validity
+ if(timerForCheckTokensList) return;
+ timerForCheckTokensList = [NSTimer scheduledTimerWithTimeInterval:TOKENS_REFRESH_TIME_IN_SEC
+ target:self
+ selector:@selector(updateAfsStatus:)
+ userInfo:nil
+ repeats:YES];
+ [timerForCheckTokensList fire];
+}
+
+// -------------------------------------------------------------------------------
+// stopTimer:
+// -------------------------------------------------------------------------------
+- (void)stopTimer{
+ if(!timerForCheckTokensList) return;
+ [timerForCheckTokensList invalidate];
+ timerForCheckTokensList = nil;
+}
+// -------------------------------------------------------------------------------
+// -(void) getImageFromBundle
+// -------------------------------------------------------------------------------
+- (NSImage*)getImageFromBundle:(NSString*)fileName fileExt:(NSString*)ext
+{
+ return [[NSImage alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:fileName
+ ofType:ext]];
+}
+
+
+
+
+// -------------------------------------------------------------------------------
+// -(void) updateMenu
+// -------------------------------------------------------------------------------
+- (void)updateMenu{
+ [getReleaseTokenMenuItem setEnabled:afsState];
+ [startStopMenuItem setTitle:afsState?kAfsButtonShutdown:kAfsButtonStartup];
+ [[statusItem view] setNeedsDisplay:YES];
+
+}
+
+
+// -------------------------------------------------------------------------------
+// -(void) useAklogPrefValue
+// -------------------------------------------------------------------------------
+- (BOOL)useAklogPrefValue
+{
+ if(useAklogPrefValue) return [useAklogPrefValue intValue] == NSOnState;
+ else return NSOffState;
+}
+
+// -------------------------------------------------------------------------------
+// repairHelperTool:
+// -------------------------------------------------------------------------------
+- (void) repairHelperTool
+{
+ struct stat st;
+ int fdTool;
+ int status = 0;
+ NSLog(@"repairHelperTool");
+ NSString *afshlpPath = [[NSBundle mainBundle] pathForResource:@"afshlp" ofType:nil];
+
+
+
+ // Open tool exclusively, so nobody can change it while we bless it.
+ fdTool = open([afshlpPath UTF8String], O_NONBLOCK | O_RDONLY | O_EXLOCK, 0);
+
+ if(fdTool == -1)
+ {
+ NSLog(@"Exclusive open while repairing tool failed: %d.", errno);
+ exit(-1);
+ }
+
+ if(fstat(fdTool, &st))
+ {
+ NSLog(@"fstat failed.");
+ exit(-1);
+ }
+
+ if(st.st_uid != 0)
+ {
+ status = [[AuthUtil shared] autorize];
+ if(status == noErr){
+ fchown(fdTool, 0, st.st_gid);
+
+ // Disable group and world writability and make setuid root.
+ fchmod(fdTool, (st.st_mode & (~(S_IWGRP | S_IWOTH)))/* | S_ISUID*/);
+ const char *args[] = {"root", [afshlpPath UTF8String],0L};
+ [[AuthUtil shared] execUnixCommand:"/usr/sbin/chown"
+ args:args
+ output:nil];
+ [[AuthUtil shared] deautorize];
+ }
+ } else NSLog(@"st_uid = 0");
+
+
+
+ close(fdTool);
+
+ NSLog(@"Self-repair done.");
+
+}
+
+#pragma mark accessor
+// -------------------------------------------------------------------------------
+// statusItem
+// -------------------------------------------------------------------------------
+-(NSStatusItem*)statusItem {
+ return statusItem;
+}
+
+// -------------------------------------------------------------------------------
+// setStatusItem
+// -------------------------------------------------------------------------------
+-(void)setStatusItem:(BOOL)show {
+ if(show) {
+ if(statusItem) return;
+ statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
+ [statusItem setView:[[AFSMenuExtraView alloc] initWithFrame:[[statusItem view] frame]
+ backgrounder:self
+ menu:backgrounderMenu]];
+ //Tells the NSStatusItem what menu to load
+ [statusItem setMenu:backgrounderMenu];
+ //Sets the tooptip for our item
+ [statusItem setToolTip:@"OpenAFS Preference"];
+ //Enables highlighting
+ [statusItem setHighlightMode:YES];
+ [statusItem setImage:noTokenImage];
+ } else {
+ if(!statusItem) return;
+ [statusItem release];
+ statusItem = nil;
+ }
+}
+// -------------------------------------------------------------------------------
+// -(void) imageToRender
+// -------------------------------------------------------------------------------
+- (NSImage*)imageToRender
+{
+ if(gotToken){
+ return hasTokenImage;
+ } else {
+ return noTokenImage;
+ }
+}
+
+
+-(IBAction) startStopEvent:(id)sender {
+ [self startStopAfs:sender];
+}
+
+-(IBAction) getReleaseTokenEvent:(id)sender {
+ [self getToken:sender];
}
@end