/* * Copyright (C) 2013 Martin Willi * Copyright (C) 2013 revosec AG * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See . * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #import "AppDelegate.h" #import "Control.h" #import "LogController.h" #import "ConnController.h" #import "PasswordController.h" @implementation AppDelegate { NSStatusItem *statusItem; NSImage *active; NSImage *inactive; NSInteger nonConnectionItemCount; NSMutableArray *connections; Control *control; ConnController *editor; PasswordController *password; } - (void)change:(connectionState)state withConnection:(NSDictionary*)conn { NSInteger idx; NSMenuItem *item; idx = [statusMenu indexOfItemWithRepresentedObject:conn]; if (idx != -1) { item = [statusMenu itemAtIndex:idx]; switch (state) { case STATE_DOWN: [item setState:NSOffState]; [item setAction:@selector(doConnection:)]; [[[item submenu] itemAtIndex:0] setAction:@selector(doConnection:)]; [[[item submenu] itemAtIndex:0] setTitle:@"Connect"]; [[[item submenu] itemAtIndex:1] setAction:@selector(editConnection:)]; [[[item submenu] itemAtIndex:2] setAction:@selector(removeConnection:)]; [self updateIcon]; break; case STATE_WORKING: [item setState:NSMixedState]; [item setAction:@selector(undoConnection:)]; [[[item submenu] itemAtIndex:0] setAction:@selector(undoConnection:)]; [[[item submenu] itemAtIndex:0] setTitle:@"Disconnect"]; [[[item submenu] itemAtIndex:1] setAction:nil]; [[[item submenu] itemAtIndex:2] setAction:nil]; [self updateIcon]; break; case STATE_UP: [item setState:NSOnState]; [self updateIcon]; break; } } } - (NSString*)createPasswordWithConnection:(NSDictionary*)conn { return [password query]; } - (void)raise:(NSString*)alert withConnection:(NSDictionary*)conn { NSAlert *popup; NSString *text; text = [[NSString alloc] initWithFormat:@"Establishing connection %@ failed:", [conn objectForKey:@"name"]]; popup = [[NSAlert alloc] init]; [popup setMessageText:text]; [popup setInformativeText:alert]; [popup runModal]; [text release]; [popup release]; } - (void)log:(NSString*)line withConnection:(NSDictionary*)conn { [[self findLog:conn] appendLine:line]; } - (IBAction)undoConnection:(id)sender { NSDictionary *conn; conn = [sender representedObject]; [control disconnect:conn]; } - (IBAction)doConnection:(id)sender { NSDictionary *conn; conn = [sender representedObject]; [[self findLog:conn] clear]; [control connect:conn]; } - (IBAction)addConnection:(id)sender { NSMutableDictionary *conn; conn = [editor createConnection]; if (conn) { [connections insertObject:conn atIndex:[connections count]]; [self saveConnections]; } } - (IBAction)editConnection:(id)sender { NSMutableDictionary *conn; conn = [sender representedObject]; if ([editor editConnection:conn]) { [self saveConnections]; } } - (IBAction)removeConnection:(id)sender { NSDictionary *conn; conn = [sender representedObject]; [connections removeObject:conn]; [self saveConnections]; } - (void)loadConnections { NSUserDefaults *defaults; NSArray *array; defaults = [NSUserDefaults standardUserDefaults]; array = [defaults arrayForKey:@"connections"]; if (array) { [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { if ([obj isKindOfClass:[NSDictionary class]]) { NSMutableDictionary *dict; dict = [obj mutableCopy]; [connections insertObject:dict atIndex:[connections count]]; [dict release]; } }]; } [defaults addObserver:self forKeyPath:@"connections" options:NSKeyValueObservingOptionNew context:NULL]; } - (void)saveConnections { NSUserDefaults *defaults; defaults = [NSUserDefaults standardUserDefaults]; [defaults setObject:connections forKey:@"connections"]; [defaults synchronize]; } - (void)viewLog:(id)sender { [[sender representedObject] show]; } - (LogController*)findLog:(NSDictionary *)connection { NSInteger idx; NSMenuItem *item; idx = [statusMenu indexOfItemWithRepresentedObject:connection]; if (idx != -1) { item = [statusMenu itemAtIndex:idx]; item = [[item submenu] itemAtIndex:3]; return [item representedObject]; } return nil; } - (void)addMenuItem:(NSDictionary *)connection { NSString *name, *title; NSMenuItem *item; NSMenu *submenu; LogController *ctl; name = [connection objectForKey:@"name"]; if (name) { /* create submenu first */ submenu = [[NSMenu alloc] initWithTitle:@"submenu"]; item = [[NSMenuItem alloc] initWithTitle:@"Connect" action:@selector(doConnection:) keyEquivalent:@""]; [item setTarget:self]; [item setRepresentedObject:connection]; [submenu insertItem:item atIndex:0]; [item release]; item = [[NSMenuItem alloc] initWithTitle:@"Edit..." action:@selector(editConnection:) keyEquivalent:@""]; [item setTarget:self]; [item setRepresentedObject:connection]; [submenu insertItem:item atIndex:1]; [item release]; item = [[NSMenuItem alloc] initWithTitle:@"Remove" action:@selector(removeConnection:) keyEquivalent:@""]; [item setTarget:self]; [item setRepresentedObject:connection]; [submenu insertItem:item atIndex:2]; [item release]; item = [[NSMenuItem alloc] initWithTitle:@"View Log..." action:@selector(viewLog:) keyEquivalent:@""]; [item setTarget:self]; ctl = [[LogController alloc] initWithWindowNibName:@"LogWindow"]; title = [NSString stringWithFormat: @"strongSwan Log: %@", name]; [[ctl window] setTitle:title]; [item setRepresentedObject:ctl]; [ctl release]; [submenu insertItem:item atIndex:3]; [item release]; item = [[NSMenuItem alloc] initWithTitle:name action:@selector(doConnection:) keyEquivalent:@""]; [item setTarget:self]; [item setRepresentedObject:connection]; [item setSubmenu:submenu]; [submenu release]; [statusMenu insertItem:item atIndex: [statusMenu numberOfItems] - nonConnectionItemCount]; [item release]; } } - (void)repopulateMenu { while ([statusMenu numberOfItems] > nonConnectionItemCount) { [statusMenu removeItemAtIndex:0]; } [connections enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) { if ([obj isKindOfClass:[NSDictionary class]]) { [self addMenuItem:obj]; } }]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { [self repopulateMenu]; } - (void)updateIcon { NSMenuItem *item; bool anyactive = FALSE; int i; for (i = 0; i < [statusMenu numberOfItems] - nonConnectionItemCount; i++) { item = [statusMenu itemAtIndex:i]; if ([item state] == NSOnState) { anyactive = TRUE; break; } } [statusItem setImage: anyactive ? active : inactive]; } - (void)initializeMenu { NSImage *icon; NSString *path; statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength] retain]; [statusItem setMenu:statusMenu]; [statusItem setHighlightMode:YES]; path = [[NSBundle mainBundle] pathForResource:@"icon" ofType:@"png"]; icon = [[NSImage alloc] initWithContentsOfFile:path]; [statusItem setImage:icon]; inactive = icon; path = [[NSBundle mainBundle] pathForResource:@"icon-active" ofType:@"png"]; icon = [[NSImage alloc] initWithContentsOfFile:path]; active = icon; path = [[NSBundle mainBundle] pathForResource:@"icon-alt" ofType:@"png"]; icon = [[NSImage alloc] initWithContentsOfFile:path]; [statusItem setAlternateImage:icon]; [icon release]; nonConnectionItemCount = [statusMenu numberOfItems]; [self repopulateMenu]; } - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { [self loadConnections]; [self initializeMenu]; } - (id)init { self = [super init]; control = [[Control alloc] initWithDelegate:self]; connections = [[NSMutableArray alloc] init]; editor = [[ConnController alloc] initWithWindowNibName:@"ConnWindow"]; password = [[PasswordController alloc] initWithWindowNibName:@"PasswordWindow"]; return self; } - (void)dealloc { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults removeObserver:self forKeyPath:@"connections"]; [statusItem release]; [active release]; [inactive release]; [connections release]; [control release]; [editor release]; [password release]; [super dealloc]; } @end