From 197c40908a84128cc16ea70c341633c6fa0a67df Mon Sep 17 00:00:00 2001 From: Patrick Wardle Date: Tue, 18 Aug 2015 21:59:25 -1000 Subject: [PATCH] global search window logic (work in progress!) --- AppDelegate.h | 4 + AppDelegate.m | 59 +- Filter.m | 1 - FlaggedItems.h | 2 +- FlaggedItems.m | 14 +- ItemView.h | 3 + ItemView.m | 159 +++++- SearchWindowController.h | 64 +++ SearchWindowController.m | 520 ++++++++++++++++++ TaskExplorer.xcodeproj/project.pbxproj | 28 + .../xcshareddata/TaskExplorer.xccheckout | 4 +- TaskTableController.h | 2 +- UI/FlaggedItems.xib | 6 +- UI/SearchWindow.xib | 449 +++++++++++++++ en.lproj/MainMenu.xib | 6 +- 15 files changed, 1282 insertions(+), 39 deletions(-) create mode 100644 SearchWindowController.h create mode 100644 SearchWindowController.m create mode 100644 UI/SearchWindow.xib diff --git a/AppDelegate.h b/AppDelegate.h index c43d7b5..9583022 100755 --- a/AppDelegate.h +++ b/AppDelegate.h @@ -18,6 +18,7 @@ #import "FlaggedItems.h" #import "ResultsWindowController.h" #import "RequestRootWindowController.h" +#import "SearchWindowController.h" #import "Task.h" @@ -108,6 +109,9 @@ //about window controller @property(nonatomic, retain)AboutWindowController* aboutWindowController; +//search window controller +@property(nonatomic, retain)SearchWindowController* searchWindowController; + //results window controller @property(nonatomic, retain)ResultsWindowController* resultsWindowController; diff --git a/AppDelegate.m b/AppDelegate.m index d34887a..55f802b 100755 --- a/AppDelegate.m +++ b/AppDelegate.m @@ -32,6 +32,11 @@ //TODO: show 'from where' via quarantine attrz //TODO: show user (after pid): -> (pid, user)? //TODO: when filtering, and then refresh, doesn't go to row #0 :/ +//TODO: check if VT can be reached! if not, error? or don't show '0 VT results detected' etc... + +//TODO: JavaW (iWorm) dylibs... +//TODO: remove task, remove from taskEnum's global list for executables, and dylibs, etc +//TODO: also refresh!.... @implementation AppDelegate @@ -51,6 +56,7 @@ @synthesize requestRootWindowController; @synthesize taskViewFormat; @synthesize flagItemsWindowController; +@synthesize searchWindowController; @synthesize scannerThread; @synthesize progressIndicator; @@ -63,11 +69,6 @@ @synthesize flaggedItems; -//@synthesize taskScrollView; -//TODO: check if VT can be reached! if not, error? or don't show '0 VT results detected' etc... - -//TODO: JavaW (iWorm) dylibs... - //center window // ->also make front -(void)awakeFromNib @@ -88,9 +89,10 @@ // ->main entry point -(void)applicationDidFinishLaunching:(NSNotification *)notification { + //TODO: re-enable //first thing... // ->install exception handlers! - installExceptionHandlers(); + //installExceptionHandlers(); //init virus total object virusTotalObj = [[VirusTotal alloc] init]; @@ -326,8 +328,9 @@ bail: // ->waits until window is non-nil dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + //TODO: re-enable //make modal - makeModal(self.requestRootWindowController); + //makeModal(self.requestRootWindowController); }); @@ -1146,17 +1149,31 @@ bail: //automatically invoked when user clicks 'search' button // ->perform global search -//TODO: implement (in next version) -- (IBAction)search:(id)sender +-(IBAction)search:(id)sender { - //'unimplemented' msg - NSAlert* errorPopup = nil; + //alloc/init flagged items window + if(nil == self.searchWindowController) + { + //alloc/init + searchWindowController = [[SearchWindowController alloc] initWithWindowNibName:@"SearchWindow"]; + } - //init popup w/ msg - errorPopup = [NSAlert alertWithMessageText:@"sorry, 'global search' not yet implemented" defaultButton:@"Ok" alternateButton:nil otherButton:nil informativeTextWithFormat:@"...should be in next version :)"]; + //init/prep it + [self.searchWindowController prepare]; - //and show it - [errorPopup runModal]; + //show it + [self.searchWindowController showWindow:self]; + + /* + //invoke function in background that will make window modal + // ->waits until window is non-nil + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + //make modal + //makeModal(self.searchWindowController); + + }); + */ return; } @@ -1735,7 +1752,7 @@ bail: //show flagged items else { - //alloc/init settings window + //alloc/init flagged items window if(nil == self.flagItemsWindowController) { //alloc/init @@ -1745,20 +1762,18 @@ bail: //show it [self.flagItemsWindowController showWindow:self]; + /* //invoke function in background that will make window modal // ->waits until window is non-nil dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //make modal - makeModal(self.prefsWindowController); + makeModal(self.flagItemsWindowController); }); - - + */ } - - //NSLog(@"would show flagged items"); - + return; } diff --git a/Filter.m b/Filter.m index 8d9792d..0972b0c 100644 --- a/Filter.m +++ b/Filter.m @@ -116,7 +116,6 @@ NSString * const KEYWORDS[] = {@"#apple", @"#nonapple", @"#signed", @"#unsigned" } - //filter dylibs and files // ->name and path -(void)filterFiles:(NSString*)filterText items:(NSMutableArray*)items results:(NSMutableArray*)results diff --git a/FlaggedItems.h b/FlaggedItems.h index 09e0edb..12d93dc 100644 --- a/FlaggedItems.h +++ b/FlaggedItems.h @@ -3,7 +3,7 @@ // TaskExplorer // // Created by Patrick Wardle on 8/14/15. -// Copyright (c) 2015 Lucas Derraugh. All rights reserved. +// Copyright (c) 2015 Objective-See. All rights reserved. // #import diff --git a/FlaggedItems.m b/FlaggedItems.m index 82783a1..427b605 100644 --- a/FlaggedItems.m +++ b/FlaggedItems.m @@ -3,7 +3,7 @@ // TaskExplorer // // Created by Patrick Wardle on 8/14/15. -// Copyright (c) 2015 Lucas Derraugh. All rights reserved. +// Copyright (c) 2015 Objective-See. All rights reserved. // #import "AppDelegate.h" @@ -11,6 +11,7 @@ #import "ItemView.h" #import "KKRow.h" +//TODO: mouse over for info/show in finder buttons! @interface FlaggedItems () @@ -50,6 +51,17 @@ [self.flaggedItemTable reloadData]; } +//TODO: don't need +//automatically invoked when window is closing +// ->make ourselves unmodal +-(void)windowWillClose:(NSNotification *)notification +{ + //make un-modal + //[[NSApplication sharedApplication] stopModal]; + + return; +} + //table delegate // ->return number of rows, which is just number of items in the currently selected plugin -(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView diff --git a/ItemView.h b/ItemView.h index e3c799d..429571b 100644 --- a/ItemView.h +++ b/ItemView.h @@ -22,6 +22,9 @@ NSTableCellView* createItemView(NSTableView* tableView, id owner, id item); //create & customize flagged item view NSTableCellView* createFlaggedItemView(NSTableView* tableView, id owner, id item); +//create & customize global dylib/file view +NSTableCellView* createLoadedItemView(NSTableView* tableView, id owner, id item); + //create & customize task view NSTableCellView* createTaskView(NSTableView* tableView, id owner, id item); diff --git a/ItemView.m b/ItemView.m index 01d2d6c..7cf0c2b 100644 --- a/ItemView.m +++ b/ItemView.m @@ -9,10 +9,12 @@ #import "Consts.h" #import "ItemView.h" #import "VTButton.h" -#import "AppDelegate.h" #import "kkRowCell.h" +#import "AppDelegate.h" +#import "SearchWindowController.h" #import "3rdParty/OrderedDictionary.h" + //create customize item view NSTableCellView* createItemView(NSTableView* tableView, id owner, id item) { @@ -25,12 +27,22 @@ NSTableCellView* createItemView(NSTableView* tableView, id owner, id item) //bail goto bail; } - - //first handle logic for flagged items - if(YES == [owner isKindOfClass:[FlaggedItems class]]) + //handle logic for flagged items + // ->but only dylibs, to get special global 'loaded in' views + if( (YES == [owner isKindOfClass:[FlaggedItems class]]) && + (YES == [item isKindOfClass:[Binary class]]) ) { //create & config view - itemCell = createFlaggedItemView(tableView, owner, item); + itemCell = createLoadedItemView(tableView, owner, item); + } + + //handle logic for search results + // ->dylibs and files have the special global 'loaded in' views + else if( (YES == [owner isKindOfClass:[SearchWindowController class]]) && + ( (YES == [item isKindOfClass:[Binary class]]) || (YES == [item isKindOfClass:[File class]]) ) ) + { + //create & config view + itemCell = createLoadedItemView(tableView, owner, item); } //logic to create task view @@ -135,6 +147,143 @@ NSImage* getCodeSigningIcon(Binary* binary) return codeSignIcon; } +//create & customize global dylib/file view +NSTableCellView* createLoadedItemView(NSTableView* tableView, id owner, id item) +{ + //item cell + NSTableCellView* loadedItemCell = nil; + + //matching or host tasks + NSMutableArray* tasks = nil; + + //pid or 'loaded in' string + NSMutableString* loadedIn = nil; + + //task's name frame + CGRect nameFrame = {0}; + + //get host tasks + // TODO: make this work for files too! + tasks = [((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator loadedIn:item]; + + //start 'loaded in: ...' str + loadedIn = [NSMutableString stringWithFormat:@"(loaded in:"]; + + //add all tasks + for(Task* task in tasks) + { + //append name + [loadedIn appendFormat:@" %@,", task.binary.name]; + } + + //remove last ',' + if(YES == [loadedIn hasSuffix:@","]) + { + //remove + [loadedIn deleteCharactersInRange:NSMakeRange([loadedIn length]-1, 1)]; + } + + //terminate list/output + [loadedIn appendString:@")"]; + + //dylibs + // ->create cell + if(YES == [item isKindOfClass:[Binary class]]) + { + //create + loadedItemCell = [tableView makeViewWithIdentifier:@"TaskCell" owner:owner]; + } + //files + // ->create cell + else if(YES == [item isKindOfClass:[File class]]) + { + //create + loadedItemCell = [tableView makeViewWithIdentifier:@"FileCell" owner:owner]; + } + + //sanity check + if(nil == loadedItemCell) + { + //bail + goto bail; + } + + //brand new cells need tracking areas + // ->determine if new, by checking default (.xib/IB) value + if( (YES == [loadedItemCell.textField.stringValue isEqualToString:@"Task Name"]) || + (YES == [loadedItemCell.textField.stringValue isEqualToString:@"File Name"]) ) + { + //only dylibs have VT button + if(YES == [item isKindOfClass:[Binary class]]) + { + //add tracking area + // ->'vt' button + addTrackingArea(loadedItemCell, TABLE_ROW_VT_BUTTON, owner); + } + + //add tracking area + // ->'info' button + addTrackingArea(loadedItemCell, TABLE_ROW_INFO_BUTTON, owner); + + //add tracking area + // ->'show' button + addTrackingArea(loadedItemCell, TABLE_ROW_SHOW_BUTTON, owner); + } + + //set icon + //TODO: make sure files have icons!! + loadedItemCell.imageView.image = [item icon]; + + //only dylibs have code signing icons + if(YES == [item isKindOfClass:[Binary class]]) + { + //set code signing icon + ((NSImageView*)[loadedItemCell viewWithTag:TABLE_ROW_SIGNATURE_ICON]).image = getCodeSigningIcon(item); + } + + //default + // ->(re)set main textfield's color to black + loadedItemCell.textField.textColor = [NSColor blackColor]; + + //set main text + // ->name + [loadedItemCell.textField setStringValue:[item name]]; + + //get name frame + nameFrame = loadedItemCell.textField.frame; + + //adjust width to fit text + nameFrame.size.width = [loadedItemCell.textField.stringValue sizeWithAttributes: @{NSFontAttributeName: loadedItemCell.textField.font}].width + 5; + + //disable autolayout for name + loadedItemCell.textField.translatesAutoresizingMaskIntoConstraints = YES; + + //update name frame + // ->should now be exact size of text + loadedItemCell.textField.frame = nameFrame; + + //set pid + // ->immediately follows name + [((NSTextField*)[loadedItemCell viewWithTag:TABLE_ROW_PID_LABEL]) setStringValue:loadedIn]; + + //set path + [[loadedItemCell viewWithTag:TABLE_ROW_SUB_TEXT_TAG] setStringValue:[item path]]; + + //only dylibs have VT button + if(YES == [item isKindOfClass:[Binary class]]) + { + //config VT button + configVTButton(loadedItemCell, owner, item); + } + +//bail +bail: + + return loadedItemCell; +} + + +//TODO: for search, each task is unique, so same for flagged tasks? YES, get args etc :) //create & customize flagged item view NSTableCellView* createFlaggedItemView(NSTableView* tableView, id owner, Binary* binary) { diff --git a/SearchWindowController.h b/SearchWindowController.h new file mode 100644 index 0000000..746e25f --- /dev/null +++ b/SearchWindowController.h @@ -0,0 +1,64 @@ +// +// FlaggedItems.h +// TaskExplorer +// +// Created by Patrick Wardle on 8/14/15. +// Copyright (c) 2015 Objective-See. All rights reserved. +// + +#import + +#import "InfoWindowController.h" +#import "VTInfoWindowController.h" + + +@interface SearchWindowController : NSWindowController + +//automatically invoked when user presses 'Enter' in search box +// ->search! +-(IBAction)search:(id)sender; + +//PROPERTIES + +//flag for first time init's +@property BOOL didInit; + +//search box +@property (weak) IBOutlet NSTextField *searchBox; + +//table +@property (weak) IBOutlet NSTableView *searchTable; + +//table items +@property(nonatomic, retain)NSMutableArray* searchResults; + +//filter object +@property(nonatomic, retain)Filter* filterObj; + +//vt window controller +@property (nonatomic, retain)VTInfoWindowController* vtWindowController; + +//info window controller +@property(retain, nonatomic)InfoWindowController* infoWindowController; + + +//tasks +@property(nonatomic, retain)NSMutableDictionary* tasks; + +//dylibs +@property(nonatomic, retain)NSMutableDictionary* dylibs; + +//files +@property(nonatomic, retain)NSMutableDictionary* files; + +//connections +@property(nonatomic, retain)NSMutableDictionary* connections; + +/* METHODS */ + +//init/prepare +// ->make sure everything is cleanly init'd +-(void)prepare; + + +@end diff --git a/SearchWindowController.m b/SearchWindowController.m new file mode 100644 index 0000000..7fab5c8 --- /dev/null +++ b/SearchWindowController.m @@ -0,0 +1,520 @@ +// +// SearchWindowController.m +// TaskExplorer +// +// Created by Patrick Wardle on 8/14/15. +// Copyright (c) 2015 Objective-See. All rights reserved. +// + + +//TODO: mouse over for info/show in finder buttons! + + +#import "AppDelegate.h" +#import "SearchWindowController.h" +#import "ItemView.h" +#import "KKRow.h" +#import "Filter.h" +#import "SearchResult.h" + + +@implementation SearchWindowController + +@synthesize tasks; +@synthesize dylibs; +@synthesize files; +@synthesize connections; +@synthesize didInit; +@synthesize searchTable; +@synthesize filterObj; +@synthesize searchResults; +@synthesize searchBox; +@synthesize vtWindowController; +@synthesize infoWindowController; + +//automatically called when nib is loaded +// ->center window +-(void)awakeFromNib +{ + //single time init + if(YES != self.didInit) + { + //center + [self.window center]; + + //set flag + self.didInit = YES; + } + + return; +} + +/* +//automatically invoked when window is loaded +// ->set to white +-(void)windowDidLoad +{ + //super + //[super windowDidLoad]; + + + //TODO: reset searchResults when user clears search box~! + + + //init search data + // ->loads all current tasks, dylibs, files, network conns + //[self initSearchData]; + + //TODO: disable search box till done generating search dicts? + + return; +} +*/ + +//automatically invoked when window is closing +// ->make ourselves unmodal +-(void)windowWillClose:(NSNotification *)notification +{ + //make un-modal + //[[NSApplication sharedApplication] stopModal]; + + return; +} + +//init/prepare +// ->make sure everything is cleanly init'd +-(void)prepare +{ + //init filter obj + filterObj = [[Filter alloc] init]; + + //init array for search results + searchResults = [NSMutableArray array]; + + //table reload + // ->make sure all is reset + [self.searchTable reloadData]; + + //reset search string + [self.searchBox setStringValue:@""]; + + return; +} + + +/* + +//init search data +// ->load all tasks/dylibs/files/connections into dictionaries for easy/quick searching +-(void)initSearchData:(NSString*)searchString +{ + //alloc task dictionary + tasks = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.tasks; + + //alloc dylibs dictionary + dylibs = [NSMutableDictionary dictionary]; + + //alloc files dictionary + files = [NSMutableDictionary dictionary]; + + //alloc connections dictionary + connections = [NSMutableDictionary dictionary]; + + + /* + //'#' indicates a keyword search + // ->check for keyword match, then filter by keyword + if(YES == [search.string hasPrefix:@"#"]) + { + //ignore #search strings that don't match a keyword + if(YES != [filterObj isKeyword:search.string]) + { + //ignore + goto bail; + } + } + + //filter + [self.filterObj filterTasks:search.string items:self.taskEnumerator.tasks results:self.taskTableController.filteredItems]; + */ + + //process each + // ->add files, tasks, network connections +/* + for(NSNumber* taskPid in tasks) + { + //extract task + task = tasks[taskPid]; + + // + + } + */ + /* + + return; +} +*/ +/* +-(void)search:(NSString*)searchString +{ + //filter object + Filter* filterObj = nil; + + //task + Task* task = nil; + + //init filter obj + filterObj = [[Filter alloc] init]; + + + return; +} +*/ + + +//table delegate +// ->return number of rows +-(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView +{ + //count + return self.searchResults.count; +} + +//table delegate method +// ->return cell for row +-(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +{ + //row view + NSView* rowView = nil; + + //sanity check + // ->make sure there is table item for row + if(row >= self.searchResults.count) + { + //bail + goto bail; + } + + //create the view + // ->inits row w/ all required info + rowView = createItemView(tableView, self, [self.searchResults objectAtIndex:row]); + +//bail +bail: + + return rowView; +} + +//automatically invoked +// ->create custom (sub-classed) NSTableRowView +-(NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row +{ + //row view + KKRow* rowView = nil; + + //row ID + static NSString* const kRowIdentifier = @"TableRowView"; + + //try grab existing row view + rowView = [tableView makeViewWithIdentifier:kRowIdentifier owner:self]; + + //make new if needed + if(nil == rowView) + { + //create new + // ->size doesn't matter + rowView = [[KKRow alloc] initWithFrame:NSZeroRect]; + + //set row ID + rowView.identifier = kRowIdentifier; + } + + return rowView; +} + +//automatically invoked when user presses 'Enter' in search box +// ->search! +- (IBAction)search:(id)sender +{ + //search string + NSString* searchString = nil; + + //all tasks + OrderedDictionary* allTasks = nil; + + //matching items + NSMutableArray* matchingItems = nil; + + //matching tasks + NSMutableArray* matchingTasks = nil; + + //matching dylibs + NSMutableDictionary* matchingDylibs = nil; + + //task + Task* task = nil; + + //search result + //SearchResult* searchResult = nil; + + //alloc array for matching items + matchingItems = [NSMutableArray array]; + + //alloc array for matching tasks + matchingTasks = [NSMutableArray array]; + + //alloc dictionary for matching dylibs + matchingDylibs = [NSMutableDictionary dictionary]; + + //reset search results + [self.searchResults removeAllObjects]; + + //grab search string + searchString = [sender stringValue]; + + //grab all tasks + allTasks = ((AppDelegate*)[[NSApplication sharedApplication] delegate]).taskEnumerator.tasks; + + //'#' indicates a keyword search + // ->check for keyword match, then filter by keyword + if(YES == [searchString hasPrefix:@"#"]) + { + //ignore #search strings that don't match a keyword + if(YES != [filterObj isKeyword:searchString]) + { + //ignore + goto bail; + } + } + + //first; search for all matching tasks + [self.filterObj filterTasks:searchString items:allTasks results:matchingTasks]; + + //TODO: don't need for loop for this? + //convert/save into search result objects + for(Task* task in matchingTasks) + { + //init + //searchResult = [[SearchResult alloc] initWithItem:task]; + + //add to table items + [self.searchResults addObject:task]; + } + + //refresh table to display task matches + [self.searchTable reloadData]; + + //second; search for all matching dylibs + //sync + @synchronized(allTasks) + { + + //walk all tasks + // ->scan each for dylib matches, only processing first match + for(NSNumber* taskPid in allTasks) + { + //extract task + task = allTasks[taskPid]; + + //filter + [self.filterObj filterFiles:searchString items:task.dylibs results:matchingItems]; + + //process all matching dylibs + // ->but first check if processed due to matching in another task already + for(Binary* dylib in matchingItems) + { + //ignore if already seen/processed + if(nil != matchingDylibs[dylib.path]) + { + //skip + continue; + } + + //process + [self.searchResults addObject:dylib]; + + //save + matchingDylibs[dylib.path] = dylib; + } + + }//all tasks + + }//sync + + //refresh table to display dylib + [self.searchTable reloadData]; + +//bail +bail: + + return; + +} + +//invoked when the user clicks 'virus total' icon +// ->launch browser and browse to virus total's page +-(void)showVTInfo:(id)sender +{ + //item + // ->task or dylib + id item = nil; + + //binary + Binary* binary = nil; + + //row + NSInteger itemRow = 0; + + //grab sender's row + itemRow = [self.searchTable rowForView:sender]; + + //sanity check(s) + // ->make sure row is decent + if( (-1 == itemRow) || + (itemRow >= self.searchResults.count) ) + { + //bail + goto bail; + } + + //extract item for row + item = self.searchResults[itemRow]; + + //tasks + // ->grab binary + if(YES == [item isKindOfClass:[Task class]]) + { + //get binary + binary = ((Task*)item).binary; + } + //binaries + // ->can use as is + else if(YES == [item isKindOfClass:[Binary class]]) + { + //set + binary = item; + } + + //sanity check + if(nil == binary) + { + //bail + goto bail; + } + + //alloc/init info window + vtWindowController = [[VTInfoWindowController alloc] initWithItem:binary]; + + //show it + [self.vtWindowController.windowController showWindow:self]; + + +//bail +bail: + + return; +} + +//automatically invoked when user clicks the 'show in finder' icon +// ->open Finder to show item +-(IBAction)showInFinder:(id)sender +{ + //item + // ->task, dylib, or file + id item = nil; + + //path to item + NSString* path = nil; + + //row + NSInteger itemRow = 0; + + //grab sender's row + itemRow = [self.searchTable rowForView:sender]; + + //sanity check(s) + // ->make sure row is decent + if( (-1 == itemRow) || + (itemRow >= self.searchResults.count) ) + { + //bail + goto bail; + } + + //extract item for row + item = self.searchResults[itemRow]; + + //tasks + // ->grab path from binary + if(YES == [item isKindOfClass:[Task class]]) + { + //get path + path = ((Task*)item).binary.path; + } + //binary/files + // ->use as is + else if( (YES == [item isKindOfClass:[Binary class]]) || + (YES == [item isKindOfClass:[File class]]) ) + { + //get path + path = [item path]; + } + + //sanity check + if(nil == path) + { + //bail + goto bail; + } + + //open Finder + // ->will reveal binary + [[NSWorkspace sharedWorkspace] selectFile:path inFileViewerRootedAtPath:nil]; + +//bail +bail: + + return; +} + +//automatically invoked when user clicks the 'info' icon +// ->create/configure/display info window for task/dylib/file/etc +-(IBAction)showInfo:(id)sender +{ + //item + // ->task, dylib, file, etc + id item = nil; + + //row + NSInteger itemRow = 0; + + //grab sender's row + itemRow = [self.searchTable rowForView:sender]; + + //sanity check(s) + // ->make sure row is decent + if( (-1 == itemRow) || + (itemRow >= self.searchResults.count) ) + { + //bail + goto bail; + } + + //grab item + item = self.searchResults[itemRow]; + + //alloc/init info window + infoWindowController = [[InfoWindowController alloc] initWithItem:item]; + + //show it + [self.infoWindowController.windowController showWindow:self]; + + //bail +bail: + + return; +} + + +@end diff --git a/TaskExplorer.xcodeproj/project.pbxproj b/TaskExplorer.xcodeproj/project.pbxproj index 42cdd8e..2152280 100755 --- a/TaskExplorer.xcodeproj/project.pbxproj +++ b/TaskExplorer.xcodeproj/project.pbxproj @@ -8,6 +8,9 @@ /* Begin PBXBuildFile section */ 1D21BC4F172AF43D009D1CFD /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D21BC4E172AF43D009D1CFD /* Cocoa.framework */; }; + 7D2F567C1B81BEAB00C7D85E /* SearchWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D2F567B1B81BEAB00C7D85E /* SearchWindow.xib */; }; + 7D2F567F1B81BEB400C7D85E /* SearchWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D2F567E1B81BEB400C7D85E /* SearchWindowController.m */; }; + 7DEC68971B844F4800F4C12E /* SearchResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DEC68961B844F4800F4C12E /* SearchResult.m */; }; CD001B381AB903040089014A /* logo.png in Resources */ = {isa = PBXBuildFile; fileRef = CD001B351AB903040089014A /* logo.png */; }; CD001B391AB903040089014A /* logoApple.png in Resources */ = {isa = PBXBuildFile; fileRef = CD001B361AB903040089014A /* logoApple.png */; }; CD02194F1AD34D8B005148A2 /* AboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD02194D1AD34D8B005148A2 /* AboutWindow.xib */; }; @@ -150,6 +153,11 @@ 1D21BC51172AF43D009D1CFD /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 1D21BC52172AF43D009D1CFD /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 1D21BC53172AF43D009D1CFD /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 7D2F567B1B81BEAB00C7D85E /* SearchWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = SearchWindow.xib; path = UI/SearchWindow.xib; sourceTree = ""; }; + 7D2F567D1B81BEB300C7D85E /* SearchWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchWindowController.h; sourceTree = ""; }; + 7D2F567E1B81BEB400C7D85E /* SearchWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchWindowController.m; sourceTree = ""; }; + 7DEC68951B844F4800F4C12E /* SearchResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchResult.h; sourceTree = ""; }; + 7DEC68961B844F4800F4C12E /* SearchResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchResult.m; sourceTree = ""; }; CD001B351AB903040089014A /* logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logo.png; path = images/logo.png; sourceTree = SOURCE_ROOT; }; CD001B361AB903040089014A /* logoApple.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logoApple.png; path = images/logoApple.png; sourceTree = SOURCE_ROOT; }; CD02194D1AD34D8B005148A2 /* AboutWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = AboutWindow.xib; path = UI/AboutWindow.xib; sourceTree = ""; }; @@ -323,6 +331,10 @@ 1D21BC42172AF43D009D1CFD = { isa = PBXGroup; children = ( + 7D2F567D1B81BEB300C7D85E /* SearchWindowController.h */, + 7D2F567E1B81BEB400C7D85E /* SearchWindowController.m */, + 7DEC68951B844F4800F4C12E /* SearchResult.h */, + 7DEC68961B844F4800F4C12E /* SearchResult.m */, CD74A0781B7F170B00A8AAD3 /* FlaggedItems.h */, CD74A0791B7F170B00A8AAD3 /* FlaggedItems.m */, CD4D54201B2CE6F200008030 /* NSMutableArray+QueueAdditions.h */, @@ -551,6 +563,7 @@ CDA81E621AA020E8009790E2 /* UI */ = { isa = PBXGroup; children = ( + 7D2F567B1B81BEAB00C7D85E /* SearchWindow.xib */, CD74A07D1B81B5D400A8AAD3 /* FlaggedItems.xib */, CD4D54271B2EAC7800008030 /* NetworkInfoWindow.xib */, CD4D54231B2D082300008030 /* DylibInfoWindow.xib */, @@ -630,8 +643,12 @@ LastUpgradeCheck = 0620; ORGANIZATIONNAME = "Lucas Derraugh"; TargetAttributes = { + 1D21BC4A172AF43D009D1CFD = { + DevelopmentTeam = VBG97UB4TA; + }; CDA5F6AC1B16D805003CE340 = { CreatedOnToolsVersion = 6.3.2; + DevelopmentTeam = VBG97UB4TA; }; }; }; @@ -685,6 +702,7 @@ CDF08CD01AC4C6E8009B3423 /* settingsBG.png in Resources */, CDEE77021B3FD55600763826 /* teText.png in Resources */, CDEE76FC1B3FD44500763826 /* saveIcon.png in Resources */, + 7D2F567C1B81BEAB00C7D85E /* SearchWindow.xib in Resources */, CD0219591AD37748005148A2 /* unsigned2.png in Resources */, CD4D54281B2EAC7800008030 /* NetworkInfoWindow.xib in Resources */, CDA81D5C1A95B4B4009790E2 /* MainMenu.xib in Resources */, @@ -753,6 +771,7 @@ CD74A07B1B7F170B00A8AAD3 /* FlaggedItems.m in Sources */, CDA5F6C41B16E20E003CE340 /* RequestRootWindowController.m in Sources */, CDD2483B1AF5CC4D00232422 /* Task.m in Sources */, + 7D2F567F1B81BEB400C7D85E /* SearchWindowController.m in Sources */, CD83887F1AACCEDF000EB098 /* VirusTotal.m in Sources */, CDF08CDF1AC886F2009B3423 /* VTInfoWindowController.m in Sources */, CD3F4CEB1AF6D948002A2647 /* OrderedDictionary.m in Sources */, @@ -777,6 +796,7 @@ CDD248351AF5947300232422 /* TAAdaptiveSpaceItemView.m in Sources */, CDBE49181B58DC9B0031FC22 /* NSApplicationKeyEvents.m in Sources */, CDA81D531A95B492009790E2 /* Utilities.m in Sources */, + 7DEC68971B844F4800F4C12E /* SearchResult.m in Sources */, CD7B9FAB1AD08FA100DF3C71 /* KKRow.m in Sources */, CD3F4CFD1AF71B58002A2647 /* ItemBase.m in Sources */, ); @@ -884,11 +904,14 @@ 1D21BC69172AF43D009D1CFD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_IDENTITY = "Developer ID Application"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer"; COMBINE_HIDPI_IMAGES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "TaskExplorer-Prefix.pch"; INFOPLIST_FILE = "TaskExplorer-Info.plist"; PRODUCT_NAME = TaskExplorer; + PROVISIONING_PROFILE = ""; WRAPPER_EXTENSION = app; }; name = Debug; @@ -896,11 +919,14 @@ 1D21BC6A172AF43D009D1CFD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_IDENTITY = "Developer ID Application"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer"; COMBINE_HIDPI_IMAGES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "TaskExplorer-Prefix.pch"; INFOPLIST_FILE = "TaskExplorer-Info.plist"; PRODUCT_NAME = TaskExplorer; + PROVISIONING_PROFILE = ""; WRAPPER_EXTENSION = app; }; name = Release; @@ -913,6 +939,7 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "Developer ID Application"; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -941,6 +968,7 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "Developer ID Application"; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; ENABLE_NS_ASSERTIONS = NO; diff --git a/TaskExplorer.xcodeproj/project.xcworkspace/xcshareddata/TaskExplorer.xccheckout b/TaskExplorer.xcodeproj/project.xcworkspace/xcshareddata/TaskExplorer.xccheckout index df18232..c0c67db 100644 --- a/TaskExplorer.xcodeproj/project.xcworkspace/xcshareddata/TaskExplorer.xccheckout +++ b/TaskExplorer.xcodeproj/project.xcworkspace/xcshareddata/TaskExplorer.xccheckout @@ -7,14 +7,14 @@ IDESourceControlProjectIdentifier FE4103FE-6F26-4639-8C9F-D8D32C76D6A9 IDESourceControlProjectName - TaskExplorer + project IDESourceControlProjectOriginsDictionary 61F07AFB33748EF0C810BEEF6126283DAC63A899 https://bitbucket.org/objective-see/taskexplorer.git IDESourceControlProjectPath - TaskExplorer.xcodeproj + TaskExplorer.xcodeproj/project.xcworkspace IDESourceControlProjectRelativeInstallPathDictionary 61F07AFB33748EF0C810BEEF6126283DAC63A899 diff --git a/TaskTableController.h b/TaskTableController.h index 89fcd77..06ca584 100644 --- a/TaskTableController.h +++ b/TaskTableController.h @@ -38,7 +38,7 @@ //category table view @property(weak) IBOutlet NSTableView *itemView; -//info window +//info window controller @property(retain, nonatomic)InfoWindowController* infoWindowController; //virus total window controller diff --git a/UI/FlaggedItems.xib b/UI/FlaggedItems.xib index 81bd7e6..3ebd0d8 100644 --- a/UI/FlaggedItems.xib +++ b/UI/FlaggedItems.xib @@ -1,5 +1,5 @@ - + @@ -17,7 +17,7 @@ - + @@ -49,7 +49,7 @@ - + diff --git a/UI/SearchWindow.xib b/UI/SearchWindow.xib new file mode 100644 index 0000000..b1238a9 --- /dev/null +++ b/UI/SearchWindow.xib @@ -0,0 +1,449 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/en.lproj/MainMenu.xib b/en.lproj/MainMenu.xib index 8936c57..bc12c19 100755 --- a/en.lproj/MainMenu.xib +++ b/en.lproj/MainMenu.xib @@ -1,5 +1,5 @@ - + @@ -47,7 +47,7 @@ - + @@ -298,7 +298,7 @@ - +