PageRenderTime 83ms CodeModel.GetById 12ms app.highlight 66ms RepoModel.GetById 1ms app.codeStats 0ms

/iPhoneTrackingAppDelegate.m

http://github.com/petewarden/iPhoneTracker
Objective C | 271 lines | 183 code | 60 blank | 28 comment | 17 complexity | ea4e48e644e3d9e1ba8e9edf0fbaa936 MD5 | raw file
  1//
  2//  iPhoneTrackingAppDelegate.m
  3//  iPhoneTracking
  4//
  5//  Created by Pete Warden on 4/15/11.
  6//
  7
  8/***********************************************************************************
  9*
 10* All code (C) Pete Warden, 2011
 11*
 12*    This program is free software: you can redistribute it and/or modify
 13*    it under the terms of the GNU General Public License as published by
 14*    the Free Software Foundation, either version 3 of the License, or
 15*    (at your option) any later version.
 16*
 17*    This program is distributed in the hope that it will be useful,
 18*    but WITHOUT ANY WARRANTY; without even the implied warranty of
 19*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 20*
 21*    GNU General Public License for more details.
 22*
 23*    You should have received a copy of the GNU General Public License
 24*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 25*
 26************************************************************************************/
 27
 28#import "iPhoneTrackingAppDelegate.h"
 29#import "fmdb/FMDatabase.h"
 30#import "parsembdb.h"
 31
 32@implementation iPhoneTrackingAppDelegate
 33
 34@synthesize window;
 35@synthesize webView;
 36
 37- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
 38}
 39
 40- displayErrorAndQuit:(NSString *)error
 41{
 42    [[NSAlert alertWithMessageText: @"Error"
 43      defaultButton:@"OK" alternateButton:nil otherButton:nil
 44      informativeTextWithFormat: error] runModal];
 45    exit(1);
 46}
 47
 48- (void)awakeFromNib
 49{
 50  NSString* htmlString = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"]
 51      encoding:NSUTF8StringEncoding error:NULL];
 52
 53 	[[webView mainFrame] loadHTMLString:htmlString baseURL:NULL];
 54  [webView setUIDelegate:self];
 55  [webView setFrameLoadDelegate:self]; 
 56  [webView setResourceLoadDelegate:self]; 
 57}
 58
 59- (void)debugLog:(NSString *) message
 60{
 61  NSLog(@"%@", message);
 62}
 63
 64+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector { return NO; }
 65
 66- (void)webView:(WebView *)sender windowScriptObjectAvailable: (WebScriptObject *)windowScriptObject
 67{
 68  scriptObject = windowScriptObject;
 69}
 70
 71- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
 72{
 73  [self loadLocationDB];
 74}
 75
 76- (void)loadLocationDB
 77{
 78  NSString* backupPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/MobileSync/Backup/"];
 79
 80  NSFileManager *fm = [NSFileManager defaultManager];
 81  NSArray* backupContents = [[NSFileManager defaultManager] directoryContentsAtPath:backupPath];
 82
 83  NSMutableArray* fileInfoList = [NSMutableArray array];
 84  for (NSString *childName in backupContents) {
 85    NSString* childPath = [backupPath stringByAppendingPathComponent:childName];
 86
 87    NSString *plistFile = [childPath   stringByAppendingPathComponent:@"Info.plist"];
 88      
 89    NSError* error;
 90    NSDictionary *childInfo = [fm attributesOfItemAtPath:childPath error:&error];
 91
 92    NSDate* modificationDate = [childInfo objectForKey:@"NSFileModificationDate"];    
 93
 94    NSDictionary* fileInfo = [NSDictionary dictionaryWithObjectsAndKeys: 
 95      childPath, @"fileName", 
 96      modificationDate, @"modificationDate", 
 97      plistFile, @"plistFile", 
 98      nil];
 99    [fileInfoList addObject: fileInfo];
100
101  }
102  
103  NSSortDescriptor* sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"modificationDate" ascending:NO] autorelease];
104  [fileInfoList sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
105
106  BOOL loadWorked = NO;
107  for (NSDictionary* fileInfo in fileInfoList) {
108    @try {
109      NSString* newestFolder = [fileInfo objectForKey:@"fileName"];
110      NSString* plistFile = [fileInfo objectForKey:@"plistFile"];
111      
112      NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:plistFile];
113      if (plist==nil) {
114        NSLog(@"No plist file found at '%@'", plistFile);
115        continue;
116      }
117      NSString* deviceName = [plist objectForKey:@"Device Name"];
118      NSLog(@"file = %@, device = %@", plistFile, deviceName);  
119
120      NSDictionary* mbdb = [ParseMBDB getFileListForPath: newestFolder];
121      if (mbdb==nil) {
122        NSLog(@"No MBDB file found at '%@'", newestFolder);
123        continue;
124      }
125
126      NSString* wantedFileName = @"Library/Caches/locationd/consolidated.db";
127      NSString* dbFileName = nil;
128      for (NSNumber* offset in mbdb) {
129        NSDictionary* fileInfo = [mbdb objectForKey:offset];
130        NSString* fileName = [fileInfo objectForKey:@"filename"];
131        if ([wantedFileName compare:fileName]==NSOrderedSame) {
132          dbFileName = [fileInfo objectForKey:@"fileID"];
133        }
134      }
135
136      if (dbFileName==nil) {
137        NSLog(@"No consolidated.db file found in '%@'", newestFolder);
138        continue;
139      }
140
141      NSString* dbFilePath = [newestFolder stringByAppendingPathComponent:dbFileName];
142
143      loadWorked = [self tryToLoadLocationDB: dbFilePath forDevice:deviceName];
144      if (loadWorked) {
145        break;
146      }
147    }
148    @catch (NSException *exception) {
149      NSLog(@"Exception: %@", [exception reason]);
150    }
151  }
152
153  if (!loadWorked) {
154    [self displayErrorAndQuit: [NSString stringWithFormat: @"Couldn't load consolidated.db file from '%@'", backupPath]];  
155  }
156}
157
158- (BOOL)tryToLoadLocationDB:(NSString*) locationDBPath forDevice:(NSString*) deviceName
159{
160  [scriptObject setValue:self forKey:@"cocoaApp"];
161    
162  FMDatabase* database = [FMDatabase databaseWithPath: locationDBPath];
163  [database setLogsErrors: YES];
164  BOOL openWorked = [database open];
165  if (!openWorked) {
166    return NO;
167  }
168
169  const float precision = 100;
170  NSMutableDictionary* buckets = [NSMutableDictionary dictionary];
171
172  NSString* queries[] = {@"SELECT * FROM CellLocation;", @"SELECT * FROM WifiLocation;"};
173  
174  // Temporarily disabled WiFi location pulling, since it's so dodgy. Change to 
175  for (int pass=0; pass<1; /*pass<2;*/ pass+=1) {
176  
177    FMResultSet* results = [database executeQuery:queries[pass]];
178
179    while ([results next]) {
180      NSDictionary* row = [results resultDict];
181
182      NSNumber* latitude_number = [row objectForKey:@"latitude"];
183      NSNumber* longitude_number = [row objectForKey:@"longitude"];
184      NSNumber* timestamp_number = [row objectForKey:@"timestamp"];
185
186      const float latitude = [latitude_number floatValue];
187      const float longitude = [longitude_number floatValue];
188      const float timestamp = [timestamp_number floatValue];
189      
190      // The timestamps seem to be based off 2001-01-01 strangely, so convert to the 
191      // standard Unix form using this offset
192      const float iOSToUnixOffset = (31*365.25*24*60*60);
193      const float unixTimestamp = (timestamp+iOSToUnixOffset);
194      
195      if ((latitude==0.0)&&(longitude==0.0)) {
196        continue;
197      }
198      
199      const float weekInSeconds = (7*24*60*60);
200      const float timeBucket = (floor(unixTimestamp/weekInSeconds)*weekInSeconds);
201      
202      NSDate* timeBucketDate = [NSDate dateWithTimeIntervalSince1970:timeBucket];
203
204      NSString* timeBucketString = [timeBucketDate descriptionWithCalendarFormat:@"%Y-%m-%d" timeZone:nil locale:nil];
205
206      const float latitude_index = (floor(latitude*precision)/precision);  
207      const float longitude_index = (floor(longitude*precision)/precision);
208      NSString* allKey = [NSString stringWithFormat:@"%f,%f,All Time", latitude_index, longitude_index];
209      NSString* timeKey = [NSString stringWithFormat:@"%f,%f,%@", latitude_index, longitude_index, timeBucketString];
210
211      [self incrementBuckets: buckets forKey: allKey];
212      [self incrementBuckets: buckets forKey: timeKey];
213    }
214  }
215  
216  NSMutableArray* csvArray = [[[NSMutableArray alloc] init] autorelease];
217  
218  [csvArray addObject: @"lat,lon,value,time\n"];
219
220  for (NSString* key in buckets) {
221    NSNumber* count = [buckets objectForKey:key];
222
223    NSArray* parts = [key componentsSeparatedByString:@","];
224    NSString* latitude_string = [parts objectAtIndex:0];
225    NSString* longitude_string = [parts objectAtIndex:1];
226    NSString* time_string = [parts objectAtIndex:2];
227
228    NSString* rowString = [NSString stringWithFormat:@"%@,%@,%@,%@\n", latitude_string, longitude_string, count, time_string];
229    [csvArray addObject: rowString];
230  }
231
232  if ([csvArray count]<10) {
233    return NO;
234  }
235  
236  NSString* csvText = [csvArray componentsJoinedByString:@"\n"];
237  
238  id scriptResult = [scriptObject callWebScriptMethod: @"storeLocationData" withArguments:[NSArray arrayWithObjects:csvText,deviceName,nil]];
239	if(![scriptResult isMemberOfClass:[WebUndefined class]]) {
240		NSLog(@"scriptResult='%@'", scriptResult);
241  }
242
243  return YES;
244}
245
246- (void) incrementBuckets:(NSMutableDictionary*)buckets forKey:(NSString*)key
247{
248    NSNumber* existingValue = [buckets objectForKey:key];
249    if (existingValue==nil) {
250      existingValue = [NSNumber numberWithInteger:0];
251    }
252    NSNumber* newValue = [NSNumber numberWithInteger:([existingValue integerValue]+1)];
253
254    [buckets setObject: newValue forKey: key];
255}
256
257- (IBAction)openAboutPanel:(id)sender {
258    
259    NSImage *img = [NSImage imageNamed: @"Icon"];
260    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
261               @"1.0", @"Version",
262               @"iPhone Tracking", @"ApplicationName",
263               img, @"ApplicationIcon",
264               @"Copyright 2011, Pete Warden and Alasdair Allan", @"Copyright",
265               @"iPhone Tracking v1.0", @"ApplicationVersion",
266               nil];
267    
268    [[NSApplication sharedApplication] orderFrontStandardAboutPanelWithOptions:options];
269    
270}
271@end