You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by sh...@apache.org on 2012/02/17 02:38:49 UTC
[17/27] Rename PhoneGap to Cordova.
http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/bcff9559/PhoneGapLib/Classes/Contact.m
----------------------------------------------------------------------
diff --git a/PhoneGapLib/Classes/Contact.m b/PhoneGapLib/Classes/Contact.m
deleted file mode 100644
index ac2bc85..0000000
--- a/PhoneGapLib/Classes/Contact.m
+++ /dev/null
@@ -1,1734 +0,0 @@
-/*
- 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 "Contact.h"
-#import "Categories.h"
-
-#define DATE_OR_NULL(dateObj) ( (aDate != nil) ? (id)([aDate descriptionWithLocale: [NSLocale currentLocale]]) : (id)([NSNull null]) )
-#define IS_VALID_VALUE(value) ((value != nil) && (![value isKindOfClass: [NSNull class]]))
-
-static NSDictionary* com_phonegap_contacts_W3CtoAB = nil;
-static NSDictionary* com_phonegap_contacts_ABtoW3C = nil;
-static NSSet* com_phonegap_contacts_W3CtoNull = nil;
-static NSDictionary* com_phonegap_contacts_objectAndProperties = nil;
-static NSDictionary* com_phonegap_contacts_defaultFields = nil;
-
-@implementation PGContact : NSObject
-
-@synthesize returnFields;
-
-- (id) init
-{
- if ((self = [super init]) != nil) {
- ABRecordRef rec = ABPersonCreate();
- self.record = rec;
- CFRelease(rec);
- }
- return self;
-}
-
-- (id) initFromABRecord:(ABRecordRef)aRecord
-{
- if ((self = [super init]) != nil) {
- self.record = aRecord;
- }
- return self;
-}
-
-/* synthesize 'record' ourselves to have retain properties for CF types */
-
-- (void) setRecord:(ABRecordRef)aRecord
-{
- if (record != NULL) {
- CFRelease(record);
- }
- if (aRecord != NULL) {
- record = CFRetain(aRecord);
- }
-}
-
-- (ABRecordRef) record
-{
- return record;
-}
-
-
-/* Rather than creating getters and setters for each AddressBook (AB) Property, generic methods are used to deal with
- * simple properties, MultiValue properties( phone numbers and emails) and MultiValueDictionary properties (Ims and addresses).
- * The dictionaries below are used to translate between the W3C identifiers and the AB properties. Using the dictionaries,
- * allows looping through sets of properties to extract from or set into the W3C dictionary to/from the ABRecord.
- */
-
-/* The two following dictionaries translate between W3C properties and AB properties. It currently mixes both
- * Properties (kABPersonAddressProperty for example) and Strings (kABPersonAddressStreetKey) so users should be aware of
- * what types of values are expected.
- * a bit.
-*/
-+(NSDictionary*) defaultABtoW3C
-{
- if (com_phonegap_contacts_ABtoW3C == nil) {
- com_phonegap_contacts_ABtoW3C = [NSDictionary dictionaryWithObjectsAndKeys:
- kW3ContactNickname, [NSNumber numberWithInt: kABPersonNicknameProperty],
- kW3ContactGivenName, [NSNumber numberWithInt: kABPersonFirstNameProperty],
- kW3ContactFamilyName, [NSNumber numberWithInt: kABPersonLastNameProperty],
- kW3ContactMiddleName, [NSNumber numberWithInt: kABPersonMiddleNameProperty],
- kW3ContactHonorificPrefix, [NSNumber numberWithInt: kABPersonPrefixProperty],
- kW3ContactHonorificSuffix, [NSNumber numberWithInt: kABPersonSuffixProperty],
- kW3ContactPhoneNumbers, [NSNumber numberWithInt: kABPersonPhoneProperty],
- kW3ContactAddresses, [NSNumber numberWithInt: kABPersonAddressProperty],
- kW3ContactStreetAddress, kABPersonAddressStreetKey,
- kW3ContactLocality, kABPersonAddressCityKey,
- kW3ContactRegion, kABPersonAddressStateKey,
- kW3ContactPostalCode, kABPersonAddressZIPKey,
- kW3ContactCountry, kABPersonAddressCountryKey,
- kW3ContactEmails, [NSNumber numberWithInt: kABPersonEmailProperty],
- kW3ContactIms, [NSNumber numberWithInt: kABPersonInstantMessageProperty],
- kW3ContactOrganizations, [NSNumber numberWithInt: kABPersonOrganizationProperty],
- kW3ContactOrganizationName, [NSNumber numberWithInt: kABPersonOrganizationProperty],
- kW3ContactTitle, [NSNumber numberWithInt: kABPersonJobTitleProperty],
- kW3ContactDepartment, [NSNumber numberWithInt:kABPersonDepartmentProperty],
- kW3ContactBirthday, [NSNumber numberWithInt: kABPersonBirthdayProperty],
- kW3ContactUrls,[NSNumber numberWithInt: kABPersonURLProperty],
- kW3ContactNote, [NSNumber numberWithInt: kABPersonNoteProperty],
- nil];
- // these dictionaries get invalidated without the retain, although running with GuardMalloc shows no memory overwrites???
- [com_phonegap_contacts_ABtoW3C retain];
- }
-
- return com_phonegap_contacts_ABtoW3C;
-}
-+(NSDictionary*) defaultW3CtoAB
-{
- if (com_phonegap_contacts_W3CtoAB == nil){
- com_phonegap_contacts_W3CtoAB = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithInt: kABPersonNicknameProperty], kW3ContactNickname,
- [NSNumber numberWithInt: kABPersonFirstNameProperty],kW3ContactGivenName,
- [NSNumber numberWithInt: kABPersonLastNameProperty],kW3ContactFamilyName,
- [NSNumber numberWithInt: kABPersonMiddleNameProperty],kW3ContactMiddleName,
- [NSNumber numberWithInt: kABPersonPrefixProperty], kW3ContactHonorificPrefix,
- [NSNumber numberWithInt: kABPersonSuffixProperty],kW3ContactHonorificSuffix,
- [NSNumber numberWithInt: kABPersonPhoneProperty],kW3ContactPhoneNumbers,
- [NSNumber numberWithInt: kABPersonAddressProperty],kW3ContactAddresses,
- kABPersonAddressStreetKey,kW3ContactStreetAddress,
- kABPersonAddressCityKey,kW3ContactLocality,
- kABPersonAddressStateKey, kW3ContactRegion,
- kABPersonAddressZIPKey,kW3ContactPostalCode,
- kABPersonAddressCountryKey,kW3ContactCountry,
- [NSNumber numberWithInt: kABPersonEmailProperty],kW3ContactEmails,
- [NSNumber numberWithInt: kABPersonInstantMessageProperty],kW3ContactIms,
- [NSNumber numberWithInt: kABPersonOrganizationProperty],kW3ContactOrganizations,
- [NSNumber numberWithInt: kABPersonJobTitleProperty],kW3ContactTitle,
- [NSNumber numberWithInt:kABPersonDepartmentProperty],kW3ContactDepartment,
- [NSNumber numberWithInt: kABPersonBirthdayProperty],kW3ContactBirthday,
- [NSNumber numberWithInt: kABPersonNoteProperty],kW3ContactNote,
- [NSNumber numberWithInt: kABPersonURLProperty], kW3ContactUrls,
- kABPersonInstantMessageUsernameKey, kW3ContactImValue,
- kABPersonInstantMessageServiceKey, kW3ContactImType,
- [NSNull null], kW3ContactFieldType, /* include entries in dictionary to indicate ContactField properties */
- [NSNull null], kW3ContactFieldValue,
- [NSNull null], kW3ContactFieldPrimary,
- [NSNull null], kW3ContactFieldId,
- [NSNumber numberWithInt: kABPersonOrganizationProperty], kW3ContactOrganizationName, /* careful, name is used mulitple times*/
- nil];
- [com_phonegap_contacts_W3CtoAB retain];
- }
- return com_phonegap_contacts_W3CtoAB;
-}
-+(NSSet*) defaultW3CtoNull
-{
-
- // these are values that have no AddressBook Equivalent OR have not been implemented yet
- if (com_phonegap_contacts_W3CtoNull == nil){
- com_phonegap_contacts_W3CtoNull = [NSSet setWithObjects: kW3ContactDisplayName,
- kW3ContactCategories, kW3ContactFormattedName, nil];
- [com_phonegap_contacts_W3CtoNull retain];
- }
- return com_phonegap_contacts_W3CtoNull;
-}
-/*
- * The objectAndProperties dictionary contains the all of the properties of the W3C Contact Objects specified by the key
- * Used in calcReturnFields, and various extract<Property> methods
- */
-+(NSDictionary*) defaultObjectAndProperties
-{
- if (com_phonegap_contacts_objectAndProperties == nil){
- com_phonegap_contacts_objectAndProperties = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSArray arrayWithObjects: kW3ContactGivenName,kW3ContactFamilyName,
- kW3ContactMiddleName, kW3ContactHonorificPrefix, kW3ContactHonorificSuffix, kW3ContactFormattedName, nil],kW3ContactName,
- [NSArray arrayWithObjects: kW3ContactStreetAddress, kW3ContactLocality,kW3ContactRegion,
- kW3ContactPostalCode, kW3ContactCountry,/*kW3ContactAddressFormatted,*/nil], kW3ContactAddresses,
- [NSArray arrayWithObjects: kW3ContactOrganizationName, kW3ContactTitle, kW3ContactDepartment, nil],kW3ContactOrganizations,
- [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary,nil], kW3ContactPhoneNumbers,
- [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary,nil], kW3ContactEmails,
- [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary,nil], kW3ContactPhotos,
- [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary,nil], kW3ContactUrls,
- [NSArray arrayWithObjects: kW3ContactImValue, kW3ContactImType, nil], kW3ContactIms,
- nil];
- [com_phonegap_contacts_objectAndProperties retain];
- }
- return com_phonegap_contacts_objectAndProperties;
-}
-+(NSDictionary*) defaultFields
-{
- if (com_phonegap_contacts_defaultFields == nil){
- com_phonegap_contacts_defaultFields = [NSDictionary dictionaryWithObjectsAndKeys:
- [[PGContact defaultObjectAndProperties] objectForKey: kW3ContactName], kW3ContactName,
- [NSNull null], kW3ContactNickname,
- [[PGContact defaultObjectAndProperties] objectForKey: kW3ContactAddresses], kW3ContactAddresses,
- [[PGContact defaultObjectAndProperties] objectForKey: kW3ContactOrganizations], kW3ContactOrganizations,
- [[PGContact defaultObjectAndProperties] objectForKey: kW3ContactPhoneNumbers], kW3ContactPhoneNumbers,
- [[PGContact defaultObjectAndProperties] objectForKey: kW3ContactEmails], kW3ContactEmails,
- [[PGContact defaultObjectAndProperties] objectForKey: kW3ContactIms], kW3ContactIms,
- [[PGContact defaultObjectAndProperties] objectForKey: kW3ContactPhotos], kW3ContactPhotos,
- [[PGContact defaultObjectAndProperties] objectForKey: kW3ContactUrls], kW3ContactUrls,
- [NSNull null],kW3ContactBirthday,
- [NSNull null],kW3ContactNote,
- nil];
- [com_phonegap_contacts_defaultFields retain];
-
- }
- return com_phonegap_contacts_defaultFields;
-}
-
-+(void) releaseDefaults
-{
- // ugly but it works
- if (com_phonegap_contacts_ABtoW3C != nil) {
- [com_phonegap_contacts_ABtoW3C release];
- if ([com_phonegap_contacts_ABtoW3C retainCount] == 1)
- com_phonegap_contacts_ABtoW3C = nil;
- }
- if (com_phonegap_contacts_W3CtoAB != nil) {
- [com_phonegap_contacts_W3CtoAB release];
- if ([com_phonegap_contacts_W3CtoAB retainCount] == 1)
- com_phonegap_contacts_W3CtoAB = nil;
- }
- if (com_phonegap_contacts_W3CtoNull != nil) {
- [com_phonegap_contacts_W3CtoNull release];
- if ([com_phonegap_contacts_W3CtoNull retainCount] == 1)
- com_phonegap_contacts_W3CtoNull = nil;
- }if (com_phonegap_contacts_objectAndProperties != nil) {
- [com_phonegap_contacts_objectAndProperties release];
- if ([com_phonegap_contacts_objectAndProperties retainCount] == 1)
- com_phonegap_contacts_objectAndProperties = nil;
- }
- if (com_phonegap_contacts_defaultFields != nil) {
- [com_phonegap_contacts_defaultFields release];
- if ([com_phonegap_contacts_defaultFields retainCount] == 1)
- com_phonegap_contacts_defaultFields = nil;
- }
-}
-
-/* Translate W3C Contact data into ABRecordRef
- *
- * New contact information comes in as a NSMutableDictionary. All Null entries in Contact object are set
- * as [NSNull null] in the dictionary when translating from the JSON input string of Contact data. However, if
- * user did not set a value within a Contact object or sub-object (by not using the object constructor) some data
- * may not exist.
- * bUpdate = YES indicates this is a save of an existing record
- */
--(bool) setFromContactDict:(NSMutableDictionary*) aContact asUpdate: (BOOL) bUpdate
-{
-
- if (![aContact isKindOfClass:[NSDictionary class]]){
- return FALSE; // can't do anything if no dictionary!
- }
-
- ABRecordRef person = self.record;
- bool bSuccess= TRUE;
- CFErrorRef error;
-
- // set name info
- // iOS doesn't have displayName - might have to pull parts from it to create name
- bool bName = false;
- NSMutableDictionary* dict = [aContact valueForKey:kW3ContactName];
- if ([dict isKindOfClass:[NSDictionary class]]){
- bName = true;
- NSArray* propArray = [[PGContact defaultObjectAndProperties] objectForKey: kW3ContactName];
- for(id i in propArray){
- if (![(NSString*)i isEqualToString:kW3ContactFormattedName]){ //kW3ContactFormattedName is generated from ABRecordCopyCompositeName() and can't be set
- [self setValue:[dict valueForKey:i] forProperty: (ABPropertyID)[(NSNumber*)[[PGContact defaultW3CtoAB] objectForKey: i]intValue]
- inRecord: person asUpdate: bUpdate];
- }
- }
- }
-
- id nn = [aContact valueForKey:kW3ContactNickname];
- if (![nn isKindOfClass:[NSNull class]]){
- bName = true;
- [self setValue: nn forProperty: kABPersonNicknameProperty inRecord: person asUpdate: bUpdate];
- }
- if (!bName){
- // if no name or nickname - try and use displayName as W3Contact must have displayName or ContactName
- [self setValue:[aContact valueForKey:kW3ContactDisplayName] forProperty: kABPersonNicknameProperty
- inRecord: person asUpdate: bUpdate];
- }
-
- // set phoneNumbers
- //NSLog(@"setting phoneNumbers");
- NSArray* array = [aContact valueForKey:kW3ContactPhoneNumbers];
- if ([array isKindOfClass:[NSArray class]]){
- [self setMultiValueStrings: array forProperty: kABPersonPhoneProperty inRecord: person asUpdate: bUpdate];
- }
- // set Emails
- //NSLog(@"setting emails");
- array = [aContact valueForKey:kW3ContactEmails];
- if ([array isKindOfClass:[NSArray class]]){
- [self setMultiValueStrings: array forProperty: kABPersonEmailProperty inRecord: person asUpdate: bUpdate];
- }
- // set Urls
- //NSLog(@"setting urls");
- array = [aContact valueForKey:kW3ContactUrls];
- if ([array isKindOfClass:[NSArray class]]){
- [self setMultiValueStrings: array forProperty: kABPersonURLProperty inRecord: person asUpdate: bUpdate];
- }
-
- // set multivalue dictionary properties
- // set addresses: streetAddress, locality, region, postalCode, country
- // set ims: value = username, type = servicetype
- // iOS addresses and im are a MultiValue Properties with label, value=dictionary of info, and id
- //NSLog(@"setting addresses");
- error = nil;
- array = [aContact valueForKey:kW3ContactAddresses];
- if ([array isKindOfClass:[NSArray class]]){
- [self setMultiValueDictionary: array forProperty: kABPersonAddressProperty inRecord: person asUpdate: bUpdate];
- }
- //ims
- //NSLog(@"setting ims");
- array = [aContact valueForKey:kW3ContactIms];
- if ([array isKindOfClass:[NSArray class]]){
- [self setMultiValueDictionary: array forProperty: kABPersonInstantMessageProperty inRecord: person asUpdate: bUpdate];
- }
-
- // organizations
- // W3C ContactOrganization has pref, type, name, title, department
- // iOS only supports name, title, department
- //NSLog(@"setting organizations");
- array = [aContact valueForKey:kW3ContactOrganizations]; // iOS only supports one organization - use first one
- if ([array isKindOfClass:[NSArray class]]){
- NSDictionary* dict = [array objectAtIndex:0];
- if ([dict isKindOfClass:[NSDictionary class]]){
- [self setValue: [dict valueForKey:@"name"] forProperty: kABPersonOrganizationProperty inRecord: person asUpdate: bUpdate];
- [self setValue: [dict valueForKey:kW3ContactTitle] forProperty: kABPersonJobTitleProperty inRecord: person asUpdate: bUpdate];
- [self setValue: [dict valueForKey:kW3ContactDepartment] forProperty: kABPersonDepartmentProperty inRecord: person asUpdate: bUpdate];
- }
- }
- // add dates
- // Dates come in as milliseconds in NSNumber Object
- id ms = [aContact valueForKey:kW3ContactBirthday];
- NSDate* aDate = nil;
- if (ms && [ms isKindOfClass:[NSNumber class]]){
- double msValue = [ms doubleValue];
- msValue = msValue/1000;
- aDate = [NSDate dateWithTimeIntervalSince1970: msValue];
- }
- if (aDate != nil || [ms isKindOfClass:[NSString class]]) {
- [self setValue: aDate != nil ? aDate : ms forProperty: kABPersonBirthdayProperty inRecord: person asUpdate: bUpdate];
- }
- // don't update creation date
- // modifiction date will get updated when save
- // anniversary is removed from W3C Contact api Dec 9, 2010 spec - don't waste time on it yet
-
- //kABPersonDateProperty
-
- //kABPersonAnniversaryLabel
-
-
-
- // iOS doesn't have gender - ignore
- // note
- [self setValue: [aContact valueForKey:kW3ContactNote] forProperty: kABPersonNoteProperty inRecord: person asUpdate: bUpdate];
-
-
- // iOS doesn't have preferredName- ignore
-
- // photo
- array = [aContact valueForKey: kW3ContactPhotos];
- if ([array isKindOfClass:[NSArray class]]){
- if (bUpdate && [array count] == 0){
- // remove photo
- bSuccess = ABPersonRemoveImageData(person, &error);
- } else if ([array count] > 0){
- NSDictionary* dict = [array objectAtIndex:0]; // currently only support one photo
- if ([dict isKindOfClass:[NSDictionary class]]){
- id value = [dict objectForKey:kW3ContactFieldValue];
- if ([value isKindOfClass:[NSString class]]){
- if (bUpdate && [value length] == 0){
- // remove the current image
- bSuccess = ABPersonRemoveImageData(person, &error);
- } else {
- // use this image
- // don't know if string is encoded or not so first unencode it then encode it again
- NSString* cleanPath = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- NSURL* photoUrl = [NSURL URLWithString: [cleanPath stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
- // caller is responsible for checking for a connection, if no connection this will fail
- NSError* err = nil;
- NSData* data = nil;
- if (photoUrl) {
- data = [NSData dataWithContentsOfURL:photoUrl options: NSDataReadingUncached error:&err];
- }
- if(data && [data length] > 0){
- bSuccess = ABPersonSetImageData(person, (CFDataRef)data, &error);
- }
- if (!data || !bSuccess){
- NSLog(@"error setting contact image: %@", (err != nil ? [err localizedDescription] : @""));
- }
-
- }
- }
- }
- }
- }
-
-
- // TODO WebURLs
-
-
- // TODO timezone
-
- return bSuccess;
-}
-/* Set item into an AddressBook Record for the specified property.
- * aValue - the value to set into the address book (code checks for null or [NSNull null]
- * aProperty - AddressBook property ID
- * aRecord - the record to update
- * bUpdate - whether this is a possible update vs a new enry
- * RETURN
- * true - property was set (or input value as null)
- * false - property was not set
- */
-- (bool) setValue: (id)aValue forProperty: (ABPropertyID) aProperty inRecord: (ABRecordRef) aRecord asUpdate: (BOOL) bUpdate
-{
-
- bool bSuccess = true; // if property was null, just ignore and return success
- CFErrorRef error;
- if (aValue && ![aValue isKindOfClass:[NSNull class]]){
- if (bUpdate && ([aValue isKindOfClass:[NSString class]] && [aValue length] == 0)) { // if updating, empty string means to delete
- aValue = NULL;
- } // really only need to set if different - more efficient to just update value or compare and only set if necessay???
- bSuccess = ABRecordSetValue(aRecord, aProperty, aValue, &error);
- if (!bSuccess){
- NSLog(@"error setting %d property", aProperty);
- }
- }
-
- return bSuccess;
-
-}
--(bool) removeProperty: (ABPropertyID) aProperty inRecord: (ABRecordRef) aRecord{
- CFErrorRef err;
- bool bSuccess = ABRecordRemoveValue(aRecord, aProperty, &err);
- if(!bSuccess){
- CFStringRef errDescription = CFErrorCopyDescription(err);
- NSLog(@"Unable to remove property %@: %@", aProperty, errDescription );
- CFRelease(errDescription);
- }
- return bSuccess;
-}
-
--(bool) addToMultiValue: (ABMultiValueRef) multi fromDictionary: dict{
- bool bSuccess = FALSE;
- id value = [dict valueForKey:kW3ContactFieldValue];
- if (IS_VALID_VALUE(value)){
- NSString* label = (NSString*)[PGContact convertContactTypeToPropertyLabel:[dict valueForKey:kW3ContactFieldType]];
- bSuccess = ABMultiValueAddValueAndLabel(multi, value,(CFStringRef)label, NULL);
- if (!bSuccess) {
- NSLog(@"Error setting Value: %@ and label: %@", value, label);
- }
- }
- return bSuccess;
-}
-
--(ABMultiValueRef) allocStringMultiValueFromArray: array
-{
- ABMutableMultiValueRef multi = ABMultiValueCreateMutable(kABMultiStringPropertyType);
- for (NSDictionary *dict in array){
- [self addToMultiValue: multi fromDictionary: dict];
- }
- return multi; //caller is responsible for releasing multi
-}
--(bool) setValue: (CFTypeRef) value forProperty: (ABPropertyID)prop inRecord: (ABRecordRef)person
-{
- CFErrorRef error;
- bool bSuccess = ABRecordSetValue(person, prop, value, &error);
- if (!bSuccess) {
- NSLog(@"Error setting value for property: %@", prop);
- }
- return bSuccess;
-}
-
-
-/* Set MultiValue string properties into Address Book Record.
- * NSArray* fieldArray - array of dictionaries containing W3C properties to be set into record
- * ABPropertyID prop - the property to be set (generally used for phones and emails)
- * ABRecordRef person - the record to set values into
- * BOOL bUpdate - whether or not to update date or set as new.
- * When updating:
- * emtpy array indicates to remove entire property
- * empty string indicates to remove
- * [NSNull null] do not modify (keep existing record value)
- * RETURNS
- * bool false indicates error
- *
- * used for phones and emails
- */
--(bool) setMultiValueStrings: (NSArray*)fieldArray forProperty: (ABPropertyID) prop inRecord: (ABRecordRef)person asUpdate: (BOOL)bUpdate
-{
- bool bSuccess = TRUE;
- ABMutableMultiValueRef multi = nil;
-
- if (!bUpdate){
- multi = [self allocStringMultiValueFromArray: fieldArray];
- bSuccess = [self setValue: multi forProperty:prop inRecord: person];
- } else if (bUpdate && [fieldArray count] == 0){
- // remove entire property
- bSuccess = [self removeProperty: prop inRecord: person];
- } else { // check for and apply changes
- ABMultiValueRef copy = ABRecordCopyValue(person, prop);
- if (copy != nil){
- multi = ABMultiValueCreateMutableCopy(copy);
- CFRelease(copy);
- for(NSDictionary* dict in fieldArray){
- id val;
- NSString* label = nil;
- val = [dict valueForKey:kW3ContactFieldValue];
- label = (NSString*)[PGContact convertContactTypeToPropertyLabel:[dict valueForKey:kW3ContactFieldType]];
- if (IS_VALID_VALUE(val)){
- // is an update, find index of entry with matching id, if values are different, update.
- id idValue = [dict valueForKey: kW3ContactFieldId];
- int identifier = [idValue isKindOfClass:[NSNumber class]] ? [idValue intValue] : -1;
- CFIndex i = identifier >= 0 ? ABMultiValueGetIndexForIdentifier(multi, identifier) : kCFNotFound;
- if (i != kCFNotFound){
- if ([val length] == 0){
- // remove both value and label
- ABMultiValueRemoveValueAndLabelAtIndex(multi, i);
- } else {
- NSString* valueAB = [(NSString*)ABMultiValueCopyValueAtIndex(multi, i) autorelease];
- NSString* labelAB = [(NSString*)ABMultiValueCopyLabelAtIndex(multi, i) autorelease];
- if (valueAB == nil || ![val isEqualToString: valueAB]){
- ABMultiValueReplaceValueAtIndex(multi, val, i);
- }
- if (labelAB == nil || ![label isEqualToString:labelAB]){
- ABMultiValueReplaceLabelAtIndex(multi, (CFStringRef)label, i);
- }
- }
- } else {
- // is a new value - insert
- [self addToMultiValue: multi fromDictionary: dict];
- }
-
- } // end of if value
-
- } //end of for
-
- } else { // adding all new value(s)
- multi = [self allocStringMultiValueFromArray: fieldArray];
- }
- // set the (updated) copy as the new value
- bSuccess = [self setValue: multi forProperty:prop inRecord: person];
- }
-
- if (multi){
- CFRelease(multi);
- }
-
- return bSuccess;
-}
-
-// used for ims and addresses
--(ABMultiValueRef) allocDictMultiValueFromArray: array forProperty: (ABPropertyID) prop
-{
- ABMutableMultiValueRef multi = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType);
- NSMutableDictionary* newDict;
- NSMutableDictionary* addDict;
- for (NSDictionary *dict in array){
- newDict = [self translateW3Dict: dict forProperty: prop];
- addDict = [NSMutableDictionary dictionaryWithCapacity: 2];
- if (newDict){ // create a new dictionary with a Label and Value, value is the dictionary previously created
- // June, 2011 W3C Contact spec adds type into ContactAddress book
- // get the type out of the original dictionary for address
- NSString* addrType = (NSString*)[dict valueForKey: kW3ContactFieldType];
- if (!addrType) {
- addrType = (NSString*) kABOtherLabel;
- }
- NSObject* typeValue = ((prop == kABPersonInstantMessageProperty) ? (NSObject*)kABOtherLabel : addrType );
- //NSLog(@"typeValue: %@", typeValue);
- [addDict setObject: typeValue forKey: kW3ContactFieldType]; // im labels will be set as Other and address labels as type from dictionary
- [addDict setObject: newDict forKey:kW3ContactFieldValue];
- [self addToMultiValue: multi fromDictionary: addDict];
- }
- }
- return multi; // caller is responsible for releasing
-}
-// used for ims and addresses to convert W3 dictionary of values to AB Dictionary
-// got messier when June, 2011 W3C Contact spec added type field into ContactAddress
--(NSMutableDictionary*) translateW3Dict: (NSDictionary*) dict forProperty: (ABPropertyID) prop
-{
-
- NSArray* propArray = [[PGContact defaultObjectAndProperties] valueForKey: [[PGContact defaultABtoW3C] objectForKey:[NSNumber numberWithInt: prop]]];
-
- NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:1];
- id value;
- for(NSString* key in propArray){ // for each W3 Contact key get the value
- if ((value = [dict valueForKey:key]) != nil && ![value isKindOfClass:[NSNull class]]){
- // if necessary convert the W3 value to AB Property label
- NSString * setValue = value;
- if ([PGContact needsConversion: key]){ // IM types must be converted
- setValue = (NSString*)[PGContact convertContactTypeToPropertyLabel:value];
- // IMs must have a valid AB value!
- if (prop == kABPersonInstantMessageProperty && [setValue isEqualToString: (NSString*)kABOtherLabel])
- setValue = @""; // try empty string
- }
- // set the AB value into the dictionary
- [newDict setObject:setValue forKey: (NSString*)[[PGContact defaultW3CtoAB] valueForKey:(NSString*)key]];
- }
- }
- if ([newDict count] ==0){
- newDict=nil; // no items added
- }
- return newDict;
-}
-/* set multivalue dictionary properties into an AddressBook Record
- * NSArray* array - array of dictionaries containing the W3C properties to set into the record
- * ABPropertyID prop - the property id for the multivalue dictionary (addresses and ims)
- * ABRecordRef person - the record to set the values into
- * BOOL bUpdate - YES if this is an update to an existing record
- * When updating:
- * emtpy array indicates to remove entire property
- * value/label == "" indicates to remove
- * value/label == [NSNull null] do not modify (keep existing record value)
- * RETURN
- * bool false indicates fatal error
- *
- * iOS addresses and im are a MultiValue Properties with label, value=dictionary of info, and id
- * set addresses: streetAddress, locality, region, postalCode, country
- * set ims: value = username, type = servicetype
- * there are some special cases in here for ims - needs cleanup / simplification
- *
- */
--(bool) setMultiValueDictionary: (NSArray*)array forProperty: (ABPropertyID) prop inRecord: (ABRecordRef)person asUpdate: (BOOL)bUpdate
-{
- bool bSuccess = FALSE;
- ABMutableMultiValueRef multi = nil;
- if (!bUpdate){
- multi = [self allocDictMultiValueFromArray: array forProperty: prop];
- bSuccess = [self setValue: multi forProperty:prop inRecord: person];
- }
- else if (bUpdate && [array count] == 0){
- // remove property
- bSuccess = [self removeProperty: prop inRecord: person];
- } else { // check for and apply changes
- ABMultiValueRef copy = ABRecordCopyValue(person, prop);
- if (copy) {
- multi = ABMultiValueCreateMutableCopy(copy);
- CFRelease(copy);
- // get the W3C values for this property
- NSArray* propArray = [[PGContact defaultObjectAndProperties] valueForKey: [[PGContact defaultABtoW3C] objectForKey:[NSNumber numberWithInt: prop]]];
- id value;
- id valueAB;
- for (NSDictionary* field in array) {
- NSMutableDictionary* dict;
- // find the index for the current property
- id idValue = [field valueForKey: kW3ContactFieldId];
- int identifier = [idValue isKindOfClass:[NSNumber class]] ? [idValue intValue] : -1;
- CFIndex idx = identifier >= 0 ? ABMultiValueGetIndexForIdentifier(multi, identifier) : kCFNotFound;
- BOOL bUpdateLabel = NO;
- if (idx != kCFNotFound){
- dict = [NSMutableDictionary dictionaryWithCapacity:1];
- NSDictionary* existingDictionary = (NSDictionary*)ABMultiValueCopyValueAtIndex(multi, idx);
- NSString* existingABLabel = [(NSString*)ABMultiValueCopyLabelAtIndex(multi, idx) autorelease];
- NSString* testLabel = [field valueForKey:kW3ContactFieldType];
- // fixes cb-143 where setting empty label could cause address to not be removed
- // (because empty label would become 'other' in convertContactTypeToPropertyLabel
- // which may not have matched existing label thus resulting in an incorrect updating of the label
- // and the address not getting removed at the end of the for loop)
- if (testLabel && [testLabel isKindOfClass:[NSString class]] && [testLabel length] > 0)
- {
- CFStringRef w3cLabel = [PGContact convertContactTypeToPropertyLabel:testLabel];
- if (w3cLabel && ![existingABLabel isEqualToString:(NSString*)w3cLabel]){
- //replace the label
- ABMultiValueReplaceLabelAtIndex(multi, w3cLabel,idx);
- bUpdateLabel = YES;
- }
- } // else was invalid or empty label string so do not update
-
- for (id k in propArray){
- value = [field valueForKey:k];
- bool bSet = (value != nil && ![value isKindOfClass:[NSNull class]] && ([value isKindOfClass:[NSString class]] && [value length] > 0));
- // if there is a contact value, put it into dictionary
- if (bSet){
- NSString* setValue = [PGContact needsConversion:(NSString*)k] ? (NSString*)[PGContact convertContactTypeToPropertyLabel:value] : value;
- [dict setObject:setValue forKey: (NSString*)[[PGContact defaultW3CtoAB] valueForKey:(NSString*)k]];
- } else if (value == nil || ([value isKindOfClass:[NSString class]] && [value length] != 0)) {
- // value not provided in contact dictionary - if prop exists in AB dictionary, preserve it
- valueAB = [existingDictionary valueForKey:[[PGContact defaultW3CtoAB] valueForKey:k]];
- if (valueAB != nil){
- [dict setValue:valueAB forKey:[[PGContact defaultW3CtoAB] valueForKey:k]];
- }
- } // else if value == "" it will not be added into updated dict and thus removed
- } // end of for loop (moving here fixes cb-143, need to end for loop before replacing or removing multivalue)
- if ([dict count] > 0){
- // something was added into new dict,
- ABMultiValueReplaceValueAtIndex(multi, dict, idx);
- } else if (!bUpdateLabel) {
- // nothing added into new dict and no label change so remove this property entry
- ABMultiValueRemoveValueAndLabelAtIndex(multi, idx);
- }
-
- CFRelease(existingDictionary);
- } else {
- // not found in multivalue so add it
- dict = [self translateW3Dict:field forProperty:prop];
- if (dict){
- NSMutableDictionary* addDict = [NSMutableDictionary dictionaryWithCapacity:2];
- // get the type out of the original dictionary for address
- NSObject* typeValue = ((prop == kABPersonInstantMessageProperty) ? (NSObject*)kABOtherLabel : (NSString*)[field valueForKey: kW3ContactFieldType]);
- NSLog(@"typeValue: %@", typeValue);
- [addDict setObject: typeValue forKey: kW3ContactFieldType]; // im labels will be set as Other and address labels as type from dictionary
- [addDict setObject: dict forKey:kW3ContactFieldValue];
- [self addToMultiValue: multi fromDictionary: addDict];
- }
- }
- } // end of looping through dictionaries
- // set the (updated) copy as the new value
- bSuccess = [self setValue: multi forProperty:prop inRecord: person];
- }
- } // end of copy and apply changes
- if (multi){
- CFRelease(multi);
- }
-
- return bSuccess;
-}
-
-/* Determine which W3C labels need to be converted
- */
-+(BOOL) needsConversion: (NSString*)W3Label{
- BOOL bConvert = NO;
-
- if ([W3Label isEqualToString:kW3ContactFieldType] || [W3Label isEqualToString:kW3ContactImType]) {
- bConvert = YES;
- }
- return bConvert;
-}
-/* Translation of property type labels contact API ---> iPhone
- *
- * phone: work, home, other, mobile, fax, pager -->
- * kABWorkLabel, kABHomeLabel, kABOtherLabel, kABPersonPhoneMobileLabel, kABPersonHomeFAXLabel || kABPersonHomeFAXLabel, kABPersonPhonePagerLabel
- * emails: work, home, other ---> kABWorkLabel, kABHomeLabel, kABOtherLabel
- * ims: aim, gtalk, icq, xmpp, msn, skype, qq, yahoo --> kABPersonInstantMessageService + (AIM, ICG, MSN, Yahoo). No support for gtalk, xmpp, skype, qq
- * addresses: work, home, other --> kABWorkLabel, kABHomeLabel, kABOtherLabel
- *
- *
- */
-+(CFStringRef) convertContactTypeToPropertyLabel:(NSString*)label
-{
- CFStringRef type;
-
- if ([label isKindOfClass:[NSNull class]] || ![label isKindOfClass:[NSString class]]){
- type = NULL; // no label
- }
- else if ([label caseInsensitiveCompare: kW3ContactWorkLabel] == NSOrderedSame){
- type = kABWorkLabel;
- } else if ([label caseInsensitiveCompare: kW3ContactHomeLabel] == NSOrderedSame){
- type = kABHomeLabel;
- } else if ( [label caseInsensitiveCompare: kW3ContactOtherLabel] == NSOrderedSame){
- type = kABOtherLabel;
- } else if ( [label caseInsensitiveCompare:kW3ContactPhoneMobileLabel] == NSOrderedSame){
- type = kABPersonPhoneMobileLabel;
- } else if ( [label caseInsensitiveCompare:kW3ContactPhonePagerLabel] == NSOrderedSame){
- type = kABPersonPhonePagerLabel;
- } else if ( [label caseInsensitiveCompare:kW3ContactImAIMLabel] == NSOrderedSame){
- type = kABPersonInstantMessageServiceAIM;
- } else if ( [label caseInsensitiveCompare:kW3ContactImICQLabel] == NSOrderedSame){
- type = kABPersonInstantMessageServiceICQ;
- } else if ( [label caseInsensitiveCompare:kW3ContactImMSNLabel] == NSOrderedSame){
- type = kABPersonInstantMessageServiceMSN;
- } else if ( [label caseInsensitiveCompare:kW3ContactImYahooLabel] == NSOrderedSame){
- type = kABPersonInstantMessageServiceYahoo;
- } else if ( [label caseInsensitiveCompare:kW3ContactUrlProfile] == NSOrderedSame){
- type = kABPersonHomePageLabel;
- } else {
- type = kABOtherLabel;
- }
-
- return type;
-
-}
-+(NSString*) convertPropertyLabelToContactType: (NSString*)label
-{
- NSString* type = nil;
- if (label != nil){ // improve effieciency......
- if ([label isEqualToString:(NSString*)kABPersonPhoneMobileLabel]){
- type = kW3ContactPhoneMobileLabel;
- }else if ([label isEqualToString: (NSString*)kABPersonPhoneHomeFAXLabel] ||
- [label isEqualToString: (NSString*)kABPersonPhoneWorkFAXLabel]) {
- type=kW3ContactPhoneFaxLabel;
- } else if ([label isEqualToString:(NSString*)kABPersonPhonePagerLabel]){
- type = kW3ContactPhonePagerLabel;
- } else if ([label isEqualToString:(NSString*)kABHomeLabel]){
- type = kW3ContactHomeLabel;
- } else if ([label isEqualToString:(NSString*)kABWorkLabel]){
- type = kW3ContactWorkLabel;
- } else if ([label isEqualToString:(NSString*)kABOtherLabel]){
- type = kW3ContactOtherLabel;
- } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceAIM]){
- type = kW3ContactImAIMLabel;
- } else if ([label isEqualToString: (NSString*)kABPersonInstantMessageServiceICQ]) {
- type=kW3ContactImICQLabel;
- } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceJabber]){
- type = kW3ContactOtherLabel;
- } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceMSN]){
- type = kW3ContactImMSNLabel;
- } else if ([label isEqualToString:(NSString*)kABPersonInstantMessageServiceYahoo]){
- type = kW3ContactImYahooLabel;
- } else if ([label isEqualToString:(NSString*)kABPersonHomePageLabel]){
- type = kW3ContactUrlProfile;
- } else {
- type = kW3ContactOtherLabel;
- }
-
- }
- return type;
-}
-/* Check if the input label is a valid W3C ContactField.type. This is used when searching,
- * only search field types if the search string is a valid type. If we converted any search
- * string to a ABPropertyLabel it could convert to kABOtherLabel which is probably not want
- * the user wanted to search for and could skew the results.
- */
-+(BOOL) isValidW3ContactType: (NSString*) label
-{
- BOOL isValid = NO;
- if ([label isKindOfClass:[NSNull class]] || ![label isKindOfClass:[NSString class]]){
- isValid = NO; // no label
- }
- else if ([label caseInsensitiveCompare: kW3ContactWorkLabel] == NSOrderedSame){
- isValid = YES;
- } else if ([label caseInsensitiveCompare: kW3ContactHomeLabel] == NSOrderedSame){
- isValid = YES;
- } else if ( [label caseInsensitiveCompare: kW3ContactOtherLabel] == NSOrderedSame){
- isValid = YES;
- } else if ( [label caseInsensitiveCompare:kW3ContactPhoneMobileLabel] == NSOrderedSame){
- isValid = YES;
- } else if ( [label caseInsensitiveCompare:kW3ContactPhonePagerLabel] == NSOrderedSame){
- isValid = YES;
- } else if ( [label caseInsensitiveCompare:kW3ContactImAIMLabel] == NSOrderedSame){
- isValid = YES;
- } else if ( [label caseInsensitiveCompare:kW3ContactImICQLabel] == NSOrderedSame){
- isValid = YES;
- } else if ( [label caseInsensitiveCompare:kW3ContactImMSNLabel] == NSOrderedSame){
- isValid = YES;
- } else if ( [label caseInsensitiveCompare:kW3ContactImYahooLabel] == NSOrderedSame){
- isValid = YES;
- } else {
- isValid = NO;
- }
-
- return isValid;
-}
-
-
-/* Create a new Contact Dictionary object from an ABRecordRef that contains information in a format such that
- * it can be returned to JavaScript callback as JSON object string.
- * Uses:
- * ABRecordRef set into Contact Object
- * NSDictionary withFields indicates which fields to return from the AddressBook Record
- *
- * JavaScript Contact:
- * @param {DOMString} id unique identifier
- * @param {DOMString} displayName
- * @param {ContactName} name
- * @param {DOMString} nickname
- * @param {ContactField[]} phoneNumbers array of phone numbers
- * @param {ContactField[]} emails array of email addresses
- * @param {ContactAddress[]} addresses array of addresses
- * @param {ContactField[]} ims instant messaging user ids
- * @param {ContactOrganization[]} organizations
- * @param {DOMString} published date contact was first created
- * @param {DOMString} updated date contact was last updated
- * @param {DOMString} birthday contact's birthday
- * @param (DOMString} anniversary contact's anniversary
- * @param {DOMString} gender contact's gender
- * @param {DOMString} note user notes about contact
- * @param {DOMString} preferredUsername
- * @param {ContactField[]} photos
- * @param {ContactField[]} tags
- * @param {ContactField[]} relationships
- * @param {ContactField[]} urls contact's web sites
- * @param {ContactAccounts[]} accounts contact's online accounts
- * @param {DOMString} timezone UTC time zone offset
- * @param {DOMString} connected
- */
-
--(NSDictionary*) toDictionary: (NSDictionary*) withFields
-{
-
-
- // if not a person type record bail out for now
- if (ABRecordGetRecordType(self.record) != kABPersonType){
- return NULL;
- }
- id value = nil;
- self.returnFields = withFields;
-
-
-
- NSMutableDictionary* nc = [NSMutableDictionary dictionaryWithCapacity:1]; // new contact dictionary to fill in from ABRecordRef
- // id
- [nc setObject: [NSNumber numberWithInt: ABRecordGetRecordID(self.record)] forKey:kW3ContactId];
- if (self.returnFields == nil){
- // if no returnFields specified, W3C says to return empty contact (but PhoneGap will at least return id)
- return nc;
- }
- if ([self.returnFields objectForKey:kW3ContactDisplayName]){
- // diplayname requested - iOS doesn't have so return null
- [nc setObject: [NSNull null] forKey:kW3ContactDisplayName];
- // may overwrite below if requested ContactName and there are no values
- }
- // nickname
- if ([self.returnFields valueForKey:kW3ContactNickname]){
- value = [(NSString*)ABRecordCopyValue(self.record, kABPersonNicknameProperty) autorelease];
- [nc setObject: (value != nil) ? value : [NSNull null] forKey:kW3ContactNickname];
- }
-
- // name dictionary
- //NSLog(@"getting name info");
- NSObject* data = [self extractName];
- if (data != nil){
- [nc setObject:data forKey:kW3ContactName];
- }
- if ([self.returnFields objectForKey:kW3ContactDisplayName] && (data == nil || [(NSDictionary*)data objectForKey: kW3ContactFormattedName] == [NSNull null])){
- // user asked for displayName which iOS doesn't support but there is no other name data being returned
- // try and use Composite Name so some name is returned
- id tryName = [(NSString*)ABRecordCopyCompositeName(self.record) autorelease];
- if (tryName != nil){
- [nc setObject:tryName forKey:kW3ContactDisplayName];
- } else {
- // use nickname or empty string
- value = [(NSString*)ABRecordCopyValue(self.record, kABPersonNicknameProperty) autorelease];
- [nc setObject:(value!= nil) ? value : @"" forKey:kW3ContactDisplayName];
- }
- }
- // phoneNumbers array
- //NSLog(@"getting phoneNumbers");
- value = [self extractMultiValue:kW3ContactPhoneNumbers];
- if (value != nil){
- [nc setObject: value forKey: kW3ContactPhoneNumbers];
- }
- // emails array
- //NSLog(@"getting emails");
- value = [self extractMultiValue:kW3ContactEmails];
- if (value != nil){
- [nc setObject: value forKey: kW3ContactEmails];
- }
- // urls array
- value = [self extractMultiValue:kW3ContactUrls];
- if (value != nil){
- [nc setObject: value forKey: kW3ContactUrls];
- }
- // addresses array
- //NSLog(@"getting addresses");
- value = [self extractAddresses];
- if (value != nil){
- [nc setObject:[self extractAddresses] forKey: kW3ContactAddresses];
- }
- // im array
- //NSLog(@"getting ims");
- value = [self extractIms];
- if (value != nil){
- [nc setObject: value forKey: kW3ContactIms];
- }
- // organization array (only info for one organization in iOS)
- //NSLog(@"getting organizations");
- value = [self extractOrganizations];
- if (value != nil){
- [nc setObject:value forKey:kW3ContactOrganizations];
- }
-
- // for simple properties, could make this a bit more efficient by storing all simple properties in a single
- // array in the returnFields dictionary and setting them via a for loop through the array
-
- // add dates
- //NSLog(@"getting dates");
- NSNumber* ms;
-
- /** Contact Revision field removed from June 16, 2011 version of specification
-
- if ([self.returnFields valueForKey:kW3ContactUpdated]){
- ms = [self getDateAsNumber: kABPersonModificationDateProperty];
- if (!ms){
- // try and get published date
- ms = [self getDateAsNumber: kABPersonCreationDateProperty];
- }
- if (ms){
- [nc setObject: ms forKey:kW3ContactUpdated];
- }
-
- }
- */
-
- if ([self.returnFields valueForKey:kW3ContactBirthday]){
- ms = [self getDateAsNumber: kABPersonBirthdayProperty];
- if(ms){
- [nc setObject: ms forKey: kW3ContactBirthday];
- }
- }
- /* Anniversary removed from 12-09-2010 W3C Contacts api spec
- if ([self.returnFields valueForKey:kW3ContactAnniversary]){
- // Anniversary date is stored in a multivalue property
- ABMultiValueRef multi = ABRecordCopyValue(self.record, kABPersonDateProperty);
- if (multi){
- CFStringRef label = nil;
- CFIndex count = ABMultiValueGetCount(multi);
- // see if contains an Anniversary date
- for(CFIndex i=0; i<count; i++){
- label = ABMultiValueCopyLabelAtIndex(multi, i);
- if(label && [(NSString*)label isEqualToString:(NSString*)kABPersonAnniversaryLabel]){
- CFDateRef aDate = ABMultiValueCopyValueAtIndex(multi, i);
- if(aDate){
- [nc setObject: (NSString*)aDate forKey: kW3ContactAnniversary];
- CFRelease(aDate);
- }
- CFRelease(label);
- break;
- }
- }
- CFRelease(multi);
- }
- }*/
-
- if ([self.returnFields valueForKey:kW3ContactNote]){
- // note
- value = [(NSString*)ABRecordCopyValue(self.record, kABPersonNoteProperty) autorelease];
- [nc setObject: (value != nil) ? value : [NSNull null] forKey:kW3ContactNote];
- }
-
- if ([self.returnFields valueForKey:kW3ContactPhotos]){
- value = [self extractPhotos];
- [nc setObject: (value != nil) ? value : [NSNull null] forKey:kW3ContactPhotos];
- }
- /* TimeZone removed from June 16, 2011 Contacts spec
- *
- if ([self.returnFields valueForKey:kW3ContactTimezone]){
- [NSTimeZone resetSystemTimeZone];
- NSTimeZone* currentTZ = [NSTimeZone localTimeZone];
- NSInteger seconds = [currentTZ secondsFromGMT];
- NSString* tz = [NSString stringWithFormat:@"%2d:%02u", seconds/3600, seconds % 3600 ];
- [nc setObject:tz forKey:kW3ContactTimezone];
- }
- */
- // TODO WebURLs
- //[nc setObject:[NSNull null] forKey:kW3ContactUrls];
- // online accounts - not available on iOS
-
-
- return nc;
-
-}
--(NSNumber*)getDateAsNumber: (ABPropertyID) datePropId
-{
-
- NSNumber* msDate = nil;
- NSDate* aDate = nil;
- CFTypeRef cfDate = ABRecordCopyValue(self.record, datePropId);
- if (cfDate) {
- aDate = (NSDate*) cfDate;
- msDate = [NSNumber numberWithDouble:([aDate timeIntervalSince1970]*1000)];
- CFRelease(cfDate);
- }
- return msDate;
-}
-/* Create Dictionary to match JavaScript ContactName object:
- * formatted - ABRecordCopyCompositeName
- * familyName
- * givenName
- * middleName
- * honorificPrefix
- * honorificSuffix
-*/
-
--(NSObject*) extractName
-{
-
- NSArray* fields = [self.returnFields objectForKey:kW3ContactName];
-
- if (fields == nil) { // no name fields requested
- return nil;
- }
-
- NSMutableDictionary* newName = [NSMutableDictionary dictionaryWithCapacity:6];
- id value;
- for (NSString* i in fields){
- if ([i isEqualToString:kW3ContactFormattedName]){
- value = [(NSString*)ABRecordCopyCompositeName(self.record) autorelease];
- [newName setObject: (value != nil) ? value : [NSNull null] forKey: kW3ContactFormattedName];
- }else {
- //W3CtoAB returns NSNumber for AB name properies, get intValue and cast to ABPropertyID)
- value = [(NSString*)ABRecordCopyValue(self.record, (ABPropertyID)[[[PGContact defaultW3CtoAB] valueForKey:i] intValue]) autorelease];
- [newName setObject: (value != nil) ? value : [NSNull null] forKey: (NSString*)i];
- }
- }
-
- return newName;
-
-}
-
-/* Create array of Dictionaris to match JavaScript ContactField object for simple multiValue properties phoneNumbers, emails
- * Input: (NSString*) W3Contact Property name
- * type
- * for phoneNumbers type is one of (work,home,other, mobile, fax, pager)
- * for emails type is one of (work,home, other)
- * value - phone number or email address
- * (bool) primary (not supported on iphone)
- * id
-*/
--(NSObject*) extractMultiValue: (NSString*)propertyId
-{
- NSArray* fields = [self.returnFields objectForKey:propertyId];
- if (fields == nil){
- return nil;
- }
- ABMultiValueRef multi = nil;
- NSObject* valuesArray = nil;
- NSNumber* propNumber = [[PGContact defaultW3CtoAB] valueForKey:propertyId];
- ABPropertyID propId = [propNumber intValue];
- multi = ABRecordCopyValue(self.record, propId);
- //multi = ABRecordCopyValue(self.record, (ABPropertyID)[[[Contact defaultW3CtoAB] valueForKey:propertyId] intValue]);
- CFIndex count = multi != nil ? ABMultiValueGetCount(multi) : 0;
- id value;
- if (count){
- valuesArray = [NSMutableArray arrayWithCapacity:count];
- for (CFIndex i=0; i<count; i++) {
- NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:4];
- if ([fields containsObject:kW3ContactFieldType]){
- NSString* label = [(NSString*)ABMultiValueCopyLabelAtIndex(multi, i) autorelease];
- value = [PGContact convertPropertyLabelToContactType: label];
- [newDict setObject: (value != nil) ? value : [NSNull null] forKey: kW3ContactFieldType];
- }
- if ([fields containsObject:kW3ContactFieldValue]){
- value = [(NSString*)ABMultiValueCopyValueAtIndex(multi, i) autorelease];
- [newDict setObject: (value != nil) ? value : [NSNull null] forKey: kW3ContactFieldValue];
- }
- if ([fields containsObject:kW3ContactFieldPrimary]){
- [newDict setObject: [NSNumber numberWithBool:(BOOL)NO] forKey: kW3ContactFieldPrimary]; // iOS doesn't support primary so set all to false
- }
- // always set id
- value = [NSNumber numberWithUnsignedInt: ABMultiValueGetIdentifierAtIndex(multi,i)];
- [newDict setObject: (value !=nil) ? value : [NSNull null] forKey:kW3ContactFieldId];
- [(NSMutableArray*)valuesArray addObject:newDict];
- }
- } else {
- valuesArray = [NSNull null];
- }
- if (multi)
- CFRelease(multi);
-
- return valuesArray;
-
-}
-/* Create array of Dictionaris to match JavaScript ContactAddress object for addresses
- * pref - not supported
- * type - address type
- * formatted - formatted for mailing label (what about localization?)
- * streetAddress
- * locality
- * region;
- * postalCode
- * country
- * id
- *
- * iOS addresses are a MultiValue Properties with label, value=dictionary of address info, and id
- */
--(NSObject*) extractAddresses
-{
-
- NSArray* fields = [self.returnFields objectForKey:kW3ContactAddresses];
-
- if (fields == nil) { // no name fields requested
- return nil;
- }
- id value;
- NSObject* addresses;
- ABMultiValueRef multi = ABRecordCopyValue(self.record, kABPersonAddressProperty);
- CFIndex count = multi ? ABMultiValueGetCount(multi) : 0;
- if (count){
- addresses = [NSMutableArray arrayWithCapacity:count];
- for (CFIndex i = 0; i < count; i++) {
- NSMutableDictionary* newAddress = [NSMutableDictionary dictionaryWithCapacity:7];
- // if we got this far, at least some address info is being requested.
-
- //Always set id
- id identifier = [NSNumber numberWithUnsignedInt: ABMultiValueGetIdentifierAtIndex(multi,i)];
- [newAddress setObject: (identifier !=nil) ? identifier : [NSNull null] forKey:kW3ContactFieldId];
- // set the type label
- NSString* label = [(NSString*)ABMultiValueCopyLabelAtIndex(multi, i) autorelease];
-
- [newAddress setObject: (label != nil) ? (NSObject*) [[PGContact class] convertPropertyLabelToContactType:label] : [NSNull null] forKey:kW3ContactFieldType];
- // set the pref - iOS doesn't support so set to default of false
- [newAddress setObject:@"false" forKey:kW3ContactFieldPrimary];
- // get dictionary of values for this address
- CFDictionaryRef dict = (CFDictionaryRef) ABMultiValueCopyValueAtIndex(multi, i);
- for(id k in fields){
- bool bFound;
- id key = [[PGContact defaultW3CtoAB] valueForKey:k];
- if (key && ![k isKindOfClass:[NSNull class]]){
- bFound = CFDictionaryGetValueIfPresent(dict, key, (void *)&value);
- [newAddress setObject: (bFound && value != NULL) ? (id)value : [NSNull null] forKey: k];
- } else {
- // was a property that iPhone doesn't support
- [newAddress setObject:[NSNull null] forKey:k];
- }
-
- }
- if ([newAddress count] > 0){
- [(NSMutableArray*)addresses addObject:newAddress];
- }
- CFRelease(dict);
-
- } // end of loop through addresses
- } else {
- addresses = [NSNull null];
- }
- if (multi)
- CFRelease(multi);
-
-
- return addresses;
-
-}
-/* Create array of Dictionaries to match JavaScript ContactField object for ims
- * type one of [aim, gtalk, icq, xmpp, msn, skype, qq, yahoo] needs other as well
- * value
- * (bool) primary
- * id
- *
- * iOS IMs are a MultiValue Properties with label, value=dictionary of IM details (service, username), and id
- */
--(NSObject*) extractIms
-{
- NSArray* fields = [self.returnFields objectForKey:kW3ContactIms];
-
- if (fields == nil) { // no name fields requested
- return nil;
- }
- NSObject* imArray;
- ABMultiValueRef multi = ABRecordCopyValue(self.record, kABPersonInstantMessageProperty);
- CFIndex count = multi ? ABMultiValueGetCount(multi) : 0;
- if (count){
- imArray = [NSMutableArray arrayWithCapacity:count];
- for (CFIndex i = 0; i < ABMultiValueGetCount(multi); i++) {
- NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:3];
- // iOS has label property (work, home, other) for each IM but W3C contact API doesn't use
- CFDictionaryRef dict = (CFDictionaryRef) ABMultiValueCopyValueAtIndex(multi, i);
- NSString* value; // all values should be CFStringRefs / NSString*
- bool bFound;
- if ([fields containsObject: kW3ContactFieldValue]){
- // value = user name
- bFound = CFDictionaryGetValueIfPresent(dict, kABPersonInstantMessageUsernameKey, (void *)&value);
- [newDict setObject: (bFound && value != NULL) ? (id)value : [NSNull null] forKey: kW3ContactFieldValue];
- }
- if ([fields containsObject: kW3ContactFieldType]){
- bFound = CFDictionaryGetValueIfPresent(dict, kABPersonInstantMessageServiceKey, (void *)&value);
- [newDict setObject: (bFound && value != NULL) ? (id)[[PGContact class ]convertPropertyLabelToContactType: value] : [NSNull null] forKey: kW3ContactFieldType];
- }
- // always set ID
- id identifier = [NSNumber numberWithUnsignedInt: ABMultiValueGetIdentifierAtIndex(multi,i)];
- [newDict setObject: (identifier !=nil) ? identifier : [NSNull null] forKey:kW3ContactFieldId];
-
- [(NSMutableArray*)imArray addObject:newDict];
- CFRelease(dict);
- }
- } else {
- imArray = [NSNull null];
- }
-
- if (multi)
- CFRelease(multi);
- return imArray;
-}
-/* Create array of Dictionaris to match JavaScript ContactOrganization object
- * pref - not supported in iOS
- * type - not supported in iOS
- * name
- * department
- * title
- */
-
--(NSObject*) extractOrganizations
-{
- NSArray* fields = [self.returnFields objectForKey:kW3ContactOrganizations];
-
- if (fields == nil) { // no name fields requested
- return nil;
- }
- NSObject* array = nil;
- NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:5];
- id value;
- int validValueCount = 0;
- for (id i in fields){
- id key = [[PGContact defaultW3CtoAB] valueForKey:i];
- if (key && [key isKindOfClass:[NSNumber class]]){
- value = [(NSString *)ABRecordCopyValue(self.record, (ABPropertyID)[[[PGContact defaultW3CtoAB] valueForKey:i] intValue]) autorelease];
- if (value != nil) {
- // if there are no organization values we should return null for organization
- // this counter keeps indicates if any organization values have been set
- validValueCount++;
- }
- [newDict setObject:(value != nil) ? value : [NSNull null] forKey:i];
- }else { // not a key iOS supports, set to null
- [newDict setObject:[NSNull null] forKey:i];
- }
- }
- if ([newDict count] > 0 && validValueCount > 0) {
- // add pref and type
- // they are not supported by iOS and thus these values never change
- [newDict setObject: @"false" forKey:kW3ContactFieldPrimary];
- [newDict setObject: [NSNull null] forKey: kW3ContactFieldType];
- array = [NSMutableArray arrayWithCapacity:1];
- [(NSMutableArray*)array addObject:newDict];
- }
- else {
- array = [NSNull null];
- }
- return array;
-}
-
-// W3C Contacts expects an array of photos. Can return photos in more than one format, currently
-// just returning the default format
-// Save the photo data into tmp directory and return FileURI - temp directory is deleted upon application exit
--(NSObject*) extractPhotos
-{
- NSMutableArray* photos = nil;
- if (ABPersonHasImageData(self.record)){
- CFDataRef photoData = ABPersonCopyImageData(self.record);
- NSData* data = (NSData*)photoData;
- // write to temp directory and store URI in photos array
- // get the temp directory path
- NSString* docsPath = [NSTemporaryDirectory() stringByStandardizingPath];
- NSError* err = nil;
- NSFileManager* fileMgr = [[NSFileManager alloc] init];
- // generate unique file name
- NSString* filePath;
- int i=1;
- do {
- filePath = [NSString stringWithFormat:@"%@/photo_%03d.jpg", docsPath, i++];
- } while([fileMgr fileExistsAtPath: filePath]);
- // save file
- if ([data writeToFile: filePath options: NSAtomicWrite error: &err]){
- photos = [NSMutableArray arrayWithCapacity:1];
- NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:2];
- [newDict setObject:filePath forKey:kW3ContactFieldValue];
- [newDict setObject:@"url" forKey:kW3ContactFieldType];
- [newDict setObject:@"false" forKey:kW3ContactFieldPrimary];
- [photos addObject:newDict];
- }
- [fileMgr release];
-
- CFRelease(photoData);
- }
- return photos;
-}
-
-
-
-/**
- * given an array of W3C Contact field names, create a dictionary of field names to extract
- * if field name represents an object, return all properties for that object: "name" - returns all properties in ContactName
- * if field name is an explicit property, return only those properties: "name.givenName - returns a ContactName with only ContactName.givenName
- * if field contains ONLY ["*"] return all fields
- * dictionary format:
- * key is W3Contact #define
- * value is NSMutableArray* for complex keys: name,addresses,organizations, phone, emails, ims
- * value is [NSNull null] for simple keys
-*/
-+(NSDictionary*) calcReturnFields: (NSArray*)fieldsArray
-{ //NSLog(@"getting self.returnFields");
- NSMutableDictionary* d = [NSMutableDictionary dictionaryWithCapacity:1];
- if (fieldsArray != nil && [fieldsArray isKindOfClass:[NSArray class]]){
- if ([fieldsArray count] == 1 && [[fieldsArray objectAtIndex:0] isEqualToString:@"*"]) {
- return [PGContact defaultFields]; // return all fields
- }
- for (id i in fieldsArray){
- NSMutableArray* keys = nil;
- NSString* fieldStr = nil;
- if ([i isKindOfClass: [NSNumber class]]) {
- fieldStr = [i stringValue];
- } else {
- fieldStr = i;
- }
-
- // see if this is specific property request in object - object.property
- NSArray* parts = [fieldStr componentsSeparatedByString:@"."]; // returns original string if no separator found
- NSString* name = [parts objectAtIndex:0];
- NSString* property = nil;
- if ([parts count] > 1){
- property = [parts objectAtIndex:1];
- }
- // see if this is a complex field by looking for its array of properties in objectAndProperties dictionary
- id fields = [[PGContact defaultObjectAndProperties] objectForKey:name];
-
- // if find complex name (name,addresses,organizations, phone, emails, ims) in fields, add name as key
- // with array of associated properties as the value
- if (fields != nil && property == nil){ //request was for full object
- keys = [NSMutableArray arrayWithArray: fields];
- if(keys != nil){
- [d setObject:keys forKey:name]; // will replace if prop array already exists
- }
- } else if (fields != nil && property != nil){
- // found an individual property request in form of name.property
- // verify is real property name by using it as key in W3CtoAB
- id abEquiv = [[PGContact defaultW3CtoAB] objectForKey:property];
- if (abEquiv || [[PGContact defaultW3CtoNull] containsObject:property]){
- //if existing array add to it
- if((keys = [d objectForKey:name]) != nil){
- [keys addObject:property];
- } else {
- keys = [NSMutableArray arrayWithObject:property];
- [d setObject: keys forKey:name];
- }
- }else {
- NSLog(@"Contacts.find -- request for invalid property ignored: %@.%@", name, property);
- }
- } else { // is an individual property, verify is real property name by using it as key in W3CtoAB
- id valid = [[PGContact defaultW3CtoAB] objectForKey:name];
- if (valid || [[PGContact defaultW3CtoNull] containsObject:name]){
- [d setObject:[NSNull null] forKey: name];
- }
- }
- }
- }
- if ([d count] == 0){
- // no array or nothing in the array. W3C spec says to return nothing
- return nil; //[Contact defaultFields];
- }
- return d;
-
-}
-/*
- * Search for the specified value in each of the fields specified in the searchFields dictionary.
- * NSString* value - the string value to search for (need clarification from W3C on how to search for dates)
- * NSDictionary* searchFields - a dictionary created via calcReturnFields where the key is the top level W3C
- * object and the object is the array of specific fields within that object or null if it is a single property
- * RETURNS
- * YES as soon as a match is found in any of the fields
- * NO - the specified value does not exist in any of the fields in this contact
- *
- * Note: I'm not a fan of returning in the middle of methods but have done it some in this method in order to
- * keep the code simpler. bgibson
- */
--(BOOL) foundValue: (NSString*)testValue inFields: (NSDictionary*) searchFields
-{
- BOOL bFound = NO;
-
- if (testValue == nil || ![testValue isKindOfClass: [NSString class]] || [testValue length] == 0){
- // nothing to find so return NO
- return NO;
- }
- NSInteger valueAsInt = [testValue integerValue];
-
- // per W3C spec, always include id in search
- int recordId = ABRecordGetRecordID(self.record);
- if (valueAsInt && recordId == valueAsInt){
- return YES;
- }
-
- if (searchFields == nil) {
- // no fields to search
- return NO;
- }
-
-
- if ([searchFields valueForKey:kW3ContactNickname]){
- bFound = [self testStringValue:testValue forW3CProperty:kW3ContactNickname];
- if (bFound == YES){
- return bFound;
- }
- }
-
- if ([searchFields valueForKeyIsArray:kW3ContactName]){
- // test name fields. All are string properties obtained via ABRecordCopyValue except kW3ContactFormattedName
- NSArray* fields = [searchFields valueForKey:kW3ContactName];
- for (NSString* testItem in fields){
- if ([testItem isEqualToString:kW3ContactFormattedName]){
- NSString* propValue = [(NSString*)ABRecordCopyCompositeName(self.record) autorelease];
- if (propValue != nil && [propValue length] > 0) {
- NSRange range = [propValue rangeOfString:testValue options: NSCaseInsensitiveSearch];
- bFound = (range.location != NSNotFound);
- propValue = nil;
- }
- } else {
- bFound = [self testStringValue:testValue forW3CProperty:testItem];
- }
-
- if (bFound) {
- break;
- }
- }
- }
- if (!bFound && [searchFields valueForKeyIsArray:kW3ContactPhoneNumbers]){
- bFound = [self searchContactFields: (NSArray*) [searchFields valueForKey: kW3ContactPhoneNumbers]
- forMVStringProperty: kABPersonPhoneProperty withValue: testValue];
- }
- if (!bFound && [searchFields valueForKeyIsArray: kW3ContactEmails]){
- bFound = [self searchContactFields: (NSArray*) [searchFields valueForKey: kW3ContactEmails]
- forMVStringProperty: kABPersonEmailProperty withValue: testValue];
- }
-
- if (!bFound && [searchFields valueForKeyIsArray: kW3ContactAddresses]){
- bFound = [self searchContactFields: [searchFields valueForKey:kW3ContactAddresses]
- forMVDictionaryProperty: kABPersonAddressProperty withValue: testValue];
- }
-
- if (!bFound && [searchFields valueForKeyIsArray: kW3ContactIms]){
- bFound = [self searchContactFields: [searchFields valueForKey:kW3ContactIms]
- forMVDictionaryProperty: kABPersonInstantMessageProperty withValue: testValue];
- }
-
- if (!bFound && [searchFields valueForKeyIsArray: kW3ContactOrganizations]){
- NSArray* fields = [searchFields valueForKey: kW3ContactOrganizations];
- for (NSString* testItem in fields){
- bFound = [self testStringValue:testValue forW3CProperty:testItem];
- if (bFound == YES){
- break;
- }
- }
- }
- if (!bFound && [searchFields valueForKey:kW3ContactNote]){
- bFound = [self testStringValue:testValue forW3CProperty:kW3ContactNote];
- }
-
- // if searching for a date field is requested, get the date field as a localized string then look for match against testValue in date string
- // searching for photos is not supported
- if (!bFound && [searchFields valueForKey:kW3ContactBirthday]){
- bFound = [self testDateValue: testValue forW3CProperty: kW3ContactBirthday];
- }
- if (!bFound && [searchFields valueForKeyIsArray: kW3ContactUrls]){
- bFound = [self searchContactFields: (NSArray*) [searchFields valueForKey: kW3ContactUrls]
- forMVStringProperty: kABPersonURLProperty withValue: testValue];
- }
-
- return bFound;
-
-
-}
-
-/*
- * Test for the existence of a given string within the value of a ABPersonRecord string property based on the W3c property name.
- *
- * IN:
- * NSString* testValue - the value to find - search is case insensitive
- * NSString* property - the W3c property string
- * OUT:
- * BOOL YES if the given string was found within the property value
- * NO if the testValue was not found, W3C property string was invalid or the AddressBook property was not a string
- */
--(BOOL) testStringValue: (NSString*)testValue forW3CProperty: (NSString*) property {
- BOOL bFound = NO;
-
- if ([[PGContact defaultW3CtoAB] valueForKeyIsNumber: property ]) {
- ABPropertyID propId = [[[PGContact defaultW3CtoAB] objectForKey: property] intValue];
- if(ABPersonGetTypeOfProperty(propId) == kABStringPropertyType){
- NSString* propValue = [(NSString*)ABRecordCopyValue(self.record, propId) autorelease];
- if (propValue != nil && [propValue length] > 0) {
- NSPredicate *containPred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", testValue];
- bFound = [containPred evaluateWithObject:propValue];
- //NSRange range = [propValue rangeOfString:testValue options: NSCaseInsensitiveSearch];
- //bFound = (range.location != NSNotFound);
- }
- }
- }
- return bFound;
-}
-/*
- * Test for the existence of a given Date string within the value of a ABPersonRecord datetime property based on the W3c property name.
- *
- * IN:
- * NSString* testValue - the value to find - search is case insensitive
- * NSString* property - the W3c property string
- * OUT:
- * BOOL YES if the given string was found within the localized date string value
- * NO if the testValue was not found, W3C property string was invalid or the AddressBook property was not a DateTime
- */
--(BOOL) testDateValue: (NSString*)testValue forW3CProperty: (NSString*) property {
- BOOL bFound = NO;
-
- if ([[PGContact defaultW3CtoAB] valueForKeyIsNumber: property ]) {
- ABPropertyID propId = [[[PGContact defaultW3CtoAB] objectForKey: property] intValue];
- if(ABPersonGetTypeOfProperty(propId) == kABDateTimePropertyType){
- NSDate* date = [(NSDate*)ABRecordCopyValue(self.record, propId) autorelease];
- if (date != nil) {
- NSString* dateString = [date descriptionWithLocale:[NSLocale currentLocale]];
- NSPredicate *containPred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", testValue];
- bFound = [containPred evaluateWithObject:dateString];
- }
- }
- }
- return bFound;
-}
-/*
- * Search the specified fields within an AddressBook multivalue string property for the specified test value.
- * Used for phoneNumbers, emails and urls.
- * IN:
- * NSArray* fields - the fields to search for within the multistring property (value and/or type)
- * ABPropertyID - the property to search
- * NSString* testValue - the value to search for. Will convert between W3C types and AB types. Will only
- * search for types if the testValue is a valid ContactField type.
- * OUT:
- * YES if the test value was found in one of the specified fields
- * NO if the test value was not found
- */
--(BOOL) searchContactFields: (NSArray*) fields forMVStringProperty: (ABPropertyID) propId withValue: testValue {
-
- BOOL bFound = NO;
- for (NSString* type in fields){
- NSString* testString = nil;
- if ([type isEqualToString: kW3ContactFieldType]){
- if ([PGContact isValidW3ContactType: testValue]){
- // only search types if the filter string is a valid ContactField.type
- testString = (NSString*)[PGContact convertContactTypeToPropertyLabel:testValue];
- }
- } else {
- testString = testValue;
- }
-
- if (testString != nil){
- bFound = [self testMultiValueStrings:testString forProperty: propId ofType: type];
- }
- if (bFound == YES) {
- break;
- }
- }
- return bFound;
-}
-/*
- * Searches a multiString value of the specified type for the specified test value.
- *
- * IN:
- * NSString* testValue - the value to test for
- * ABPropertyID propId - the property id of the multivalue property to search
- * NSString* type - the W3C contact type to search for (value or type)
- * OUT:
- * YES is the test value was found
- * NO if the test value was not found
- */
-- (BOOL) testMultiValueStrings: (NSString*) testValue forProperty: (ABPropertyID) propId ofType: (NSString*) type {
- BOOL bFound = NO;
-
- if(ABPersonGetTypeOfProperty(propId) == kABMultiStringPropertyType){
- NSArray* valueArray = nil;
- if ([type isEqualToString:kW3ContactFieldType]){
- valueArray = [self labelsForProperty: propId inRecord: self.record];
- } else if ([type isEqualToString:kW3ContactFieldValue]) {
- valueArray = [self valuesForProperty: propId inRecord: self.record];
- }
- if (valueArray) {
- NSString* valuesAsString = [valueArray componentsJoinedByString:@" "];
- NSPredicate *containPred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", testValue];
- bFound = [containPred evaluateWithObject:valuesAsString];
- }
- }
- return bFound;
-
-}
-/*
- * Returns the array of values for a multivalue string property of the specified property id
- */
-- (NSArray *) valuesForProperty: (ABPropertyID) propId inRecord: (ABRecordRef) aRecord
-{
- ABMultiValueRef multi = ABRecordCopyValue(aRecord, propId);
- NSArray *values = (NSArray *)ABMultiValueCopyArrayOfAllValues(multi);
- CFRelease(multi);
- return [values autorelease];
-}
-/*
- * Returns the array of labels for a multivalue string property of the specified property id
- */
-- (NSArray *) labelsForProperty: (ABPropertyID) propId inRecord: (ABRecordRef)aRecord
-{
- ABMultiValueRef multi = ABRecordCopyValue(aRecord, propId);
- CFIndex count = ABMultiValueGetCount(multi);
- NSMutableArray *labels = [NSMutableArray arrayWithCapacity:count];
- for (int i = 0; i < count; i++) {
- NSString *label = (NSString *)ABMultiValueCopyLabelAtIndex(multi, i);
- if (label){
- [labels addObject:label];
- [label release];
- }
- }
- CFRelease(multi);
- return labels;
-}
-/* search for values within MultiValue Dictionary properties Address or IM property
- * IN:
- * (NSArray*) fields - the array of W3C field names to search within
- * (ABPropertyID) propId - the AddressBook property that returns a multivalue dictionaty
- * (NSString*) testValue - the string to search for within the specified fields
- *
- */
--(BOOL) searchContactFields: (NSArray*) fields forMVDictionaryProperty: (ABPropertyID) propId withValue: (NSString*)testValue
-{
- BOOL bFound = NO;
-
- NSArray* values = [self valuesForProperty:propId inRecord:self.record]; // array of dictionaries (as CFDictionaryRef)
- // for ims dictionary contains with service (w3C type) and username (W3c value)
- // for addresses dictionary contains street, city, state, zip, country
- for(id dict in values){
- for(NSString* member in fields){
- NSString* abKey = [[PGContact defaultW3CtoAB] valueForKey:member]; // im and address fields are all strings
- NSString* abValue = nil;
- if (abKey){
- NSString* testString = nil;
- if ([member isEqualToString:kW3ContactImType]){
- if ([PGContact isValidW3ContactType: testValue]){
- // only search service/types if the filter string is a valid ContactField.type
- testString = (NSString*)[PGContact convertContactTypeToPropertyLabel:testValue];
- }
- } else {
- testString = testValue;
- }
- if(testString != nil){
- BOOL bExists = CFDictionaryGetValueIfPresent((CFDictionaryRef)dict, abKey, (void *)&abValue);
- if(bExists) {
- NSPredicate *containPred = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", testString];
- bFound = [containPred evaluateWithObject:abValue];
- }
- }
- }
- if (bFound == YES) {
- break;
- }
- } // end of for each member in fields
- if (bFound == YES) {
- break;
- }
- } // end of for each dictionary
- return bFound;
-}
-
-
-- (void) dealloc
-{
- if (record != NULL){
- CFRelease(record);
- }
- self.returnFields = nil;
-
- [super dealloc];
-}
-@end
http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/bcff9559/PhoneGapLib/Classes/Contacts.h
----------------------------------------------------------------------
diff --git a/PhoneGapLib/Classes/Contacts.h b/PhoneGapLib/Classes/Contacts.h
deleted file mode 100755
index 4797c33..0000000
--- a/PhoneGapLib/Classes/Contacts.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- 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 <AddressBook/ABAddressBook.h>
-#import <AddressBookUI/AddressBookUI.h>
-#import "PGPlugin.h"
-#import "Contact.h"
-
-@interface PGContacts : PGPlugin <ABNewPersonViewControllerDelegate,
- ABPersonViewControllerDelegate,
- ABPeoplePickerNavigationControllerDelegate
- >
-{
- ABAddressBookRef addressBook;
-}
-
-
-
-/*
- * newContact - create a new contact via the GUI
- *
- * arguments:
- * 1: successCallback: this is the javascript function that will be called with the newly created contactId
- */
-- (void) newContact:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
-
-/*
- * displayContact - IN PROGRESS
- *
- * arguments:
- * 1: recordID of the contact to display in the iPhone contact display
- * 2: successCallback - currently not used
- * 3: error callback
- * options:
- * allowsEditing: set to true to allow the user to edit the contact - currently not supported
- */
-- (void) displayContact:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
-
-/*
- * chooseContact
- *
- * arguments:
- * 1: this is the javascript function that will be called with the contact data as a JSON object (as the first param)
- * options:
- * allowsEditing: set to true to not choose the contact, but to edit it in the iPhone contact editor
- */
-- (void) chooseContact:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
-
-- (void) newPersonViewController:(ABNewPersonViewController *)newPersonViewController didCompleteWithNewPerson:(ABRecordRef)person;
-- (BOOL) personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person
- property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue;
-
-/*
- * search - searchs for contacts. Only person records are currently supported.
- *
- * arguments:
- * 1: successcallback - this is the javascript function that will be called with the array of found contacts
- * 2: errorCallback - optional javascript functiont to be called in the event of an error with an error code.
- * options: dictionary containing ContactFields and ContactFindOptions
- * fields - ContactFields array
- * findOptions - ContactFindOptions object as dictionary
- *
- */
-- (void) search:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
-/*
- * save - saves a new contact or updates and existing contact
- *
- * arguments:
- * 1: success callback - this is the javascript function that will be called with the JSON representation of the saved contact
- * search calls a fixed navigator.service.contacts._findCallback which then calls the succes callback stored before making the call into obj. c
- *
- */
-- (void) save:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
-/*
- * remove - removes a contact from the address book
- *
- * arguments:
- * 1: 1: successcallback - this is the javascript function that will be called with a (now) empty contact object
- *
- * options: dictionary containing Contact object to remove
- * contact - Contact object as dictionary
- */
-- (void) remove: (NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
-
-- (void) dealloc;
-
-@end
-
-@interface ContactsPicker : ABPeoplePickerNavigationController
-{
- BOOL allowsEditing;
- NSString* callbackId;
- ABRecordID selectedId;
-}
-
-@property BOOL allowsEditing;
-@property (copy) NSString* callbackId;
-@property ABRecordID selectedId;
-
-@end
-
-@interface NewContactsController : ABNewPersonViewController
-{
- NSString* callbackId;
-}
-@property (copy) NSString* callbackId;
-@end
-
-/* ABPersonViewController does not have any UI to dismiss. Adding navigationItems to it does not work properly, thenavigationItems are lost when the app goes into the background.
- The solution was to create an empty NavController in front of the ABPersonViewController. This
- causes the ABPersonViewController to have a back button. By subclassing the ABPersonViewController,
- we can override viewWillDisappear and take down the entire NavigationController at that time.
- */
-@interface DisplayContactViewController : ABPersonViewController
-{
-
-}
-@property (nonatomic,retain) PGPlugin* contactsPlugin;
-
-
-
-
-@end