incubator-callback-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From shaz...@apache.org
Subject [5/27] Rename PhoneGap to Cordova.
Date Fri, 17 Feb 2012 01:38:49 GMT
http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/bcff9559/CordovaLib/Classes/CDVContacts.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVContacts.m b/CordovaLib/Classes/CDVContacts.m
new file mode 100755
index 0000000..cf38542
--- /dev/null
+++ b/CordovaLib/Classes/CDVContacts.m
@@ -0,0 +1,511 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+
+#import "CDVContacts.h"
+#import <UIKit/UIKit.h>
+#import "NSDictionary+Extensions.h"
+#import "CDVNotification.h"
+
+
+@implementation CDVContactsPicker
+
+@synthesize allowsEditing;
+@synthesize callbackId;
+@synthesize selectedId;
+
+@end
+@implementation CDVNewContactsController
+
+@synthesize callbackId;
+
+@end
+
+@implementation CDVContacts
+
+// no longer used since code gets AddressBook for each operation. 
+// If address book changes during save or remove operation, may get error but not much we can do about it
+// If address book changes during UI creation, display or edit, we don't control any saves so no need for callback
+/*void addressBookChanged(ABAddressBookRef addressBook, CFDictionaryRef info, void* context)
+{
+	// note that this function is only called when another AddressBook instance modifies 
+	// the address book, not the current one. For example, through an OTA MobileMe sync
+	Contacts* contacts = (Contacts*)context;
+	[contacts addressBookDirty];
+}*/
+
+-(CDVPlugin*) initWithWebView:(UIWebView*)theWebView
+{
+    self = (CDVContacts*)[super initWithWebView:(UIWebView*)theWebView];
+    /*if (self) {
+		addressBook = ABAddressBookCreate();
+		ABAddressBookRegisterExternalChangeCallback(addressBook, addressBookChanged, self);
+    }*/
+	
+	return self;
+}
+
+
+// overridden to clean up Contact statics
+-(void)onAppTerminate
+{
+	//NSLog(@"Contacts::onAppTerminate");
+	[CDVContact releaseDefaults];
+}
+
+
+// iPhone only method to create a new contact through the GUI
+- (void) newContact:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+{	
+	NSString* callbackId = [arguments objectAtIndex:0];
+
+	CDVNewContactsController* npController = [[[CDVNewContactsController alloc] init] autorelease];
+	
+	ABAddressBookRef ab = ABAddressBookCreate();
+	npController.addressBook = ab; // a CF retaining assign
+    CFRelease(ab);
+    
+	npController.newPersonViewDelegate = self;
+	npController.callbackId = callbackId;
+
+	UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:npController] autorelease];
+    
+    if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) {
+        [self.viewController presentViewController:navController animated:YES completion:nil];        
+    } else {
+        [self.viewController presentModalViewController:navController animated:YES ];
+    }              
+}
+
+- (void) newPersonViewController:(ABNewPersonViewController*)newPersonViewController didCompleteWithNewPerson:(ABRecordRef)person
+{
+
+	ABRecordID recordId = kABRecordInvalidID;
+	CDVNewContactsController* newCP = (CDVNewContactsController*) newPersonViewController;
+	NSString* callbackId = newCP.callbackId;
+	
+	if (person != NULL) {
+			//return the contact id
+			recordId = ABRecordGetRecordID(person);
+	}
+
+    if ([newPersonViewController respondsToSelector:@selector(presentingViewController)]) { 
+        [[newPersonViewController presentingViewController] dismissViewControllerAnimated:YES completion:nil];
+    } else {
+        [[newPersonViewController parentViewController] dismissModalViewControllerAnimated:YES];
+    }        
+    
+	CDVPluginResult* result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsInt:  recordId];
+	//jsString = [NSString stringWithFormat: @"%@(%d);", newCP.jsCallback, recordId];
+	[self writeJavascript: [result toSuccessCallbackString:callbackId]];
+	
+}
+
+- (void) displayContact:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	ABRecordID recordID = kABRecordInvalidID;
+	NSString* callbackId = [arguments objectAtIndex:0];
+	
+	recordID = [[arguments objectAtIndex:1] intValue];
+
+		
+	
+	bool bEdit = [options isKindOfClass:[NSNull class]] ? false : [options existsValue:@"true" forKey:@"allowsEditing"];
+	ABAddressBookRef addrBook = ABAddressBookCreate();	
+	ABRecordRef rec = ABAddressBookGetPersonWithRecordID(addrBook, recordID);
+	if (rec) {
+		CDVDisplayContactViewController* personController = [[[CDVDisplayContactViewController alloc] init] autorelease];
+		personController.displayedPerson = rec;
+		personController.personViewDelegate = self;
+		personController.allowsEditing = NO;
+		
+        // create this so DisplayContactViewController will have a "back" button.
+        UIViewController* parentController = [[[UIViewController alloc] init] autorelease];
+        UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:parentController] autorelease];
+
+        [navController pushViewController:personController animated:YES];
+
+        if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) {
+            [self.viewController presentViewController:navController animated:YES completion:nil];        
+        } else {
+            [self.viewController presentModalViewController:navController animated:YES ];
+        }              
+
+		if (bEdit) {
+            // create the editing controller and push it onto the stack
+            ABPersonViewController* editPersonController = [[[ABPersonViewController alloc] init] autorelease];
+            editPersonController.displayedPerson = rec;
+            editPersonController.personViewDelegate = self;
+            editPersonController.allowsEditing = YES; 
+            [navController pushViewController:editPersonController animated:YES];
+        }
+	} 
+	else 
+	{
+		// no record, return error
+		CDVPluginResult* result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsInt:  UNKNOWN_ERROR];
+		[self writeJavascript:[result toErrorCallbackString:callbackId]];
+		
+	}
+	CFRelease(addrBook);
+}
+								   
+- (BOOL) personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person 
+					 property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue
+{
+	return YES;
+}
+	
+- (void) chooseContact:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments objectAtIndex:0];
+	
+	CDVContactsPicker* pickerController = [[[CDVContactsPicker alloc] init] autorelease];
+	pickerController.peoplePickerDelegate = self;
+	pickerController.callbackId = callbackId;
+	pickerController.selectedId = kABRecordInvalidID;
+	pickerController.allowsEditing = (BOOL)[options existsValue:@"true" forKey:@"allowsEditing"];
+	
+    if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) {
+        [self.viewController presentViewController:pickerController animated:YES completion:nil];        
+    } else {
+        [self.viewController presentModalViewController:pickerController animated:YES ];
+    }              
+}
+
+- (BOOL) peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker 
+	     shouldContinueAfterSelectingPerson:(ABRecordRef)person
+{
+	
+	CDVContactsPicker* picker = (CDVContactsPicker*)peoplePicker;
+	ABRecordID contactId = ABRecordGetRecordID(person);
+	picker.selectedId = contactId; // save so can return when dismiss
+
+	
+	if (picker.allowsEditing) {
+		
+		ABPersonViewController* personController = [[[ABPersonViewController alloc] init] autorelease];
+		personController.displayedPerson = person;
+		personController.personViewDelegate = self;
+		personController.allowsEditing = picker.allowsEditing;
+		
+		
+		[peoplePicker pushViewController:personController animated:YES];
+	} else {
+		// return the contact Id
+		CDVPluginResult* result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsInt: contactId];
+		[self writeJavascript:[result toSuccessCallbackString: picker.callbackId]];
+		
+        if ([picker respondsToSelector:@selector(presentingViewController)]) { 
+            [[picker presentingViewController] dismissViewControllerAnimated:YES completion:nil];
+        } else {
+            [[picker parentViewController] dismissModalViewControllerAnimated:YES];
+        }        
+	}
+	return NO;
+}
+
+- (BOOL) peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker 
+	     shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier
+{
+	return YES;
+}
+
+- (void) peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker
+{
+	// return contactId or invalid if none picked
+	CDVContactsPicker* picker = (CDVContactsPicker*)peoplePicker;
+	CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: picker.selectedId];
+	[self writeJavascript:[result toSuccessCallbackString:picker.callbackId]];
+	
+    if ([peoplePicker respondsToSelector:@selector(presentingViewController)]) { 
+        [[peoplePicker presentingViewController] dismissViewControllerAnimated:YES completion:nil];
+    } else {
+        [[peoplePicker parentViewController] dismissModalViewControllerAnimated:YES];
+    }        
+}
+
+- (void) search:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* jsString = nil;
+	NSString* callbackId = [arguments objectAtIndex:0];
+	
+	
+	NSArray* fields = [options valueForKey:@"fields"];
+	NSDictionary* findOptions = [options valueForKey:@"findOptions"];
+	
+	ABAddressBookRef  addrBook = nil;
+	NSArray* foundRecords = nil;
+	
+
+	addrBook = ABAddressBookCreate();
+	// get the findOptions values
+	BOOL multiple = NO; // default is false
+	NSString* filter = nil;
+	if (![findOptions isKindOfClass:[NSNull class]]){
+		id value = nil;
+		filter = (NSString*)[findOptions objectForKey:@"filter"];
+		value = [findOptions objectForKey:@"multiple"];
+		if ([value isKindOfClass:[NSNumber class]]){
+			// multiple is a boolean that will come through as an NSNumber
+			multiple = [(NSNumber*)value boolValue];
+			//NSLog(@"multiple is: %d", multiple);
+		}
+	}
+
+	NSDictionary* returnFields = [[CDVContact class] calcReturnFields: fields];
+	
+	NSMutableArray* matches = nil;
+	if (!filter || [filter isEqualToString:@""]){ 
+		// get all records 
+		foundRecords = (NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook);
+		if (foundRecords && [foundRecords count] > 0){
+			// create Contacts and put into matches array
+            // doesn't make sense to ask for all records when multiple == NO but better check
+			int xferCount = multiple == YES ? [foundRecords count] : 1;
+			matches = [NSMutableArray arrayWithCapacity:xferCount];
+			for(int k = 0; k<xferCount; k++){
+				CDVContact* xferContact = [[[CDVContact alloc] initFromABRecord:(ABRecordRef)[foundRecords objectAtIndex:k]] autorelease];
+				[matches addObject:xferContact];
+				xferContact = nil;
+				
+			}
+		}
+	} else {
+		foundRecords = (NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook);
+		matches = [NSMutableArray arrayWithCapacity:1];
+		BOOL bFound = NO;
+		int testCount = [foundRecords count];
+		for(int j=0; j<testCount; j++){
+			CDVContact* testContact = [[[CDVContact alloc] initFromABRecord: (ABRecordRef)[foundRecords objectAtIndex:j]] autorelease];
+			if (testContact){
+				bFound = [testContact foundValue:filter inFields:returnFields];
+				if(bFound){
+					[matches addObject:testContact];
+				}
+				testContact = nil;
+			}
+		}
+	}
+
+	NSMutableArray* returnContacts = [NSMutableArray arrayWithCapacity:1];
+	
+	if (matches != nil && [matches count] > 0){
+		// convert to JS Contacts format and return in callback
+        // - returnFields  determines what properties to return
+		NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 
+		int count = multiple == YES ? [matches count] : 1;
+		for(int i = 0; i<count; i++){
+			CDVContact* newContact = [matches objectAtIndex:i];
+			NSDictionary* aContact = [newContact toDictionary: returnFields];
+			[returnContacts addObject:aContact];
+		}
+		[pool release];
+	}
+	CDVPluginResult* result = nil;
+    // return found contacts (array is empty if no contacts found)
+    result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray: returnContacts  cast: @"navigator.contacts._findCallback"];
+    jsString = [result toSuccessCallbackString:callbackId];
+    // NSLog(@"findCallback string: %@", jsString);
+	
+
+	if(addrBook){
+		CFRelease(addrBook);
+	}
+	if (foundRecords){
+		[foundRecords release];
+	}
+	
+	if(jsString){
+		[self writeJavascript:jsString];
+    }
+	return;
+	
+	
+}
+- (void) save:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments objectAtIndex:0];
+	NSString* jsString = nil;
+	bool bIsError = FALSE, bSuccess = FALSE;
+	BOOL bUpdate = NO;
+	CDVContactError errCode = UNKNOWN_ERROR;
+	CFErrorRef error;
+	CDVPluginResult* result = nil;	
+	
+	NSMutableDictionary* contactDict = [options valueForKey:@"contact"];
+	
+	ABAddressBookRef addrBook = ABAddressBookCreate();	
+	NSNumber* cId = [contactDict valueForKey:kW3ContactId];
+	CDVContact* aContact = nil; 
+	ABRecordRef rec = nil;
+	if (cId && ![cId isKindOfClass:[NSNull class]]){
+		rec = ABAddressBookGetPersonWithRecordID(addrBook, [cId intValue]);
+		if (rec){
+			aContact = [[CDVContact alloc] initFromABRecord: rec ];
+			bUpdate = YES;
+		}
+	}
+	if (!aContact){
+		aContact = [[CDVContact alloc] init]; 			
+	}
+	
+	bSuccess = [aContact setFromContactDict: contactDict asUpdate: bUpdate];
+	if (bSuccess){
+		if (!bUpdate){
+			bSuccess = ABAddressBookAddRecord(addrBook, [aContact record], &error);
+		}
+		if (bSuccess) {
+			bSuccess = ABAddressBookSave(addrBook, &error);
+		}
+		if (!bSuccess){  // need to provide error codes
+			bIsError = TRUE;
+			errCode = IO_ERROR; 
+		} else {
+			
+			// give original dictionary back?  If generate dictionary from saved contact, have no returnFields specified
+			// so would give back all fields (which W3C spec. indicates is not desired)
+			// for now (while testing) give back saved, full contact
+			NSDictionary* newContact = [aContact toDictionary: [CDVContact defaultFields]];
+			//NSString* contactStr = [newContact JSONRepresentation];
+			result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary: newContact cast: @"navigator.contacts._contactCallback" ];
+			jsString = [result toSuccessCallbackString:callbackId];
+		}
+	} else {
+		bIsError = TRUE;
+		errCode = IO_ERROR; 
+	}
+	[aContact release];	
+	CFRelease(addrBook);
+		
+	if (bIsError){
+		result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt: errCode cast:@"navigator.contacts._errCallback" ];
+		jsString = [result toErrorCallbackString:callbackId];
+	}
+	
+	if(jsString){
+		[self writeJavascript: jsString];
+		//[webView stringByEvaluatingJavaScriptFromString:jsString];
+	}
+	
+	
+}	
+- (void) remove: (NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments objectAtIndex:0];
+	NSString* jsString = nil;
+	bool bIsError = FALSE, bSuccess = FALSE;
+	CDVContactError errCode = UNKNOWN_ERROR;
+	CFErrorRef error;
+	ABAddressBookRef addrBook = nil;
+	ABRecordRef rec = nil;
+	CDVPluginResult* result = nil;
+	
+	NSMutableDictionary* contactDict = [options valueForKey:@"contact"];
+	addrBook = ABAddressBookCreate();	
+	NSNumber* cId = [contactDict valueForKey:kW3ContactId];
+	if (cId && ![cId isKindOfClass:[NSNull class]] && [cId intValue] != kABRecordInvalidID){
+		rec = ABAddressBookGetPersonWithRecordID(addrBook, [cId intValue]);
+		if (rec){
+			bSuccess = ABAddressBookRemoveRecord(addrBook, rec, &error);
+			if (!bSuccess){
+				bIsError = TRUE;
+				errCode = IO_ERROR; 
+			} else {
+				bSuccess = ABAddressBookSave(addrBook, &error);
+				if(!bSuccess){
+					bIsError = TRUE;
+					errCode = IO_ERROR;
+				}else {
+					// set id to null
+					[contactDict setObject:[NSNull null] forKey:kW3ContactId];
+					result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary: contactDict cast: @"navigator.contacts._contactCallback"];
+					jsString = [result toSuccessCallbackString:callbackId];
+					//NSString* contactStr = [contactDict JSONRepresentation];
+				}
+			}						
+		} else {
+			// no record found return error
+			bIsError = TRUE;
+			errCode = UNKNOWN_ERROR;
+		}
+		
+	} else {
+		// invalid contact id provided
+		bIsError = TRUE;
+		errCode = INVALID_ARGUMENT_ERROR;
+	}
+	
+
+	if (addrBook){
+		CFRelease(addrBook);
+	}
+	if (bIsError){
+		result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt: errCode cast: @"navigator.contacts._errCallback"];
+		 jsString = [result toErrorCallbackString:callbackId];
+	}
+	if (jsString){
+		[self writeJavascript:jsString];
+	}	
+		
+	return;
+		
+}
+
+- (void)dealloc
+{
+	/*ABAddressBookUnregisterExternalChangeCallback(addressBook, addressBookChanged, self);
+
+	if (addressBook) {
+		CFRelease(addressBook);
+	}
+	*/
+	
+    [super dealloc];
+}
+
+@end
+
+/* ABPersonViewController does not have any UI to dismiss.  Adding navigationItems to it does not work properly
+ * The navigationItems are lost when the app goes into the background.  The solution was to create an empty
+ * NavController in front of the ABPersonViewController. This will cause the ABPersonViewController to have a back button. By subclassing the ABPersonViewController, we can override viewDidDisappear and take down the entire NavigationController.
+ */ 
+@implementation CDVDisplayContactViewController
+@synthesize contactsPlugin;
+
+
+- (void)viewWillDisappear: (BOOL)animated
+{
+    [super viewWillDisappear: animated];
+    
+    if ([self respondsToSelector:@selector(presentingViewController)]) { 
+        [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];
+    } else {
+        [[self parentViewController] dismissModalViewControllerAnimated:YES];
+    }        
+    
+}
+-(void) dealloc
+{
+    self.contactsPlugin=nil;
+    [super dealloc];
+}
+
+@end
+

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/bcff9559/CordovaLib/Classes/CDVCordovaView.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVCordovaView.h b/CordovaLib/Classes/CDVCordovaView.h
new file mode 100644
index 0000000..32a2b1a
--- /dev/null
+++ b/CordovaLib/Classes/CDVCordovaView.h
@@ -0,0 +1,29 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <UIKit/UIKit.h>
+
+
+@interface CDVCordovaView : UIWebView {
+	
+
+}
+
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/bcff9559/CordovaLib/Classes/CDVCordovaView.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVCordovaView.m b/CordovaLib/Classes/CDVCordovaView.m
new file mode 100644
index 0000000..4448bdb
--- /dev/null
+++ b/CordovaLib/Classes/CDVCordovaView.m
@@ -0,0 +1,47 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVCordovaView.h"
+
+
+@implementation CDVCordovaView
+
+
+- (void)loadRequest:(NSURLRequest *)request
+{
+	[super loadRequest:request];
+}
+
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code.
+}
+*/
+
+
+
+
+- (void)dealloc {
+    [super dealloc];
+}
+
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/bcff9559/CordovaLib/Classes/CDVDebug.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVDebug.h b/CordovaLib/Classes/CDVDebug.h
new file mode 100644
index 0000000..78e7778
--- /dev/null
+++ b/CordovaLib/Classes/CDVDebug.h
@@ -0,0 +1,25 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#ifdef DEBUG
+#    define DLog(...) NSLog(__VA_ARGS__)
+#else
+#    define DLog(...) /* */
+#endif
+#define ALog(...) NSLog(__VA_ARGS__)

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/bcff9559/CordovaLib/Classes/CDVDebugConsole.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVDebugConsole.h b/CordovaLib/Classes/CDVDebugConsole.h
new file mode 100644
index 0000000..2bc82f3
--- /dev/null
+++ b/CordovaLib/Classes/CDVDebugConsole.h
@@ -0,0 +1,30 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+#import "CDVPlugin.h"
+
+
+@interface CDVDebugConsole : CDVPlugin {
+}
+
+- (void)log:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/bcff9559/CordovaLib/Classes/CDVDebugConsole.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVDebugConsole.m b/CordovaLib/Classes/CDVDebugConsole.m
new file mode 100644
index 0000000..da7e303
--- /dev/null
+++ b/CordovaLib/Classes/CDVDebugConsole.m
@@ -0,0 +1,36 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "CDVDebugConsole.h"
+
+@implementation CDVDebugConsole
+
+- (void)log:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments objectAtIndex:0];
+#pragma unused(callbackId)
+    NSString* message = [arguments objectAtIndex:1];
+    NSString* log_level = @"INFO";
+    if ([options objectForKey:@"logLevel"])
+        log_level = [options objectForKey:@"logLevel"];
+
+    NSLog(@"[%@] %@", log_level, message);
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/bcff9559/CordovaLib/Classes/CDVFile.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVFile.h b/CordovaLib/Classes/CDVFile.h
new file mode 100644
index 0000000..ccce5d9
--- /dev/null
+++ b/CordovaLib/Classes/CDVFile.h
@@ -0,0 +1,107 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import "CDVPlugin.h"
+
+enum CDVFileError {
+	NOT_FOUND_ERR = 1,
+    SECURITY_ERR = 2,
+    ABORT_ERR = 3,
+    NOT_READABLE_ERR = 4,
+    ENCODING_ERR = 5,
+    NO_MODIFICATION_ALLOWED_ERR = 6,
+    INVALID_STATE_ERR = 7,
+    SYNTAX_ERR = 8,
+    INVALID_MODIFICATION_ERR = 9,
+    QUOTA_EXCEEDED_ERR = 10,
+    TYPE_MISMATCH_ERR = 11,
+    PATH_EXISTS_ERR = 12
+};
+typedef int CDVFileError;
+
+enum CDVFileSystemType {
+	TEMPORARY = 0,
+	PERSISTENT = 1
+};
+typedef int CDVFileSystemType;
+
+@interface CDVFile : CDVPlugin {
+	
+	NSString *appDocsPath;	
+	NSString *appLibraryPath;	
+	NSString *appTempPath;
+	NSString *persistentPath;
+	NSString *temporaryPath;
+	
+	BOOL userHasAllowed;
+
+}
+- (NSNumber*) checkFreeDiskSpace: (NSString*) appPath;
+-(NSString*) getAppPath: (NSString*)pathFragment;
+//-(NSString*) getFullPath: (NSString*)pathFragment;
+- (void) requestFileSystem:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+-(NSDictionary*) getDirectoryEntry: (NSString*) fullPath isDirectory: (BOOL) isDir;
+- (void) resolveLocalFileSystemURI:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+- (void) getDirectory:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+- (void) getFile:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+- (void) getParent:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+- (void) getMetadata:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+- (void) removeRecursively:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+- (void) remove:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+- (NSString*) doRemove:(NSString*)fullPath callback: (NSString*)callbackId;
+- (void) copyTo:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+- (void) moveTo:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+-(BOOL) canCopyMoveSrc: (NSString*) src ToDestination: (NSString*) dest;
+- (void) doCopyMove:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options  isCopy:(BOOL)bCopy;
+//- (void) toURI:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+- (void) getFileMetadata:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+- (void) readEntries:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+
+- (void) readFile:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+- (void) readAsDataURL:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+-(NSString*) getMimeTypeFromPath: (NSString*) fullPath;
+- (void) write:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+- (void) testFileExists:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+- (void) testDirectoryExists:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+//- (void) createDirectory:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+//- (void) deleteDirectory:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+//- (void) deleteFile:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+- (void) getFreeDiskSpace:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+- (void) truncateFile:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+
+
+
+//- (BOOL) fileExists:(NSString*)fileName;
+//- (BOOL) directoryExists:(NSString*)dirName;
+- (void) writeToFile:(NSString*)fileName withData:(NSString*)data append:(BOOL)shouldAppend callback: (NSString*) callbackId;
+- (unsigned long long) truncateFile:(NSString*)filePath atPosition:(unsigned long long)pos;
+
+
+@property (nonatomic, retain)NSString *appDocsPath;
+@property (nonatomic, retain)NSString *appLibraryPath;
+@property (nonatomic, retain)NSString *appTempPath;
+@property (nonatomic, retain)NSString *persistentPath;
+@property (nonatomic, retain)NSString *temporaryPath;
+@property BOOL userHasAllowed;
+
+@end
+
+#define kW3FileTemporary @"temporary"
+#define kW3FilePersistent @"persistent"
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/bcff9559/CordovaLib/Classes/CDVFile.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVFile.m b/CordovaLib/Classes/CDVFile.m
new file mode 100644
index 0000000..5ad3867
--- /dev/null
+++ b/CordovaLib/Classes/CDVFile.m
@@ -0,0 +1,1241 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+
+#import "CDVFile.h"
+#import "NSDictionary+Extensions.h"
+#import "JSONKit.h"
+#import "NSData+Base64.h"
+#import <MobileCoreServices/MobileCoreServices.h>
+
+
+@implementation CDVFile
+
+@synthesize appDocsPath, appLibraryPath, appTempPath, persistentPath, temporaryPath, userHasAllowed;
+
+
+
+-(id)initWithWebView:(UIWebView *)theWebView
+{
+	self = (CDVFile*)[super initWithWebView:theWebView];
+	if(self)
+	{
+		// get the documents directory path
+		NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+		self.appDocsPath = [paths objectAtIndex:0];
+		
+		paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
+		self.appLibraryPath = [paths objectAtIndex:0];
+		
+		self.appTempPath =  [NSTemporaryDirectory() stringByStandardizingPath]; // remove trailing slash from NSTemporaryDirectory()
+		
+		self.persistentPath = [NSString stringWithFormat: @"/%@",[self.appDocsPath lastPathComponent]];
+		self.temporaryPath = [NSString stringWithFormat: @"/%@",[self.appTempPath lastPathComponent]];
+		//NSLog(@"docs: %@ - temp: %@", self.appDocsPath, self.appTempPath);
+	}
+	
+	return self;
+}
+- (NSNumber*) checkFreeDiskSpace: (NSString*) appPath
+{
+	NSFileManager* fMgr = [[NSFileManager alloc] init];
+	
+	NSError* pError = nil;
+	
+	NSDictionary* pDict = [ fMgr attributesOfFileSystemForPath:appPath error:&pError ];
+	NSNumber* pNumAvail = (NSNumber*)[ pDict objectForKey:NSFileSystemFreeSize ];
+	[fMgr release];
+	return pNumAvail;
+	
+}
+// figure out if the pathFragment represents a persistent of temporary directory and return the full application path.
+// returns nil if path is not persistent or temporary
+-(NSString*) getAppPath: (NSString*)pathFragment
+{
+	NSString* appPath = nil;
+	NSRange rangeP = [pathFragment rangeOfString:self.persistentPath];
+	NSRange rangeT = [pathFragment rangeOfString:self.temporaryPath];
+	
+	if (rangeP.location != NSNotFound && rangeT.location != NSNotFound){
+		// we found both in the path, return whichever one is first
+		if (rangeP.length < rangeT.length) {
+			appPath = self.appDocsPath;
+		}else {
+			appPath = self.appTempPath;
+		}
+	} else if (rangeP.location != NSNotFound) {
+		appPath = self.appDocsPath;
+	} else if (rangeT.location != NSNotFound){
+		appPath = self.appTempPath;
+	}
+	return appPath;
+}
+/* get the full path to this resource
+ * IN
+ *	NSString* pathFragment - full Path from File or Entry object (includes system path info)
+ * OUT
+ *	NSString* fullPath - full iOS path to this resource,  nil if not found
+ */
+/*  Was here in order to NOT have to return full path, but W3C synchronous DirectoryEntry.toURI() killed that idea since I can't call into iOS to 
+ * resolve full URI.  Leaving this code here in case W3C spec changes. 
+-(NSString*) getFullPath: (NSString*)pathFragment
+{
+	return pathFragment;
+	NSString* fullPath = nil;
+	NSString *appPath = [ self getAppPath: pathFragment];
+	if (appPath){
+
+		// remove last component from appPath
+		NSRange range = [appPath rangeOfString:@"/" options: NSBackwardsSearch];
+		NSString* newPath = [appPath substringToIndex:range.location];
+		// add pathFragment to get test Path
+		fullPath = [newPath stringByAppendingPathComponent:pathFragment];
+	}
+	return fullPath;
+} */
+
+/* Request the File System info
+ *
+ * IN:
+ * arguments[0] - type (number as string)
+ *	TEMPORARY = 0, PERSISTENT = 1;
+ * arguments[1] - size
+ *
+ * OUT:
+ *	Dictionary representing FileSystem object
+ *		name - the human readable directory name
+ *		root = DirectoryEntry object
+ *			bool isDirectory
+ *			bool isFile
+ *			string name
+ *			string fullPath
+ *			fileSystem = FileSystem object - !! ignored because creates circular reference !!
+ */
+
+- (void) requestFileSystem:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments pop];
+    VERIFY_ARGUMENTS(arguments, 2, callbackId)
+    
+    // arguments
+	NSString* strType = [arguments objectAtIndex: 0];
+	unsigned long long size = [[arguments objectAtIndex:1] longLongValue];
+
+	int type = [strType intValue];
+	CDVPluginResult* result = nil;
+	NSString* jsString = nil;
+	
+	if (type > 1){
+		result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsInt: NOT_FOUND_ERR cast: @"window.localFileSystem._castError"];
+		jsString = [result toErrorCallbackString:callbackId];
+		NSLog(@"iOS only supports TEMPORARY and PERSISTENT file systems");
+	} else {
+		
+		//NSString* fullPath = [NSString stringWithFormat:@"/%@", (type == 0 ? [self.appTempPath lastPathComponent] : [self.appDocsPath lastPathComponent])];
+		NSString* fullPath = (type == 0 ? self.appTempPath  : self.appDocsPath);
+		// check for avail space for size request
+		NSNumber* pNumAvail = [self checkFreeDiskSpace: fullPath];
+		//NSLog(@"Free space: %@", [NSString stringWithFormat:@"%qu", [ pNumAvail unsignedLongLongValue ]]);
+		if (pNumAvail && [pNumAvail unsignedLongLongValue] < size) {
+			result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsInt: QUOTA_EXCEEDED_ERR cast: @"window.localFileSystem._castError"];
+			jsString = [result toErrorCallbackString:callbackId];
+		} 
+		else {
+			NSMutableDictionary* fileSystem = [NSMutableDictionary dictionaryWithCapacity:2];
+			[fileSystem setObject: (type == TEMPORARY ? kW3FileTemporary : kW3FilePersistent)forKey:@"name"];
+			NSDictionary* dirEntry = [self getDirectoryEntry: fullPath isDirectory: YES];
+			[fileSystem setObject:dirEntry forKey:@"root"];
+			result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsDictionary: fileSystem cast: @"window.localFileSystem._castFS"];
+			jsString = [result toSuccessCallbackString:callbackId];
+		}
+	}
+	[self writeJavascript: jsString];
+	
+}
+/* Creates a dictionary representing an Entry Object
+ *
+ * IN:
+ * NSString* fullPath of the entry 
+ * FileSystem type 
+ * BOOL isDirectory - YES if this is a directory, NO if is a file
+ * OUT:
+ * NSDictionary*
+ Entry object
+ *		bool as NSNumber isDirectory
+ *		bool as NSNumber isFile
+ *		NSString*  name - last part of path
+ *		NSString* fullPath
+ *		fileSystem = FileSystem object - !! ignored because creates circular reference FileSystem contains DirectoryEntry which contains FileSystem.....!!
+ */
+-(NSDictionary*) getDirectoryEntry: (NSString*) fullPath  isDirectory: (BOOL) isDir
+{
+	
+	NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:4];
+	NSString* lastPart = [fullPath lastPathComponent];
+	
+	
+	
+	[dirEntry setObject:[NSNumber numberWithBool: !isDir]  forKey:@"isFile"];
+	[dirEntry setObject:[NSNumber numberWithBool: isDir]  forKey:@"isDirectory"];
+	//NSURL* fileUrl = [NSURL fileURLWithPath:fullPath];
+	//[dirEntry setObject: [fileUrl absoluteString] forKey: @"fullPath"];
+	[dirEntry setObject: fullPath forKey: @"fullPath"];
+	[dirEntry setObject: lastPart forKey:@"name"];
+	
+	
+	return dirEntry;
+	
+}
+/*
+ * Given a URI determine the File System information associated with it and return an appropriate W3C entry object
+ * IN
+ *	NSString* fileURI  - currently requires full file URI 
+ * OUT
+ *	Entry object
+ *		bool isDirectory
+ *		bool isFile
+ *		string name
+ *		string fullPath
+ *		fileSystem = FileSystem object - !! ignored because creates circular reference FileSystem contains DirectoryEntry which contains FileSystem.....!!
+ */
+- (void) resolveLocalFileSystemURI:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments pop];
+    VERIFY_ARGUMENTS(arguments, 1, callbackId)
+    
+    // arguments
+    NSString* inputUri = [arguments objectAtIndex:0];
+    
+	NSString* jsString = nil;
+    
+    // don't know if string is encoded or not so unescape 
+    NSString* cleanUri = [inputUri stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+	// now escape in order to create URL
+    NSString* strUri = [cleanUri stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
+	NSURL* testUri = [NSURL URLWithString:strUri];  
+	CDVPluginResult* result = nil;
+	
+	if (!testUri || ![testUri isFileURL]) {
+		// issue ENCODING_ERR
+		result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsInt: ENCODING_ERR cast: @"window.localFileSystem._castError"];
+		jsString = [result toErrorCallbackString:callbackId];
+	} else {
+		NSFileManager* fileMgr = [[NSFileManager alloc] init];
+		NSString* path = [testUri path];
+		//NSLog(@"url path: %@", path);
+		BOOL	isDir = NO;
+		// see if exists and is file or dir
+		BOOL bExists = [fileMgr fileExistsAtPath:path isDirectory: &isDir];
+		if (bExists) {
+			// see if it contains docs path
+			NSRange range = [path rangeOfString:self.appDocsPath];
+			NSString* foundFullPath = nil;
+			// there's probably an api or easier way to figure out the path type but I can't find it!
+			if (range.location != NSNotFound &&  range.length == [self.appDocsPath length]){
+				foundFullPath = self.appDocsPath;
+			}else {
+				// see if it contains the temp path
+				range = [path rangeOfString:self.appTempPath];
+				if (range.location != NSNotFound && range.length == [self.appTempPath length]){
+					foundFullPath = self.appTempPath;
+				}
+			}
+			if (foundFullPath == nil) {
+				// error SECURITY_ERR - not one of the two paths types supported
+				result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsInt: SECURITY_ERR cast: @"window.localFileSystem._castError"];
+				jsString = [result toErrorCallbackString:callbackId];
+			} else {
+				NSDictionary* fileSystem = [self getDirectoryEntry: path isDirectory: isDir];
+				result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary: fileSystem cast: @"window.localFileSystem._castEntry"];
+				jsString = [result toSuccessCallbackString:callbackId];
+								
+			}
+		
+		} else {
+			// return NOT_FOUND_ERR
+			result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsInt: NOT_FOUND_ERR cast: @"window.localFileSystem._castError"];
+			jsString = [result toErrorCallbackString:callbackId];
+			
+		}
+
+		[fileMgr release];
+	}
+	if (jsString != nil){
+		[self writeJavascript:jsString];
+	}
+
+}
+/* Part of DirectoryEntry interface,  creates or returns the specified directory
+ * IN:
+ *	NSString* fullPath - full path for this directory 
+ *	NSString* path - directory to be created/returned; may be full path or relative path
+ *	NSDictionary* - Flags object
+ *		boolean as NSNumber create - 
+ *			if create is true and directory does not exist, create dir and return directory entry
+ *			if create is true and exclusive is true and directory does exist, return error
+ *			if create is false and directory does not exist, return error
+ *			if create is false and the path represents a file, return error
+ *		boolean as NSNumber exclusive - used in conjunction with create
+ *			if exclusive is true and create is true - specifies failure if directory already exists
+ *			
+ *			
+ */
+- (void) getDirectory:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	// add getDir to options and call getFile()
+	if (!options){
+		options = [NSMutableDictionary dictionaryWithCapacity:1];
+	}
+	[options setObject:[NSNumber numberWithInt:1] forKey:@"getDir"];
+	
+	[self getFile: arguments withDict: options];
+
+
+}
+/* Part of DirectoryEntry interface,  creates or returns the specified file
+ * IN:
+ *	NSString* fullPath - full path for this file 
+ *	NSString* path - file to be created/returned; may be full path or relative path
+ *	NSDictionary* - Flags object
+ *		boolean as NSNumber create - 
+ *			if create is true and file does not exist, create file and return File entry
+ *			if create is true and exclusive is true and file does exist, return error
+ *			if create is false and file does not exist, return error
+ *			if create is false and the path represents a directory, return error
+ *		boolean as NSNumber exclusive - used in conjunction with create
+ *			if exclusive is true and create is true - specifies failure if file already exists
+ *			
+ *			
+ */
+- (void) getFile: (NSMutableArray*) arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments pop];
+    VERIFY_ARGUMENTS(arguments, 2, callbackId)
+    
+	// arguments are URL encoded
+	NSString* fullPath = [arguments objectAtIndex:0];
+	NSString* requestedPath = [arguments objectAtIndex:1];
+    
+	NSString* jsString = nil;
+	CDVPluginResult* result = nil;
+	BOOL bDirRequest = NO;
+	BOOL create = NO;
+	BOOL exclusive = NO;
+	int errorCode = 0;  // !!! risky - no error code currently defined for 0
+	
+	if ([options valueForKeyIsNumber:@"create"]) {
+		create = [(NSNumber*)[options valueForKey: @"create"] boolValue];
+	}
+	if ([options valueForKeyIsNumber:@"exclusive"]) {
+		exclusive = [(NSNumber*)[options valueForKey: @"exclusive"] boolValue];
+	}
+	
+	if ([options valueForKeyIsNumber:@"getDir"]) {
+		// this will not exist for calls directly to getFile but will have been set by getDirectory before calling this method
+		bDirRequest = [(NSNumber*)[options valueForKey: @"getDir"] boolValue];
+	}
+	// see if the requested path has invalid characters - should we be checking for  more than just ":"?
+	if ([requestedPath rangeOfString: @":"].location != NSNotFound) {
+		errorCode = ENCODING_ERR;
+	}	else {
+			
+		// was full or relative path provided?
+		NSRange range = [requestedPath rangeOfString:fullPath];
+		BOOL bIsFullPath = range.location != NSNotFound;
+		
+		NSString* reqFullPath = nil;
+		
+		if (!bIsFullPath) {
+			reqFullPath = [fullPath stringByAppendingPathComponent:requestedPath];
+		} else {
+			reqFullPath = requestedPath;
+		}
+		
+		//NSLog(@"reqFullPath = %@", reqFullPath);
+		NSFileManager* fileMgr = [[NSFileManager alloc] init];
+		BOOL bIsDir;
+		BOOL bExists = [fileMgr fileExistsAtPath: reqFullPath isDirectory: &bIsDir];
+		if (bExists && create == NO && bIsDir == !bDirRequest) {
+			// path exists and is of requested type  - return TYPE_MISMATCH_ERR
+			errorCode = TYPE_MISMATCH_ERR;
+		} else if (!bExists && create == NO) {
+			// path does not exist and create is false - return NOT_FOUND_ERR
+			errorCode = NOT_FOUND_ERR;
+		} else if (bExists && create == YES && exclusive == YES) {
+			// file/dir already exists and exclusive and create are both true - return PATH_EXISTS_ERR
+			errorCode = PATH_EXISTS_ERR;
+		} else { 
+			// if bExists and create == YES - just return data
+			// if bExists and create == NO  - just return data
+			// if !bExists and create == YES - create and return data
+			BOOL bSuccess = YES;
+			NSError* pError = nil;
+			if(!bExists && create == YES){
+				if(bDirRequest) {
+					// create the dir
+					bSuccess = [ fileMgr createDirectoryAtPath:reqFullPath withIntermediateDirectories:NO attributes:nil error:&pError];
+				} else {
+					// create the empty file
+					bSuccess = [ fileMgr createFileAtPath:reqFullPath contents: nil attributes:nil];
+				}
+			}
+			if(!bSuccess){
+				errorCode = ABORT_ERR;
+				if (pError) {
+					NSLog(@"error creating directory: %@", [pError localizedDescription]);
+				}
+			} else {
+				//NSLog(@"newly created file/dir (%@) exists: %d", reqFullPath, [fileMgr fileExistsAtPath:reqFullPath]);
+				// file existed or was created
+				result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsDictionary: [self getDirectoryEntry: reqFullPath isDirectory: bDirRequest] cast: @"window.localFileSystem._castEntry"];
+				jsString = [result toSuccessCallbackString: callbackId];
+			}
+		} // are all possible conditions met?
+		[fileMgr release];
+	} 
+
+	
+	if (errorCode > 0) {
+		// create error callback
+		result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsInt: errorCode cast: @"window.localFileSystem._castError"];
+		jsString = [result toErrorCallbackString:callbackId];
+	}
+	
+	
+	
+	[self writeJavascript:jsString];
+}
+/* 
+ * Look up the parent Entry containing this Entry. 
+ * If this Entry is the root of its filesystem, its parent is itself.
+ * IN: 
+ * NSArray* arguments
+ *	0 - NSString* callbackId
+ *	1 - NSString* fullPath
+ * NSMutableDictionary* options
+ *	empty
+ */
+- (void) getParent:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments pop];
+    VERIFY_ARGUMENTS(arguments, 1, callbackId)
+    
+	// arguments are URL encoded
+	NSString* fullPath = [arguments objectAtIndex:0];
+    
+	CDVPluginResult* result = nil;
+	NSString* jsString = nil;
+	NSString* newPath = nil;
+	
+	
+	if ([fullPath isEqualToString:self.appDocsPath] || [fullPath isEqualToString: self.appTempPath]){
+		// return self
+		newPath = fullPath;
+		
+	} else {
+		// since this call is made from an existing Entry object - the parent should already exist so no additional error checking
+		// remove last component and return Entry
+		NSRange range = [fullPath rangeOfString:@"/" options: NSBackwardsSearch];
+		newPath = [fullPath substringToIndex:range.location];
+	}
+
+	if(newPath){
+		NSFileManager* fileMgr = [[NSFileManager alloc] init];
+		BOOL bIsDir;
+		BOOL bExists = [fileMgr fileExistsAtPath: newPath isDirectory: &bIsDir];
+		if (bExists) {
+			result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsDictionary: [self getDirectoryEntry:newPath isDirectory:bIsDir] cast: @"window.localFileSystem._castEntry"];
+			jsString = [result toSuccessCallbackString:callbackId];
+		}
+		[fileMgr release];
+	}
+	if (!jsString) {
+		// invalid path or file does not exist
+		result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsInt: NOT_FOUND_ERR cast: @"window.localFileSystem._castError"];
+		jsString = [result toErrorCallbackString: callbackId];
+	}
+	[self writeJavascript:jsString];
+
+}
+/*
+ * get MetaData of entry
+ * Currently MetaData only includes modificationTime.
+ */
+- (void) getMetadata:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments pop];
+    VERIFY_ARGUMENTS(arguments, 1, callbackId)
+    
+    // arguments
+	NSString* argPath = [arguments objectAtIndex:0];
+	NSString* testPath = argPath; //[self getFullPath: argPath];
+	
+	NSFileManager* fileMgr = [[NSFileManager alloc] init];
+	NSError* error = nil;
+	CDVPluginResult* result = nil;
+	NSString* jsString = nil;
+	
+	NSDictionary* fileAttribs = [fileMgr attributesOfItemAtPath:testPath error:&error];
+	
+	if (fileAttribs){
+		NSDate* modDate = [fileAttribs fileModificationDate];
+		if (modDate){
+			NSNumber* msDate = [NSNumber numberWithDouble:[modDate timeIntervalSince1970]*1000];
+			NSMutableDictionary* metadataDict = [NSMutableDictionary dictionaryWithCapacity:1];
+			[metadataDict setObject:msDate forKey:@"modificationTime"];
+			result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary: metadataDict cast: @"window.localFileSystem._castDate"];
+			jsString = [result toSuccessCallbackString:callbackId];
+		}
+	} else {
+		// didn't get fileAttribs
+		CDVFileError errorCode = ABORT_ERR;
+		NSLog(@"error getting metadata: %@", [error localizedDescription]);
+		if ([error code] == NSFileNoSuchFileError) {
+			errorCode = NOT_FOUND_ERR;
+		}
+		// log [NSNumber numberWithDouble: theMessage] objCtype to see what it returns
+		result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: errorCode cast: @"window.localFileSystem._castError"];
+		jsString = [result toErrorCallbackString:callbackId];
+	}
+	if (jsString){
+		[self writeJavascript:jsString];
+	}
+	[fileMgr release];
+}
+
+/* removes the directory or file entry
+ * IN: 
+ * NSArray* arguments
+ *	0 - NSString* callbackId
+ *	1 - NSString* fullPath
+ * NSMutableDictionary* options
+ *	empty
+ *
+ * returns NO_MODIFICATION_ALLOWED_ERR  if is top level directory or no permission to delete dir
+ * returns INVALID_MODIFICATION_ERR if is dir and is not empty
+ * returns NOT_FOUND_ERR if file or dir is not found
+*/
+- (void) remove:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments pop];
+    VERIFY_ARGUMENTS(arguments, 1, callbackId)
+    
+    // arguments
+	NSString* fullPath = [arguments objectAtIndex:0];
+	
+	CDVPluginResult* result = nil;
+	NSString* jsString = nil;
+	CDVFileError errorCode = 0;  // !! 0 not currently defined 
+	
+	// error if try to remove top level (documents or tmp) dir
+	if ([fullPath isEqualToString:self.appDocsPath] || [fullPath isEqualToString:self.appTempPath]){
+		errorCode = NO_MODIFICATION_ALLOWED_ERR;
+	} else {
+		NSFileManager* fileMgr = [[ NSFileManager alloc] init];
+		BOOL bIsDir = NO;
+		BOOL bExists = [fileMgr fileExistsAtPath:fullPath isDirectory: &bIsDir];
+		if (!bExists){
+			errorCode = NOT_FOUND_ERR;
+		}
+		if (bIsDir &&  [[fileMgr contentsOfDirectoryAtPath:fullPath error: nil] count] != 0) {
+			// dir is not empty
+			errorCode = INVALID_MODIFICATION_ERR;
+		}
+		[fileMgr release];
+	}
+	if (errorCode > 0) {
+		result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: errorCode cast:@"window.localFileSystem._castError"];
+		jsString = [result toErrorCallbackString:callbackId];
+	} else {
+		// perform actual remove
+		jsString = [self doRemove: fullPath callback: callbackId];
+	}
+	[self writeJavascript:jsString];
+
+}
+/* recurvsively removes the directory 
+ * IN: 
+ * NSArray* arguments
+ *	0 - NSString* callbackId
+ *	1 - NSString* fullPath
+ * NSMutableDictionary* options
+ *	empty
+ *
+ * returns NO_MODIFICATION_ALLOWED_ERR  if is top level directory or no permission to delete dir
+ * returns NOT_FOUND_ERR if file or dir is not found
+ */
+- (void) removeRecursively:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments pop];
+    VERIFY_ARGUMENTS(arguments, 1, callbackId)
+    
+    // arguments
+	NSString* fullPath = [arguments objectAtIndex:0];
+	
+	CDVPluginResult* result = nil;
+	NSString* jsString = nil;
+	
+	// error if try to remove top level (documents or tmp) dir
+	if ([fullPath isEqualToString:self.appDocsPath] || [fullPath isEqualToString:self.appTempPath]){
+		result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: NO_MODIFICATION_ALLOWED_ERR cast:@"window.localFileSystem._castError"];
+		jsString = [result toErrorCallbackString:callbackId];
+	} else {
+		jsString = [self doRemove: fullPath callback: callbackId];
+	}
+	
+	[self writeJavascript:jsString];
+
+}
+/* remove the file or directory (recursively)
+ * IN:
+ * NSString* fullPath - the full path to the file or directory to be removed
+ * NSString* callbackId
+ * called from remove and removeRecursively - check all pubic api specific error conditions (dir not empty, etc) before calling
+ */
+
+- (NSString*) doRemove:(NSString*)fullPath callback: (NSString*)callbackId
+{
+	CDVPluginResult* result = nil;
+	NSString* jsString = nil;
+	BOOL bSuccess = NO;
+	NSError* pError = nil;
+	NSFileManager* fileMgr = [[ NSFileManager alloc] init];
+
+	@try {
+		bSuccess = [ fileMgr removeItemAtPath:fullPath error:&pError];
+		if (bSuccess) {
+			CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK ];
+			jsString = [result toSuccessCallbackString:callbackId];
+		} else {
+			// see if we can give a useful error
+			CDVFileError errorCode = ABORT_ERR;
+			NSLog(@"error getting metadata: %@", [pError localizedDescription]);
+			if ([pError code] == NSFileNoSuchFileError) {
+				errorCode = NOT_FOUND_ERR;
+			} else if ([pError code] == NSFileWriteNoPermissionError) {
+				errorCode = NO_MODIFICATION_ALLOWED_ERR;
+			}
+			
+			result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: errorCode cast: @"window.localFileSystem._castError"];
+			jsString = [result toErrorCallbackString:callbackId];
+		}
+	} @catch (NSException* e) { // NSInvalidArgumentException if path is . or ..
+		result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: SYNTAX_ERR cast: @"window.localFileSystem._castError"];
+		jsString = [result toErrorCallbackString:callbackId];	
+	}
+	@finally {
+		[fileMgr release];
+		return jsString;
+	}
+}
+- (void) copyTo:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	[self doCopyMove:arguments withDict:options isCopy:YES];
+}
+- (void) moveTo:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	[self doCopyMove:arguments withDict:options isCopy:NO];
+}
+/**
+ * Helpfer function to check to see if the user attempted to copy an entry into its parent without changing its name, 
+ * or attempted to copy a directory into a directory that it contains directly or indirectly.
+ * 
+ * IN: 
+ *  NSString* srcDir
+ *  NSString* destinationDir
+ * OUT:
+ *  YES copy/ move is allows
+ *  NO move is onto itself
+ */	
+-(BOOL) canCopyMoveSrc: (NSString*) src ToDestination: (NSString*) dest
+{
+    // This weird test is to determine if we are copying or moving a directory into itself.  
+    // Copy /Documents/myDir to /Documents/myDir-backup is okay but
+    // Copy /Documents/myDir to /Documents/myDir/backup not okay
+    BOOL copyOK = YES;
+    NSRange range = [dest rangeOfString:src];
+    
+    if (range.location != NSNotFound) {
+        NSRange testRange = {range.length-1, ([dest length] - range.length)};
+        NSRange resultRange = [dest rangeOfString: @"/" options: 0 range: testRange];
+        if (resultRange.location != NSNotFound){
+            copyOK = NO;
+        }
+    }
+    return copyOK;
+    
+}
+/* Copy/move a file or directory to a new location
+ * IN: 
+ * NSArray* arguments
+ *	0 - NSString* callbackId
+ *	1 - NSString* fullPath of entry
+ *  2 - NSString* newName the new name of the entry, defaults to the current name
+ *	NSMutableDictionary* options - DirectoryEntry to which to copy the entry
+ *	BOOL - bCopy YES if copy, NO if move
+ * 
+ */
+- (void) doCopyMove:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options  isCopy:(BOOL)bCopy
+{
+	NSString* callbackId = [arguments pop];
+    VERIFY_ARGUMENTS(arguments, 1, callbackId)
+    
+	// arguments
+    NSString* srcFullPath = [arguments objectAtIndex:0];
+    // optional argument
+    NSString* newName = ([arguments count] > 1) ? [arguments objectAtIndex:1] : [srcFullPath lastPathComponent]; 		// use last component from appPath if new name not provided
+
+	CDVPluginResult* result = nil;
+	NSString* jsString = nil;
+	CDVFileError errCode = 0;  // !! Currently 0 is not defined, use this to signal error !!
+		
+	NSString* destRootPath = nil;
+	NSString* key = @"fullPath";
+	if([options valueForKeyIsString:key]){
+	   destRootPath = [options objectForKey:@"fullPath"];
+	}
+	
+	if (!destRootPath) {
+		// no destination provided
+		errCode = NOT_FOUND_ERR;
+	} else if ([newName rangeOfString: @":"].location != NSNotFound) {
+		// invalid chars in new name
+		errCode = ENCODING_ERR;
+	} else {
+		NSString* newFullPath = [destRootPath stringByAppendingPathComponent: newName];
+		if ( [newFullPath isEqualToString:srcFullPath] ){
+			// source and destination can not be the same 
+			errCode = INVALID_MODIFICATION_ERR;
+		} else {
+			NSFileManager* fileMgr = [[NSFileManager alloc] init];
+			
+			BOOL bSrcIsDir = NO;
+			BOOL bDestIsDir = NO;
+			BOOL bNewIsDir = NO;
+			BOOL bSrcExists = [fileMgr fileExistsAtPath: srcFullPath isDirectory: &bSrcIsDir];
+			BOOL bDestExists= [fileMgr fileExistsAtPath: destRootPath isDirectory: &bDestIsDir];
+			BOOL bNewExists = [fileMgr fileExistsAtPath:newFullPath isDirectory: &bNewIsDir];
+			if (!bSrcExists || !bDestExists) {
+				// the source or the destination root does not exist
+				errCode = NOT_FOUND_ERR;
+			} else if (bSrcIsDir && (bNewExists && !bNewIsDir)) {
+				// can't copy/move dir to file 
+				errCode = INVALID_MODIFICATION_ERR;
+			} else { // no errors yet
+				NSError* error = nil;
+				BOOL bSuccess = NO;
+				if (bCopy){
+					if (bSrcIsDir && ![self canCopyMoveSrc: srcFullPath ToDestination: newFullPath]/*[newFullPath hasPrefix:srcFullPath]*/) {
+						// can't copy dir into self
+						errCode = INVALID_MODIFICATION_ERR;
+					} else if (bNewExists) {
+						// the full destination should NOT already exist if a copy
+						errCode = PATH_EXISTS_ERR;
+					}  else {
+						bSuccess = [fileMgr copyItemAtPath: srcFullPath toPath: newFullPath error: &error];
+					}
+				} else { // move 
+					// iOS requires that destination must not exist before calling moveTo
+					// is W3C INVALID_MODIFICATION_ERR error if destination dir exists and has contents
+					// 
+					if (!bSrcIsDir && (bNewExists && bNewIsDir)){
+						// can't move a file to directory
+						errCode = INVALID_MODIFICATION_ERR;
+					} else if (bSrcIsDir && ![self canCopyMoveSrc: srcFullPath ToDestination: newFullPath] ) { //[newFullPath hasPrefix:srcFullPath]){
+						// can't move a dir into itself
+						errCode = INVALID_MODIFICATION_ERR;	
+					} else if (bNewExists) {
+						if (bNewIsDir && [[fileMgr contentsOfDirectoryAtPath:newFullPath error: NULL] count] != 0){
+							// can't move dir to a dir that is not empty
+							errCode = INVALID_MODIFICATION_ERR;
+							newFullPath = nil;  // so we won't try to move
+						} else {
+							// remove destination so can perform the moveItemAtPath
+							bSuccess = [fileMgr removeItemAtPath:newFullPath error: NULL];
+							if (!bSuccess) {
+								errCode = INVALID_MODIFICATION_ERR; // is this the correct error?
+								newFullPath = nil;
+							}
+						}
+					} else if (bNewIsDir && [newFullPath hasPrefix:srcFullPath]) {
+						// can't move a directory inside itself or to any child at any depth;
+						errCode = INVALID_MODIFICATION_ERR;
+						newFullPath = nil;
+					}
+						
+					if (newFullPath != nil) {
+						bSuccess = [fileMgr moveItemAtPath: srcFullPath toPath: newFullPath error: &error];
+					}
+				}
+				if (bSuccess) {
+					// should verify it is there and of the correct type???
+					NSDictionary* newEntry = [self getDirectoryEntry: newFullPath isDirectory:bSrcIsDir]; //should be the same type as source
+					result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary: newEntry cast: @"window.localFileSystem._castEntry"];
+					jsString = [result toSuccessCallbackString:callbackId];
+				}
+				else {
+					errCode = INVALID_MODIFICATION_ERR; // catch all
+					if (error) {
+						if ([error code] == NSFileReadUnknownError || [error code] == NSFileReadTooLargeError) {
+							errCode = NOT_READABLE_ERR;
+						} else if ([error code] == NSFileWriteOutOfSpaceError){
+							errCode = QUOTA_EXCEEDED_ERR;
+						} else if ([error code] == NSFileWriteNoPermissionError){
+							errCode = NO_MODIFICATION_ALLOWED_ERR;
+						}
+					}
+				}			
+			}
+			[fileMgr release];	
+		}
+	}
+	if (errCode > 0) {
+		result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: errCode cast: @"window.localFileSystem._castError"];
+		jsString = [result toErrorCallbackString:callbackId];
+	}
+	
+	
+	if (jsString){
+		[self writeJavascript: jsString];
+	}
+	
+}
+/* return the URI to the entry
+ * IN: 
+ * NSArray* arguments
+ *	0 - NSString* callbackId
+ *	1 - NSString* fullPath of entry
+ *	2 - desired mime type of entry - ignored - always returns file://
+ */
+/*  Not needed since W3C toURI is synchronous.  Leaving code here for now in case W3C spec changes.....
+- (void) toURI:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments objectAtIndex:0];
+	NSString* argPath = [arguments objectAtIndex:1];
+	PluginResult* result = nil;
+	NSString* jsString = nil;
+	
+	NSString* fullPath = [self getFullPath: argPath];
+	if (fullPath) {
+		// do we need to make sure the file actually exists?
+		// create file uri
+		NSString* strUri = [fullPath stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
+		NSURL* fileUrl = [NSURL fileURLWithPath:strUri];
+		if (fileUrl) {
+			result = [PluginResult resultWithStatus:PGCommandStatus_OK messageAsString: [fileUrl absoluteString]];
+			jsString = [result toSuccessCallbackString:callbackId];
+		} // else NOT_FOUND_ERR
+	}
+	if(!jsString) {
+		// was error
+		result = [PluginResult resultWithStatus:PGCommandStatus_OK messageAsInt: NOT_FOUND_ERR cast:  @"window.localFileSystem._castError"];
+		jsString = [result toErrorCallbackString:callbackId];
+	}
+	
+	[self writeJavascript:jsString];
+}*/
+- (void) getFileMetadata:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments pop];
+    VERIFY_ARGUMENTS(arguments, 1, callbackId)
+    
+    // arguments
+	NSString* argPath = [arguments objectAtIndex:0];
+    
+	CDVPluginResult* result = nil;
+	NSString* jsString = nil;
+	
+	NSString* fullPath = argPath; //[self getFullPath: argPath];
+	if (fullPath) {
+		NSFileManager* fileMgr = [[NSFileManager alloc] init];
+		BOOL bIsDir = NO;
+		// make sure it exists and is not a directory
+		BOOL bExists = [fileMgr fileExistsAtPath:fullPath isDirectory: &bIsDir];
+		if(!bExists || bIsDir){
+			result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: NOT_FOUND_ERR cast:@"window.localFileSystem._castError"];
+			jsString = [result toErrorCallbackString:callbackId];
+		} else {
+			// create dictionary of file info
+			NSError* error = nil;
+			NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:fullPath error:&error];
+			NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
+			[fileInfo setObject: [NSNumber numberWithUnsignedLongLong:[fileAttrs fileSize]] forKey:@"size"];
+			[fileInfo setObject:argPath forKey:@"fullPath"];
+			[fileInfo setObject: @"" forKey:@"type"]; // can't easily get the mimetype unless create URL, send request and read response so skipping
+			[fileInfo setObject: [argPath lastPathComponent] forKey:@"name"];
+			NSDate* modDate = [fileAttrs fileModificationDate];
+			NSNumber* msDate = [NSNumber numberWithDouble:[modDate timeIntervalSince1970]*1000];
+			[fileInfo setObject:msDate forKey:@"lastModifiedDate"];
+			result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary: fileInfo cast: @"window.localFileSystem._castDate"];
+			jsString = [result toSuccessCallbackString:callbackId];
+		}
+		[fileMgr release];
+	}
+	
+	[self writeJavascript:jsString];
+}
+
+- (void) readEntries:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments pop];
+    VERIFY_ARGUMENTS(arguments, 1, callbackId)
+
+	// arguments
+    NSString* fullPath = [arguments objectAtIndex:0];
+	
+	CDVPluginResult* result = nil;
+	NSString* jsString = nil;
+	
+	NSFileManager* fileMgr = [[ NSFileManager alloc] init];
+	NSError* error = nil;
+	NSArray* contents = [fileMgr contentsOfDirectoryAtPath:fullPath error: &error];
+	if (contents) {
+		NSMutableArray* entries = [NSMutableArray arrayWithCapacity:1];
+		if ([contents count] > 0){
+			// create an Entry (as JSON) for each file/dir
+			for (NSString* name in contents) {
+				// see if is dir or file
+				NSString* entryPath = [fullPath stringByAppendingPathComponent:name];
+				BOOL bIsDir = NO;
+				[fileMgr fileExistsAtPath:entryPath isDirectory: &bIsDir];
+				NSDictionary* entryDict = [self getDirectoryEntry:entryPath isDirectory:bIsDir];
+				[entries addObject:entryDict];
+			}
+		}
+		result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray: entries cast: @"window.localFileSystem._castEntries"];
+		jsString = [result toSuccessCallbackString:callbackId];
+	} else {
+		// assume not found but could check error for more specific error conditions
+		result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: NOT_FOUND_ERR cast: @"window.localFileSystem._castError"];
+		jsString = [result toErrorCallbackString:callbackId];
+	} 
+
+	[fileMgr release];
+	
+	[self writeJavascript: jsString];
+	
+}
+/* read and return file data 
+ * IN: 
+ * NSArray* arguments
+ *	0 - NSString* callbackId
+ *	1 - NSString* fullPath
+ *	2 - NSString* encoding - NOT USED,  iOS reads and writes using UTF8!
+ * NSMutableDictionary* options
+ *	empty
+ */
+- (void) readFile:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments pop];
+    VERIFY_ARGUMENTS(arguments, 1, callbackId)
+    
+    // arguments
+	NSString* argPath = [arguments objectAtIndex:0];
+    
+	//NSString* encoding = [arguments objectAtIndex:2];   // not currently used
+	CDVPluginResult* result = nil;
+	NSString* jsString = nil;
+	
+	NSFileHandle* file = [ NSFileHandle fileHandleForReadingAtPath:argPath];
+	
+	if(!file){
+		// invalid path entry
+		result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: NOT_FOUND_ERR cast: @"window.localFileSystem._castError"];
+		jsString = [result toErrorCallbackString:callbackId];
+	} else {
+		NSData* readData = [ file readDataToEndOfFile];
+		
+		[file closeFile];
+        NSString* pNStrBuff = nil;
+		if (readData) {
+            pNStrBuff = [[NSString alloc] initWithBytes: [readData bytes] length: [readData length] encoding: NSUTF8StringEncoding];
+        } else {
+            // return empty string if no data
+            pNStrBuff = [[NSString alloc] initWithString: @""];
+        }
+        
+        
+        result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsString: [ pNStrBuff stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] ];
+        jsString = [result toSuccessCallbackString:callbackId];
+        [ pNStrBuff release ];
+        
+		
+	}
+	if (jsString){
+		[self writeJavascript: jsString];
+	}
+	
+
+}
+/* Read content of text file and return as base64 encoded data url.
+ * IN: 
+ * NSArray* arguments
+ *	0 - NSString* callbackId
+ *	1 - NSString* fullPath
+ * NSMutableDictionary* options
+ *	empty
+ * 
+ * Determines the mime type from the file extension, returns ENCODING_ERR if mimetype can not be determined. 
+ */
+ 
+- (void) readAsDataURL:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments pop];
+    VERIFY_ARGUMENTS(arguments, 1, callbackId)
+    
+    // arguments
+	NSString* argPath = [arguments objectAtIndex:0];
+    
+	CDVFileError errCode = ABORT_ERR; 
+	CDVPluginResult* result = nil;
+	NSString* jsString = nil;
+	
+	if(!argPath){
+		errCode = SYNTAX_ERR;
+	} else {
+		NSString* mimeType = [self getMimeTypeFromPath:argPath];
+		if (!mimeType) {
+			// can't return as data URL if can't figure out the mimeType
+			errCode = ENCODING_ERR;
+		} else {
+			NSFileHandle* file = [ NSFileHandle fileHandleForReadingAtPath:argPath];
+			NSData* readData = [ file readDataToEndOfFile];
+			[file closeFile];
+			if (readData) {
+				NSString* output = [NSString stringWithFormat:@"data:%@;base64,%@", mimeType, [readData base64EncodedString]];
+				result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: output];
+				jsString = [result toSuccessCallbackString:callbackId];
+			} else {
+				errCode = NOT_FOUND_ERR;
+			}
+		}
+	}
+	if (!jsString){
+		result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: errCode cast: @"window.localFileSystem._castError"];
+		jsString = [result toErrorCallbackString:callbackId];
+	}
+	//NSLog(@"readAsDataURL return: %@", jsString);
+	[self writeJavascript:jsString];
+		
+	
+}
+/* helper function to get the mimeType from the file extension
+ * IN:
+ *	NSString* fullPath - filename (may include path)
+ * OUT:
+ *	NSString* the mime type as type/subtype.  nil if not able to determine
+ */
+-(NSString*) getMimeTypeFromPath: (NSString*) fullPath
+{	
+	
+	NSString* mimeType = nil;
+	if(fullPath) {
+		CFStringRef typeId = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,(CFStringRef)[fullPath pathExtension], NULL);
+		if (typeId) {
+			mimeType = (NSString*)UTTypeCopyPreferredTagWithClass(typeId,kUTTagClassMIMEType);
+			if (mimeType) {
+				[mimeType autorelease];
+				//NSLog(@"mime type: %@", mimeType);
+			} else {
+                // special case for m4a
+                if ([(NSString*)typeId rangeOfString: @"m4a-audio"].location != NSNotFound){
+                    mimeType = @"audio/mp4";
+                } else if ([[fullPath pathExtension] rangeOfString:@"wav"].location != NSNotFound){
+                    mimeType = @"audio/wav";
+                }
+            }
+			CFRelease(typeId);
+		}
+	}
+	return mimeType;
+}
+
+- (void) truncateFile:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments pop];
+    VERIFY_ARGUMENTS(arguments, 2, callbackId)
+    
+    // arguments
+	NSString* argPath = [arguments objectAtIndex:0];
+	unsigned long long pos = (unsigned long long)[[arguments objectAtIndex:1 ] longLongValue];
+	
+	NSString *appFile = argPath; //[self getFullPath:argPath];
+	
+	unsigned long long newPos = [ self truncateFile:appFile atPosition:pos];
+	CDVPluginResult* result = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsInt: newPos];
+	[self writeJavascript:[result toSuccessCallbackString: callbackId]];
+	 
+}
+
+- (unsigned long long) truncateFile:(NSString*)filePath atPosition:(unsigned long long)pos
+{
+
+	unsigned long long newPos = 0UL;
+	
+	NSFileHandle* file = [ NSFileHandle fileHandleForWritingAtPath:filePath];
+	if(file)
+	{
+		[file truncateFileAtOffset:(unsigned long long)pos];
+		newPos = [ file offsetInFile];
+		[ file synchronizeFile];
+		[ file closeFile];
+	}
+	return newPos;
+} 
+
+/* write
+ * IN:
+ * NSArray* arguments
+ *  0 - NSString* callbackId
+ *  1 - NSString* file path to write to
+ *  2 - NSString* data to write
+ *  3 - NSNumber* position to begin writing 
+ */
+- (void) write:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments pop];
+    VERIFY_ARGUMENTS(arguments, 3, callbackId)
+    
+    // arguments
+	NSString* argPath = [arguments objectAtIndex:0];
+	NSString* argData = [arguments objectAtIndex:1];
+	unsigned long long pos = (unsigned long long)[[ arguments objectAtIndex:2] longLongValue];
+	
+	NSString* fullPath = argPath; //[self getFullPath:argPath];
+	
+	[self truncateFile:fullPath atPosition:pos];
+	
+	[self writeToFile: fullPath withData:argData append:YES callback: callbackId];
+}
+- (void) writeToFile:(NSString*)filePath withData:(NSString*)data append:(BOOL)shouldAppend callback: (NSString*) callbackId
+{	
+	CDVPluginResult* result = nil;
+	NSString* jsString = nil;
+	CDVFileError errCode = INVALID_MODIFICATION_ERR; 
+	int bytesWritten = 0;
+	NSData* encData = [ data dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
+	if (filePath) {
+		NSOutputStream* fileStream = [NSOutputStream outputStreamToFileAtPath:filePath append:shouldAppend ];
+		if (fileStream) {
+			NSUInteger len = [ encData length ];
+			[ fileStream open ];
+			
+			bytesWritten = [ fileStream write:[encData bytes] maxLength:len];
+			
+			[ fileStream close ];
+			if (bytesWritten > 0) {
+				result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: bytesWritten];
+				jsString = [result toSuccessCallbackString:callbackId];
+			//} else {
+				// can probably get more detailed error info via [fileStream streamError]
+				//errCode already set to INVALID_MODIFICATION_ERR;
+				//bytesWritten = 0; // may be set to -1 on error
+			}
+		} // else fileStream not created return INVALID_MODIFICATION_ERR
+	} else {
+		// invalid filePath
+		errCode = NOT_FOUND_ERR;
+	}
+	if(!jsString) {
+		// was an error 
+		result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: errCode cast: @"window.localFileSystem._castError"];
+		jsString = [result toErrorCallbackString:callbackId];
+	}
+	[self writeJavascript: jsString];
+	
+}
+
+- (void) testFileExists:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments pop];
+    VERIFY_ARGUMENTS(arguments, 1, callbackId)
+    
+    // arguments
+	NSString* argPath = [arguments objectAtIndex:0];
+    
+	NSString* jsString = nil;
+	// Get the file manager
+	NSFileManager* fMgr = [ NSFileManager defaultManager ];
+	NSString *appFile = argPath; //[ self getFullPath: argPath];
+	
+	BOOL bExists = [fMgr fileExistsAtPath:appFile];
+	CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: ( bExists ? 1 : 0 )];
+	// keep original format of returning 0 or 1 to success  callback
+	jsString = [result toSuccessCallbackString: callbackId];
+	
+
+	[self writeJavascript: jsString];
+}
+
+- (void) testDirectoryExists:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments pop];
+    VERIFY_ARGUMENTS(arguments, 1, callbackId)
+    
+    // arguments
+	NSString* argPath = [arguments objectAtIndex:0];
+	
+	NSString* jsString = nil;
+	// Get the file manager
+	NSFileManager* fMgr = [[NSFileManager alloc] init];
+	NSString *appFile = argPath; //[self getFullPath: argPath];
+	BOOL bIsDir = NO;
+	BOOL bExists = [fMgr fileExistsAtPath:appFile isDirectory: &bIsDir];
+	
+	
+	CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt: ( (bExists && bIsDir) ? 1 : 0 )];
+	// keep original format of returning 0 or 1 to success callback
+	jsString = [result toSuccessCallbackString: callbackId];
+	[fMgr release];
+	[self writeJavascript: jsString];
+}
+
+// Returns number of bytes available via callback
+- (void) getFreeDiskSpace:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+	NSString* callbackId = [arguments pop];
+    
+    // no arguments
+    
+	NSNumber* pNumAvail = [self checkFreeDiskSpace:self.appDocsPath];
+	
+	NSString* strFreeSpace = [NSString stringWithFormat:@"%qu", [ pNumAvail unsignedLongLongValue ] ];
+	//NSLog(@"Free space is %@", strFreeSpace );
+	
+	CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: strFreeSpace];
+	[self writeJavascript:[result toSuccessCallbackString: callbackId]];
+	
+}
+
+-(void) dealloc
+{
+	self.appDocsPath = nil;
+	self.appLibraryPath = nil;
+	self.appTempPath = nil;
+	self.persistentPath = nil;
+	self.temporaryPath = nil;
+	
+	[super dealloc];
+}
+
+
+
+
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/bcff9559/CordovaLib/Classes/CDVFileTransfer.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVFileTransfer.h b/CordovaLib/Classes/CDVFileTransfer.h
new file mode 100644
index 0000000..8bcb46a
--- /dev/null
+++ b/CordovaLib/Classes/CDVFileTransfer.h
@@ -0,0 +1,62 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+
+#import <Foundation/Foundation.h>
+#import "CDVPlugin.h"
+
+enum CDVFileTransferError {
+	FILE_NOT_FOUND_ERR = 1,
+    INVALID_URL_ERR = 2,
+    CONNECTION_ERR = 3
+};
+typedef int CDVFileTransferError;
+
+@interface CDVFileTransfer : CDVPlugin {
+    
+}
+
+- (void) upload:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+- (void) download:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+
+-(void) downloadFile:(NSMutableArray*)arguments;
+-(void) downloadSuccess:(NSMutableArray*)arguments; 
+-(void) downloadFail:(NSMutableArray*)arguments; 
+
+-(NSMutableDictionary*) createFileTransferError:(NSString*)code AndSource:(NSString*)source AndTarget:(NSString*)target;
+@end
+
+
+@interface CDVFileTransferDelegate : NSObject {
+	CDVFileTransfer* command;
+	NSString* callbackId;
+	NSString* source;
+	NSString* target;
+    NSInteger bytesWritten;
+}
+
+@property (nonatomic, retain) NSMutableData* responseData;
+@property (nonatomic, retain) CDVFileTransfer* command;
+@property (nonatomic, retain) NSString* callbackId;
+@property (nonatomic, retain) NSString* source;
+@property (nonatomic, retain) NSString* target;
+@property NSInteger bytesWritten;
+
+
+@end;
\ No newline at end of file


Mime
View raw message