// // JSRunHelperController.m // JSRunIpodHelperApp // // Created by Jonathan Saggau on 10/30/06. // Copyright 2006 Jonathan Saggau. All rights reserved. // #import "JSIpodDetector.h" #import "NSStringAdditions.h" @interface JSIpodDetector (privateAPI) - (void)handleMountedPath:(NSString *)path; - (void)didMount:(NSNotification *) note; - (void)didUnmount:(NSNotification *) note; @end @implementation JSIpodDetector - (id)init { if (self = [super init]) { mountedIpodPaths = [[NSMutableArray alloc] init]; mountedIpodWithRunsPaths = [[NSMutableArray alloc] init]; pedometersFiles = [[NSMutableDictionary alloc] init]; [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector( didMount: ) name:NSWorkspaceDidMountNotification object:nil]; [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector( didUnmount: ) name:NSWorkspaceDidUnmountNotification object:nil]; //get mounted removable disks and check if they are ipods on startup NSArray *removableDisks = [[NSWorkspace sharedWorkspace] mountedRemovableMedia]; NSEnumerator *disksEnum = [removableDisks objectEnumerator]; NSString *path; while (path = [disksEnum nextObject]) { [self handleMountedPath:path]; } } return self; } - (void)dealloc { [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self]; [mountedIpodPaths release]; mountedIpodPaths = nil; [mountedIpodWithRunsPaths release]; mountedIpodWithRunsPaths = nil; [pedometersFiles release]; pedometersFiles = nil; [super dealloc]; } - (void)handleMountedPath:(NSString *)path { NSFileManager *fileManager = [NSFileManager defaultManager]; //get top level directories NSArray * directoryContentsAtPath = [fileManager directoryContentsAtPath:path]; if ([directoryContentsAtPath containsObject:@"._iPod_Control"] && [directoryContentsAtPath containsObject:@"iPod_Control"]) { // if ._ipod_Control and iPod_Control are present, assume we have an ipod //take note of a valid mounted ipod [mountedIpodPaths addObject:path]; //tell delegate what we found if(delegate && [delegate respondsToSelector:@selector(ipodDidMountAtPath:)]) [delegate performSelector:@selector(ipodDidMountAtPath:) withObject:path]; //now we check for pedometers //<>/iPod_Control/Device/Trainer/Workouts/Empeds/ is where runs are stored NSString *workoutBasePath = [path stringByAppendingPathComponent:@"iPod_Control/Device/Trainer/Workouts/Empeds/"]; BOOL isDir, isPath; if (isPath = [fileManager fileExistsAtPath:workoutBasePath isDirectory:&isDir] && isDir) { //there is a run directory here //the subdirectory names correspond to the pedometer IDs NSMutableArray *pedometerIds = [NSMutableArray arrayWithArray:[fileManager directoryContentsAtPath:workoutBasePath]]; //there is a file called linkData in this directory we don't care about [pedometerIds removeObject:@"linkData"]; int pedometers = [pedometerIds count]; if (pedometers > 0) { //if we still have directories here, they're pedometer data stores NSString *pedometerBasePath; for (int i = 0; i < pedometers; i++) { //look through each pedometer directory to find xml files NSString *pedometer = [pedometerIds objectAtIndex:i]; pedometerBasePath = [workoutBasePath stringByAppendingPathComponent:pedometer]; NSArray *runFiles = [fileManager subpathsAtPath:pedometerBasePath]; NSPredicate *regexPredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES '.*?[0-9]{2};[0-9]{2};[0-9]{2}.xml$'"]; runFiles = [runFiles filteredArrayUsingPredicate:regexPredicate]; [pedometersFiles setValue:runFiles forKey:pedometerBasePath]; } if ([pedometersFiles count] > 0) { //if we have run data files, take note of the path [mountedIpodWithRunsPaths addObject:path]; //tell delegate what we found if(delegate && [delegate respondsToSelector:@selector(ipodWithRunsDidMountAtPath:)]) [delegate performSelector:@selector(ipodWithRunsDidMountAtPath:) withObject:path]; } } } } } //Fires on workspace mount notification - (void)didMount:(NSNotification *) note { //First check to see if it's an iPod NSDictionary *userInfo = [note userInfo]; NSString *path = [userInfo objectForKey: @"NSDevicePath"]; [self handleMountedPath:path]; } //Fires on workspace mount notification - (void)didUnmount:(NSNotification *) note { NSDictionary *userInfo = [note userInfo]; NSString *path = [userInfo objectForKey: @"NSDevicePath"]; //Check to see if the path that was unmounted is in our list of ipods if([mountedIpodPaths containsObject:path]) { //we unmounted, so remove the path from the list [mountedIpodPaths removeObject:path]; if([mountedIpodWithRunsPaths containsObject:path]) { //remove ipod path from mountedIpodWithRunsPaths [mountedIpodWithRunsPaths removeObject:path]; NSEnumerator *pedFilesKeyEnum = [pedometersFiles keyEnumerator]; NSMutableDictionary *tempPedsFiles = [NSMutableDictionary dictionaryWithDictionary:pedometersFiles]; NSString *currentKey; while (currentKey = [pedFilesKeyEnum nextObject]) { //match any path that starts with out ipod path and remove that from //the PedometersFiles dictionary NSString *pattern = [NSString stringWithFormat:@"%@.*?", path]; if([currentKey matchesPattern:pattern]) { NSLog(@"%@ matched %@; removing", currentKey, pattern); [tempPedsFiles removeObjectForKey:currentKey]; } } } //tell delegate what we lost if(delegate && [delegate respondsToSelector:@selector(ipodDidUnmountAtPath:)]) [delegate performSelector:@selector(ipodDidUnmountAtPath:) withObject:path]; } } #pragma mark - #pragma mark accessors //=========================================================== // mountedIpodPaths //=========================================================== - (NSArray *)mountedIpodPaths { return mountedIpodPaths; } //=========================================================== // mountedIpodWithRunsPaths //=========================================================== - (NSArray *)mountedIpodWithRunsPaths { return mountedIpodWithRunsPaths; } //=========================================================== // pedometersFiles //=========================================================== - (NSDictionary *)pedometersFiles { return pedometersFiles; } //=========================================================== // delegate //=========================================================== - (void) setDelegate:(id)d { [delegate autorelease]; delegate = [d retain]; } - (id) delegate { return delegate; } @end