diff --git a/ChangeLog b/ChangeLog index 7fdcb0e1c..259246505 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2011-11-13 Wolfgang Sourdeau + + * OpenChange/MAPIStoreContactsMessage.m (-getPrBody:inMemCtx:): + same as below. + + * OpenChange/MAPIStoreAppointmentWrapper.m (-getPrBody:inMemCtx:): + removed parsing hack since things are now done properly from + NGCards. + + * Tests/Unit/TestVersit.m (-test_rendering, -test_parsing): + adapted to new NGCards data structure and improved to test further + important use cases. + 2011-11-10 Wolfgang Sourdeau * Tests/Unit/TestVersit.m: new test module for versit parsing and diff --git a/OGoContentStore/OCSContactFieldExtractor.m b/OGoContentStore/OCSContactFieldExtractor.m index 60e204182..5382ef634 100644 --- a/OGoContentStore/OCSContactFieldExtractor.m +++ b/OGoContentStore/OCSContactFieldExtractor.m @@ -39,27 +39,19 @@ { NSMutableDictionary *fields; NSArray *values; - CardElement *adr; + CardElement *element; NSString *value; - unsigned int max; fields = [NSMutableDictionary dictionaryWithCapacity: 16]; value = [vCard fn]; if (value) [fields setObject: value forKey: @"c_cn"]; - values = [vCard n]; - if (values) - { - max = [values count]; - if (max > 0) - { - [fields setObject: [values objectAtIndex: 0] forKey: @"c_sn"]; - if (max > 1) - [fields setObject: [values objectAtIndex: 1] - forKey: @"c_givenName"]; - } - } + element = [vCard n]; + [fields setObject: [element flattenedValueAtIndex: 0 forKey: @""] + forKey: @"c_sn"]; + [fields setObject: [element flattenedValueAtIndex: 1 forKey: @""] + forKey: @"c_givenName"]; value = [vCard preferredTel]; if (value) [fields setObject: value forKey: @"c_telephoneNumber"]; @@ -67,18 +59,17 @@ if (![value isNotNull]) value = @""; [fields setObject: value forKey: @"c_mail"]; - values = [vCard org]; - max = [values count]; - if (max > 0) - { - [fields setObject: [values objectAtIndex: 0] forKey: @"c_o"]; - if (max > 1) - [fields setObject: [values objectAtIndex: 1] forKey: @"c_ou"]; - } - adr = [vCard preferredAdr]; - if (adr) - [fields setObject: [adr value: 3] forKey: @"c_l"]; - value = [[vCard uniqueChildWithTag: @"X-AIM"] value: 0]; + element = [vCard org]; + [fields setObject: [element flattenedValueAtIndex: 0 forKey: @""] + forKey: @"c_o"]; + [fields setObject: [element flattenedValueAtIndex: 1 forKey: @""] + forKey: @"c_ou"]; + element = [vCard preferredAdr]; + if (element && ![element isVoid]) + [fields setObject: [element flattenedValueAtIndex: 3 + forKey: @""] + forKey: @"c_l"]; + value = [[vCard uniqueChildWithTag: @"X-AIM"] flattenedValuesForKey: @""]; [fields setObject: value forKey: @"c_screenname"]; values = [[vCard categories] trimmedComponents]; if ([values count] > 0) diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index 216ba3795..82753c076 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -1026,17 +1026,11 @@ static NSCharacterSet *hexCharacterSet = nil; { int rc = MAPISTORE_SUCCESS; NSString *stringValue; - NSArray *values; /* FIXME: there is a confusion in NGCards around "comment" and "description" */ stringValue = [event comment]; if ([stringValue length] > 0) - { - /* FIXME: this is a temporary hack: we unescape things although NGVCards - should already have done it at this stage... */ - values = [stringValue asCardAttributeValues]; - *data = [[values objectAtIndex: 0] asUnicodeInMemCtx: memCtx]; - } + *data = [stringValue asUnicodeInMemCtx: memCtx]; else rc = MAPISTORE_ERR_NOT_FOUND; @@ -1411,7 +1405,8 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, { startDate = [event startDate]; relation = [[trigger relationType] lowercaseString]; - interval = [[trigger value] durationAsTimeInterval]; + interval = [[trigger flattenedValuesForKey: @""] + durationAsTimeInterval]; if ([relation isEqualToString: @"end"]) relationDate = [event endDate]; else diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index 5de94e2d6..33b7ffe9d 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -607,7 +607,9 @@ [alarm setAction: @"DISPLAY"]; trigger = [iCalTrigger elementWithTag: @"trigger"]; [trigger setValueType: @"DURATION"]; - [trigger setValue: [NSString stringWithFormat: @"-PT%@M", delta]]; + [trigger + setSingleValue: [NSString stringWithFormat: @"-PT%@M", delta] + forKey: @""]; [alarm setTrigger: trigger]; [newEvent addToAlarms: alarm]; [alarm release]; diff --git a/OpenChange/MAPIStoreContactsAttachment.m b/OpenChange/MAPIStoreContactsAttachment.m index ff010ff7e..99cb65538 100644 --- a/OpenChange/MAPIStoreContactsAttachment.m +++ b/OpenChange/MAPIStoreContactsAttachment.m @@ -142,7 +142,8 @@ extern NSTimeZone *utcTZ; inMemCtx: (TALLOC_CTX *) memCtx { if (!photoData) - ASSIGN (photoData, [[photo value: 0] dataByDecodingBase64]); + ASSIGN (photoData, + [[photo flattenedValuesForKey: @""] dataByDecodingBase64]); *data = [photoData asBinaryInMemCtx: memCtx]; @@ -153,7 +154,8 @@ extern NSTimeZone *utcTZ; inMemCtx: (TALLOC_CTX *) memCtx { if (!photoData) - ASSIGN (photoData, [[photo value: 0] dataByDecodingBase64]); + ASSIGN (photoData, + [[photo flattenedValuesForKey: @""] dataByDecodingBase64]); *data = MAPILongValue (memCtx, [photoData length]); diff --git a/OpenChange/MAPIStoreContactsMessage.m b/OpenChange/MAPIStoreContactsMessage.m index 8b5bd75b8..f2732ecb7 100644 --- a/OpenChange/MAPIStoreContactsMessage.m +++ b/OpenChange/MAPIStoreContactsMessage.m @@ -149,18 +149,11 @@ - (int) getPrCompanyName: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - NSArray *values; - NSString *stringValue; + CardElement *org; - values = [[sogoObject vCard] org]; - stringValue = nil; - - if ([values count] > 0) - stringValue = [values objectAtIndex: 0]; - else - stringValue = @""; - - *data = [stringValue asUnicodeInMemCtx: memCtx]; + org = [[sogoObject vCard] org]; + *data = [[org flattenedValueAtIndex: 0 forKey: @""] + asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } @@ -168,18 +161,11 @@ - (int) getPrDepartmentName: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - NSArray *values; - NSString *stringValue; + CardElement *org; - values = [[sogoObject vCard] org]; - stringValue = nil; - - if ([values count] > 1) - stringValue = [values objectAtIndex: 1]; - else - stringValue = @""; - - *data = [stringValue asUnicodeInMemCtx: memCtx]; + org = [[sogoObject vCard] org]; + *data = [[org flattenedValueAtIndex: 1 forKey: @""] + asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } @@ -314,7 +300,7 @@ max = [emails count]; for (count = 0; !stringValue && count < max; count++) { - email = [[emails objectAtIndex: count] value: 0]; + email = [[emails objectAtIndex: count] flattenedValuesForKey: @""]; if ([email caseInsensitiveCompare: [card preferredEMail]] != NSOrderedSame) stringValue = email; @@ -339,16 +325,10 @@ { int rc = MAPISTORE_SUCCESS; NSString *stringValue; - NSArray *values; stringValue = [[sogoObject vCard] note]; if ([stringValue length] > 0) - { - /* FIXME: this is a temporary hack: we unescape things although NGVCards - should already have done it at this stage... */ - values = [stringValue asCardAttributeValues]; - *data = [[values objectAtIndex: 0] asUnicodeInMemCtx: memCtx]; - } + *data = [stringValue asUnicodeInMemCtx: memCtx]; else rc = MAPISTORE_ERR_NOT_FOUND; @@ -380,7 +360,7 @@ ce = [elements objectAtIndex: count]; if (!aTypeToExclude || ![ce hasAttribute: @"type" havingValue: aTypeToExclude]) - stringValue = [ce value: pos]; + stringValue = [ce flattenedValueAtIndex: pos forKey: @""]; } if (!stringValue) @@ -471,7 +451,7 @@ NSString *stringValue; stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-aim"] - value: 0]; + flattenedValuesForKey: @""]; if (!stringValue) stringValue = @""; *data = [stringValue asUnicodeInMemCtx: memCtx]; @@ -705,7 +685,9 @@ { NSString *stringValue; - stringValue = [[[sogoObject vCard] firstChildWithTag: @"n"] value: 0]; + stringValue = [[[sogoObject vCard] firstChildWithTag: @"n"] + flattenedValueAtIndex: 0 + forKey: @""]; *data = [stringValue asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; @@ -716,7 +698,9 @@ { NSString *stringValue; - stringValue = [[[sogoObject vCard] firstChildWithTag: @"n"] value: 1]; + stringValue = [[[sogoObject vCard] firstChildWithTag: @"n"] + flattenedValueAtIndex: 1 + forKey: @""]; *data = [stringValue asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; @@ -727,7 +711,9 @@ { NSString *stringValue; - stringValue = [[[sogoObject vCard] firstChildWithTag: @"n"] value: 2]; + stringValue = [[[sogoObject vCard] firstChildWithTag: @"n"] + flattenedValueAtIndex: 2 + forKey: @""]; *data = [stringValue asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; @@ -738,7 +724,9 @@ { NSString *stringValue; - stringValue = [[[sogoObject vCard] firstChildWithTag: @"n"] value: 3]; + stringValue = [[[sogoObject vCard] firstChildWithTag: @"n"] + flattenedValueAtIndex: 3 + forKey: @""]; *data = [stringValue asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; @@ -749,7 +737,9 @@ { NSString *stringValue; - stringValue = [[[sogoObject vCard] firstChildWithTag: @"n"] value: 4]; + stringValue = [[[sogoObject vCard] firstChildWithTag: @"n"] + flattenedValueAtIndex: 4 + forKey: @""]; *data = [stringValue asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; @@ -844,9 +834,9 @@ to: photoType]; [photo setValue: 0 ofAttribute: @"encoding" to: @"b"]; - [photo setValue: 0 - to: [content stringByReplacingString: @"\n" - withString: @""]]; + [photo setSingleValue: [content stringByReplacingString: @"\n" + withString: @""] + atIndex: 0 forKey: @""]; } } } @@ -893,7 +883,7 @@ if (value) { if ([elements count] > 0) - [[elements objectAtIndex: 0] setValue: 0 to: value]; + [[elements objectAtIndex: 0] setSingleValue: value forKey: @""]; else [newCard addEmail: value types: [NSArray arrayWithObject: @"pref"]]; @@ -902,7 +892,7 @@ if (value) { if ([elements count] > 1) - [[elements objectAtIndex: 1] setValue: 0 to: value]; + [[elements objectAtIndex: 1] setSingleValue: value forKey: @""]; else [newCard addEmail: value types: nil]; } @@ -910,7 +900,7 @@ if (value) { if ([elements count] > 2) - [[elements objectAtIndex: 2] setValue: 0 to: value]; + [[elements objectAtIndex: 2] setSingleValue: value forKey: @""]; else [newCard addEmail: value types: nil]; } @@ -950,7 +940,7 @@ [element addAttribute: @"type" value: @"pref"]; } - [element setValue: 0 to: value]; + [element setSingleValue: value forKey: @""]; } elements = [newCard childrenWithTag: @"adr" @@ -968,22 +958,22 @@ [element addAttribute: @"type" value: @"pref"]; value = [properties objectForKey: MAPIPropertyKey(PidLidWorkAddressPostOfficeBox)]; if (value) - [element setValue: 0 to: value]; + [element setSingleValue: value atIndex: 0 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PidLidWorkAddressStreet)]; if (value) - [element setValue: 2 to: value]; + [element setSingleValue: value atIndex: 2 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PidLidWorkAddressCity)]; if (value) - [element setValue: 3 to: value]; + [element setSingleValue: value atIndex: 3 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PidLidWorkAddressState)]; if (value) - [element setValue: 4 to: value]; + [element setSingleValue: value atIndex: 4 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PidLidWorkAddressPostalCode)]; if (value) - [element setValue: 5 to: value]; + [element setSingleValue: value atIndex: 5 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PidLidWorkAddressCountry)]; if (value) - [element setValue: 6 to: value]; + [element setSingleValue: value atIndex: 6 forKey: @""]; // // home postal addresses handling @@ -1009,7 +999,7 @@ [element addAttribute: @"type" value: @"pref"]; } - [element setValue: 0 to: value]; + [element setSingleValue: value forKey: @""]; } elements = [newCard childrenWithTag: @"adr" @@ -1028,22 +1018,22 @@ value = [properties objectForKey: MAPIPropertyKey(PR_HOME_ADDRESS_POST_OFFICE_BOX_UNICODE)]; if (value) - [element setValue: 0 to: value]; + [element setSingleValue: value atIndex: 0 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey( PR_HOME_ADDRESS_STREET_UNICODE)]; if (value) - [element setValue: 2 to: value]; + [element setSingleValue: value atIndex: 2 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PR_HOME_ADDRESS_CITY_UNICODE)]; if (value) - [element setValue: 3 to: value]; + [element setSingleValue: value atIndex: 3 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PR_HOME_ADDRESS_STATE_OR_PROVINCE_UNICODE)]; if (value) - [element setValue: 4 to: value]; + [element setSingleValue: value atIndex: 4 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PR_HOME_ADDRESS_POSTAL_CODE_UNICODE)]; if (value) - [element setValue: 5 to: value]; + [element setSingleValue: value atIndex: 5 forKey: @""]; value = [properties objectForKey: MAPIPropertyKey(PR_HOME_ADDRESS_COUNTRY_UNICODE)]; if (value) - [element setValue: 6 to: value]; + [element setSingleValue: value atIndex: 6 forKey: @""]; // @@ -1052,27 +1042,27 @@ element = [self _elementWithTag: @"tel" ofType: @"work" forCard: newCard]; value = [properties objectForKey: MAPIPropertyKey(PR_OFFICE_TELEPHONE_NUMBER_UNICODE)]; if (value) - [element setValue: 0 to: value]; + [element setSingleValue: value forKey: @""]; element = [self _elementWithTag: @"tel" ofType: @"home" forCard: newCard]; value = [properties objectForKey: MAPIPropertyKey(PR_HOME_TELEPHONE_NUMBER_UNICODE)]; if (value) - [element setValue: 0 to: value]; + [element setSingleValue: value forKey: @""]; element = [self _elementWithTag: @"tel" ofType: @"fax" forCard: newCard]; value = [properties objectForKey: MAPIPropertyKey(PR_BUSINESS_FAX_NUMBER_UNICODE)]; if (value) - [element setValue: 0 to: value]; + [element setSingleValue: value forKey: @""]; element = [self _elementWithTag: @"tel" ofType: @"pager" forCard: newCard]; value = [properties objectForKey: MAPIPropertyKey(PR_PAGER_TELEPHONE_NUMBER_UNICODE)]; if (value) - [element setValue: 0 to: value]; + [element setSingleValue: value forKey: @""]; element = [self _elementWithTag: @"tel" ofType: @"cell" forCard: newCard]; value = [properties objectForKey: MAPIPropertyKey(PR_MOBILE_TELEPHONE_NUMBER_UNICODE)]; if (value) - [element setValue: 0 to: value]; + [element setSingleValue: value forKey: @""]; // @@ -1100,15 +1090,14 @@ if (value) { [[self _elementWithTag: @"url" ofType: @"work" forCard: newCard] - setValue: 0 to: value]; + setSingleValue: value forKey: @""]; } value = [properties objectForKey: MAPIPropertyKey(PidLidInstantMessagingAddress)]; if (value) { [[newCard uniqueChildWithTag: @"x-aim"] - setValue: 0 - to: value]; + setSingleValue: value forKey: @""]; } value = [properties objectForKey: MAPIPropertyKey(PR_BIRTHDAY)]; diff --git a/OpenChange/MAPIStoreRecurrenceUtils.m b/OpenChange/MAPIStoreRecurrenceUtils.m index 4026c5b88..010066e43 100644 --- a/OpenChange/MAPIStoreRecurrenceUtils.m +++ b/OpenChange/MAPIStoreRecurrenceUtils.m @@ -96,7 +96,7 @@ [rule setFrequency: iCalRecurrenceFrequenceYearly]; [rule setRepeatInterval: rp->Period / 12]; month = [NSString stringWithFormat: @"%d", [startDate monthOfYear]]; - [rule setNamedValue: @"bymonth" to: month]; + [rule setSingleValue: month forKey: @"bymonth"]; } else [self errorWithFormat: @@ -116,7 +116,7 @@ else monthDay = [NSString stringWithFormat: @"%d", rp->PatternTypeSpecific.MonthRecurrencePattern.N]; - [rule setNamedValue: @"bymonthday" to: monthDay]; + [rule setSingleValue: monthDay forKey: @"bymonthday"]; } else if ((rp->PatternTypeSpecific.MonthRecurrencePattern.WeekRecurrencePattern == 0x3e) /* Nth week day */ @@ -139,8 +139,9 @@ else bySetPos = rp->PatternTypeSpecific.MonthRecurrencePattern.N; - [rule setNamedValue: @"bysetpos" - to: [NSString stringWithFormat: @"%d", bySetPos]]; + [rule + setSingleValue: [NSString stringWithFormat: @"%d", bySetPos] + forKey: @"bysetpos"]; } else { @@ -167,9 +168,10 @@ || (rp->PatternType & 4) == 4) { /* MonthEnd, HjMonth and HjMonthEnd */ - [rule setNamedValue: @"bymonthday" - to: [NSString stringWithFormat: @"%d", - rp->PatternTypeSpecific.Day]]; + [rule + setSingleValue: [NSString stringWithFormat: @"%d", + rp->PatternTypeSpecific.Day] + forKey: @"bymonthday"]; } else [self errorWithFormat: @"invalid value for PatternType: %.4x", @@ -348,7 +350,7 @@ if (mask) { rp->PatternTypeSpecific.MonthRecurrencePattern.WeekRecurrencePattern = mask; - bySetPos = [self namedValue: @"bysetpos"]; + bySetPos = [self flattenedValuesForKey: @"bysetpos"]; if ([bySetPos length]) rp->PatternTypeSpecific.MonthRecurrencePattern.N = ([bySetPos hasPrefix: @"-"] diff --git a/SOPE/NGCards/CardElement.h b/SOPE/NGCards/CardElement.h index 6f59d0ad1..af94a5c49 100644 --- a/SOPE/NGCards/CardElement.h +++ b/SOPE/NGCards/CardElement.h @@ -36,7 +36,7 @@ @interface CardElement : NSObject { NSString *tag; - NSMutableArray *values; + NSMutableDictionary *values; NSMutableDictionary *attributes; NSString *group; CardGroup *parent; @@ -51,31 +51,44 @@ singleType: (NSString *) aType value: (NSString *) aValue; -+ (id) elementWithTag: (NSString *) aTag - attributes: (NSDictionary *) someAttributes - values: (NSArray *) someValues; - - (void) setParent: (CardGroup *) aParent; - (id) parent; - (void) setTag: (NSString *) aTag; +- (NSString *) tag; - (void) setGroup: (NSString *) aGroup; - (NSString *) group; -- (void) addValue: (NSString *) aValue; -- (void) addValues: (NSArray *) someValues; +- (BOOL) isVoid; -- (void) setValue: (unsigned int) anInt - to: (NSString *) aValue; -- (NSString *) value: (unsigned int) anInt; +- (void) setValues: (NSMutableDictionary *) newValues; +- (NSMutableDictionary *) values; -- (void) setNamedValue: (NSString *) aValueName - to: (NSString *) aValue; -- (NSString *) namedValue: (NSString *) aValueName; +/* ELEM:...;value1,value2,...;... */ +- (void) setValues: (NSMutableArray *) newValues + atIndex: (NSUInteger) idx + forKey: (NSString *) key; -- (void) setCommaSeparatedValues: (NSArray *) values; +/* ELEM:...;value;... */ +- (void) setSingleValue: (NSString *) newValue + atIndex: (NSUInteger) idx + forKey: (NSString *) key; +/* ELEM:value */ +- (void) setSingleValue: (NSString *) newValue + forKey: (NSString *) key; +- (NSMutableArray *) valuesForKey: (NSString *) key; +- (NSMutableArray *) valuesAtIndex: (NSUInteger) idx + forKey: (NSString *) key; + +/* This joins all subvalues with "," and ordered values with ";". Handy for + retrieving data from clients which don't escape their data properly. */ +- (NSString *) flattenedValuesForKey: (NSString *) key; +- (NSString *) flattenedValueAtIndex: (NSUInteger) idx + forKey: (NSString *) key; + +/* attribute values */ - (void) setValue: (unsigned int) anInt ofAttribute: (NSString *) anAttribute to: (NSString *) aValue; @@ -87,17 +100,11 @@ - (void) addAttributes: (NSDictionary *) someAttributes; - (void) removeValue: (NSString *) aValue fromAttribute: (NSString *) anAttribute; - -- (void) addType: (NSString *) aType; - -- (NSString *) tag; -- (void) setValues: (NSArray *) newValues; -- (NSArray *) values; -- (NSDictionary *) attributes; +- (NSMutableDictionary *) attributes; - (BOOL) hasAttribute: (NSString *) aType havingValue: (NSString *) aValue; -- (BOOL) isVoid; +- (void) addType: (NSString *) aType; - (NSString *) versitString; diff --git a/SOPE/NGCards/CardElement.m b/SOPE/NGCards/CardElement.m index 49c3913b4..ec4d7404f 100644 --- a/SOPE/NGCards/CardElement.m +++ b/SOPE/NGCards/CardElement.m @@ -56,7 +56,7 @@ id newElement; newElement = [self elementWithTag: aTag]; - [newElement addValue: aValue]; + [newElement setSingleValue: aValue forKey: @""]; return newElement; } @@ -74,21 +74,6 @@ return newElement; } -+ (id) elementWithTag: (NSString *) aTag - attributes: (NSDictionary *) someAttributes - values: (NSArray *) someValues -{ - id newElement; - - newElement = [self new]; - [newElement autorelease]; - [newElement setTag: aTag]; - [newElement addAttributes: someAttributes]; - [newElement addValues: someValues]; - - return newElement; -} - - (id) init { if ((self = [super init])) @@ -96,7 +81,7 @@ parent = nil; tag = nil; group = nil; - values = [NSMutableArray new]; + values = [NSMutableDictionary new]; attributes = [NSMutableDictionary new]; } @@ -142,16 +127,172 @@ return group; } -- (void) addValue: (NSString *) aValue +/* values */ +- (void) setValues: (NSMutableDictionary *) newValues { - if (!aValue) - aValue = @""; - [values addObject: aValue]; + ASSIGN (values, newValues); } -- (void) addValues: (NSArray *) someValues +- (NSMutableDictionary *) values { - [values addObjectsFromArray: someValues]; + return values; +} + +- (void) setValues: (NSMutableArray *) newValues + atIndex: (NSUInteger) idx + forKey: (NSString *) key +{ + NSMutableArray *oldValues, *subValues; + + oldValues = [self valuesForKey: key]; + if (!oldValues) + { + oldValues = [NSMutableArray new]; + [values setObject: oldValues forKey: key]; + [oldValues release]; + } + + while ([oldValues count] < (idx + 1)) + { + subValues = [NSMutableArray new]; + [oldValues addObject: subValues]; + [subValues release]; + } + + if (!newValues) + newValues = [NSMutableArray array]; + [oldValues replaceObjectAtIndex: idx withObject: newValues]; +} + +- (void) setSingleValue: (NSString *) newValue + atIndex: (NSUInteger) idx + forKey: (NSString *) key +{ + NSMutableArray *subValues; + + if (newValue) + { + subValues = [NSMutableArray new]; + [subValues addObject: newValue]; + } + else + subValues = nil; + [self setValues: subValues atIndex: idx forKey: key]; + [subValues release]; +} + +- (void) setSingleValue: (NSString *) newValue + forKey: (NSString *) key +{ + [self setSingleValue: newValue + atIndex: 0 forKey: key]; +} + +- (NSMutableArray *) valuesForKey: (NSString *) key +{ + return [values objectForKey: [key lowercaseString]]; +} + +- (NSMutableArray *) valuesAtIndex: (NSUInteger) idx + forKey: (NSString *) key +{ + return [[self valuesForKey: key] objectAtIndex: idx]; +} + +- (NSString *) flattenedValueAtIndex: (NSUInteger) idx + forKey: (NSString *) key +{ + NSMutableArray *orderedValues, *sValues; + NSUInteger count, max; + NSMutableString *flattenedValues; + NSString *encoding, *realValue, *value; + + flattenedValues = [NSMutableString string]; + + orderedValues = [self valuesForKey: key]; + max = [orderedValues count]; + if (max > idx) + { + encoding = [[self value: 0 ofAttribute: @"encoding"] + lowercaseString]; + sValues = [orderedValues objectAtIndex: idx]; + max = [sValues count]; + for (count = 0; count < max; count++) + { + if (count > 0) + [flattenedValues appendString: @","]; + realValue = [sValues objectAtIndex: count]; + if ([encoding isEqualToString: @"quoted-printable"]) + value = [realValue stringByDecodingQuotedPrintable]; + else if ([encoding isEqualToString: @"base64"]) + value = [realValue stringByDecodingBase64]; + else + { + value = realValue; + if ([encoding length] && ![encoding isEqualToString: @"8bit"]) + [self logWithFormat: @"unknown encoding '%@'", encoding]; + } + + [flattenedValues appendString: value]; + } + } + + return flattenedValues; +} + +- (NSString *) flattenedValuesForKey: (NSString *) key +{ + NSMutableArray *orderedValues, *sValues; + NSUInteger count, max, sCount, sMax; + NSMutableString *flattenedValues; + NSString *encoding, *realValue, *value; + + encoding = [[self value: 0 ofAttribute: @"encoding"] + lowercaseString]; + + flattenedValues = [NSMutableString string]; + + orderedValues = [self valuesForKey: key]; + max = [orderedValues count]; + for (count = 0; count < max; count++) + { + if (count > 0) + [flattenedValues appendString: @";"]; + sValues = [orderedValues objectAtIndex: count]; + sMax = [sValues count]; + for (sCount = 0; sCount < sMax; sCount++) + { + if (sCount > 0) + [flattenedValues appendString: @","]; + realValue = [sValues objectAtIndex: sCount]; + if ([encoding isEqualToString: @"quoted-printable"]) + value = [realValue stringByDecodingQuotedPrintable]; + else if ([encoding isEqualToString: @"base64"]) + value = [realValue stringByDecodingBase64]; + else + { + value = realValue; + if ([encoding length] && ![encoding isEqualToString: @"8bit"]) + [self logWithFormat: @"unknown encoding '%@'", encoding]; + } + + [flattenedValues appendString: value]; + } + } + + return flattenedValues; +} + +/* attributes */ + +- (NSMutableDictionary *) attributes +{ + return attributes; +} + +- (void) setAttributesAsCopy: (NSMutableDictionary *) someAttributes +{ + ASSIGN (attributes, someAttributes); } - (void) addAttribute: (NSString *) anAttribute @@ -219,26 +360,6 @@ [self addAttribute: @"type" value: aType]; } -- (void) setValues: (NSArray *) newValues -{ - if (![newValues isKindOfClass: [NSMutableArray class]]) - { - newValues = [newValues mutableCopy]; - [newValues autorelease]; - } - ASSIGN (values, newValues); -} - -- (NSArray *) values -{ - return values; -} - -- (NSDictionary *) attributes -{ - return attributes; -} - - (BOOL) hasAttribute: (NSString *) anAttribute havingValue: (NSString *) aValue { @@ -249,141 +370,6 @@ return (attribute && [attribute hasCaseInsensitiveString: aValue]); } -- (void) setValue: (unsigned int) anInt - to: (NSString *) aValue -{ - unsigned int count, max; - - if (!aValue) - aValue = @""; - max = [values count]; - for (count = max; count <= anInt; count++) - [self addValue: @""]; - - [values replaceObjectAtIndex: anInt withObject: aValue]; -} - -- (NSString *) value: (unsigned int) anInt -{ - NSString *realValue, *value, *encoding; - - if ([values count] <= anInt) - value = @""; - else - { - realValue = [values objectAtIndex: anInt]; - encoding = [[self value: 0 ofAttribute: @"encoding"] lowercaseString]; - if ([encoding length]) - { - if ([encoding isEqualToString: @"quoted-printable"]) - value = [realValue stringByDecodingQuotedPrintable]; - else if ([encoding isEqualToString: @"base64"]) - value = [realValue stringByDecodingBase64]; - else - { - value = realValue; - if (![encoding isEqualToString: @"8bit"]) - [self logWithFormat: @"unknown encoding '%@'", encoding]; - } - } - else - value = realValue; - } - - return value; -} - -- (unsigned int) _namedValue: (NSString *) aValueName -{ - NSString *prefix, *value; - unsigned int count, max, result; - - result = NSNotFound; - - prefix = [NSString stringWithFormat: @"%@=", [aValueName uppercaseString]]; - max = [values count]; - count = 0; - - while (result == NSNotFound && count < max) - { - value = [[values objectAtIndex: count] uppercaseString]; - if ([value hasPrefix: prefix]) - result = count; - else - count++; - } - - return result; -} - -- (void) setNamedValue: (NSString *) aValueName - to: (NSString *) aValue -{ - NSString *newValue; - unsigned int index; - - if (!aValue) - aValue = @""; - newValue = [NSString stringWithFormat: @"%@=%@", - [aValueName uppercaseString], - aValue]; - index = [self _namedValue: aValueName]; - if (index == NSNotFound) - { - if ([aValue length]) - [self addValue: newValue]; - } - else - { - if ([aValue length]) - [self setValue: index to: newValue]; - else - [values removeObjectAtIndex: index]; - } -} - -- (NSString *) namedValue: (NSString *) aValueName -{ - unsigned int index; - NSRange equalSign; - NSString *value; - - index = [self _namedValue: aValueName]; - if (index == NSNotFound) - value = @""; - else - { - value = [values objectAtIndex: index]; - equalSign = [value rangeOfString: @"="]; - if (equalSign.location != NSNotFound) - value = [value substringFromIndex: equalSign.location + 1]; - } - - return value; -} - -- (void) setCommaSeparatedValues: (NSArray *) newValues -{ - NSMutableString *newValue; - NSUInteger count, max; - NSString *currentValue; - - newValue = [NSMutableString stringWithCapacity: 250]; - - max = [newValues count]; - for (count = 0; count < max; count++) - { - currentValue = [[newValues objectAtIndex: count] - stringByReplacingString: @"," - withString: @"\\,"]; - if (count > 0) - [newValue appendFormat: @",%@", currentValue]; - else - [newValue appendString: currentValue]; - } - [self setValues: [NSArray arrayWithObject: newValue]]; -} - - (void) setValue: (unsigned int) anInt ofAttribute: (NSString *) anAttribute to: (NSString *) aValue @@ -423,10 +409,7 @@ - (NSString *) description { - NSArray *attrs; NSMutableString *str; - unsigned int count, max; - NSString *attr; str = [NSMutableString stringWithCapacity:64]; [str appendFormat:@"<%p[%@]:", self, NSStringFromClass([self class])]; @@ -435,48 +418,56 @@ else [str appendFormat: @"%@\n", tag, group]; - attrs = [attributes allKeys]; - max = [attrs count]; - if (max > 0) - { - [str appendFormat: @"\n %d attributes: {\n", [attrs count]]; - for (count = 0; count < max; count++) - { - attr = [attrs objectAtIndex: count]; - [str appendFormat: @" %@: %@\n", - attr, [attributes objectForKey: attr]]; - } - [str appendFormat: @"}"]; - } - - max = [values count]; - if (max > 0) - { - [str appendFormat: @"\n %d values: {\n", [values count]]; - for (count = 0; count < max; count++) - [str appendFormat: @" %@\n", [values objectAtIndex: count]]; - [str appendFormat: @"}"]; - } - - [str appendString:@">"]; + [str appendString: [self versitString]]; return str; } -- (BOOL) isVoid +static inline BOOL +_subValuesAreVoid (NSArray *subValues) { - BOOL result; - NSString *value; - NSEnumerator *enu; + BOOL result = YES; + NSUInteger count, max; result = YES; - enu = [values objectEnumerator]; - value = [enu nextObject]; - while (value && result) + max = [subValues count]; + for (count = 0; result && count < max; count++) + result = ([[subValues objectAtIndex: count] length] == 0); + + return result; +} + +static inline BOOL +_orderedValuesAreVoid (NSArray *orderedValues) +{ + BOOL result = YES; + NSUInteger count, max; + + result = YES; + + max = [orderedValues count]; + for (count = 0; result && count < max; count++) + result = _subValuesAreVoid ([orderedValues objectAtIndex: count]); + + return result; +} + +- (BOOL) isVoid +{ + BOOL result = YES; + NSArray *keys; + NSMutableArray *orderedValues; + NSUInteger count, max; + + result = YES; + + keys = [values allKeys]; + max = [keys count]; + for (count = 0; result && count < max; count++) { - result = ([value length] == 0); - value = [enu nextObject]; + orderedValues = [values objectForKey: [keys objectAtIndex: count]]; + result = _orderedValuesAreVoid (orderedValues); } return result; @@ -523,11 +514,6 @@ return newElement; } -- (void) setAttributesAsCopy: (NSMutableDictionary *) someAttributes -{ - ASSIGN (attributes, someAttributes); -} - - (CardGroup *) searchParentOfClass: (Class) parentClass { CardGroup *current; @@ -594,7 +580,7 @@ newGroup = [group copyWithZone: aZone]; [new setGroup: newGroup]; [newGroup release]; - [new setValues: [self deepCopyOfArray: values withZone: aZone]]; + [new setValues: [self deepCopyOfDictionary: values withZone: aZone]]; [new setAttributesAsCopy: [self deepCopyOfDictionary: attributes withZone: aZone]]; @@ -604,22 +590,7 @@ /* NSMutableCopying */ - (id) mutableCopyWithZone: (NSZone *) aZone { -#warning this method really is the same as "copyWithZone:" - CardElement *new; - NSString *newTag, *newGroup; - - new = [[self class] new]; - newTag = [tag copyWithZone: aZone]; - [new setTag: newTag]; - [newTag release]; - newGroup = [group copyWithZone: aZone]; - [new setGroup: newGroup]; - [newGroup release]; - [new setValues: [self deepCopyOfArray: values withZone: aZone]]; - [new setAttributesAsCopy: [self deepCopyOfDictionary: attributes - withZone: aZone]]; - - return new; + return [self copyWithZone: aZone]; } @end diff --git a/SOPE/NGCards/CardGroup.m b/SOPE/NGCards/CardGroup.m index 8af47506b..c6ef8bb62 100644 --- a/SOPE/NGCards/CardGroup.m +++ b/SOPE/NGCards/CardGroup.m @@ -281,7 +281,7 @@ static NGCardsSaxHandler *sax = nil; havingValue: (NSString *) aValue { return [children cardElementsWithAttribute: anAttribute - havingValue: aValue]; + havingValue: aValue]; } - (NSArray *) childrenWithTag: (NSString *) aTag @@ -293,7 +293,7 @@ static NGCardsSaxHandler *sax = nil; elements = [self childrenWithTag: aTag]; return [elements cardElementsWithAttribute: anAttribute - havingValue: aValue]; + havingValue: aValue]; } - (NSArray *) childrenGroupWithTag: (NSString *) aTag @@ -313,7 +313,8 @@ static NGCardsSaxHandler *sax = nil; { if ([element isKindOfClass: [CardGroup class]]) { - value = [[element uniqueChildWithTag: aChild] value: 0]; + value = [[element uniqueChildWithTag: aChild] + flattenedValuesForKey: @""]; if ([value isEqualToString: aValue]) [elements addObject: element]; } diff --git a/SOPE/NGCards/CardVersitRenderer.m b/SOPE/NGCards/CardVersitRenderer.m index 71677fcd0..35e50d0e7 100644 --- a/SOPE/NGCards/CardVersitRenderer.m +++ b/SOPE/NGCards/CardVersitRenderer.m @@ -31,7 +31,7 @@ #import "CardGroup.h" #import "NSString+NGCards.h" -#import "NSArray+NGCards.h" +#import "NSDictionary+NGCards.h" #import "CardVersitRenderer.h" @@ -55,9 +55,8 @@ { NSMutableString *rendering; NSDictionary *attributes; - NSEnumerator *keys; - NSArray *values, *renderedAttrs; - NSString *key, *finalRendering, *tag; + NSMutableDictionary *values; + NSString *finalRendering, *tag; if (![anElement isVoid]) { @@ -76,41 +75,16 @@ /* parameters */ attributes = [anElement attributes]; - keys = [[attributes allKeys] objectEnumerator]; - while ((key = [keys nextObject])) + if ([attributes count]) { - NSString *s; - int i, c; - - renderedAttrs = [[attributes objectForKey: key] renderedForCards]; - c = [renderedAttrs count]; - if (c > 0) - { - [rendering appendFormat: @";%@=", [key uppercaseString]]; - - for (i = 0; i < c; i++) - { - s = [renderedAttrs objectAtIndex: i]; - - /* We MUST quote attribute values that have a ":" in them - and that not already quoted */ - if ([s length] > 2 && [s rangeOfString: @":"].length && - [s characterAtIndex: 0] != '"' && ![s hasSuffix: @"\""]) - s = [NSString stringWithFormat: @"\"%@\"", s]; - - [rendering appendFormat: @"%@", s]; - - if (i+1 < c) - [rendering appendString: @","]; - } - } + [rendering appendString: @";"]; + [attributes versitRenderInString: rendering asAttributes: YES]; } /* values */ values = [anElement values]; - if ([values count] > 0) - [rendering appendFormat: @":%@", - [[values renderedForCards] componentsJoinedByString: @";"]]; + [rendering appendString: @":"]; + [values versitRenderInString: rendering asAttributes: NO]; if ([rendering length] > 0) [rendering appendString: @"\r\n"]; @@ -143,12 +117,8 @@ groupTag = [groupTag uppercaseString]; [rendering appendFormat: @"BEGIN:%@\r\n", groupTag]; children = [[aGroup children] objectEnumerator]; - currentChild = [children nextObject]; - while (currentChild) - { - [rendering appendString: [self render: currentChild]]; - currentChild = [children nextObject]; - } + while ((currentChild = [children nextObject])) + [rendering appendString: [self render: currentChild]]; [rendering appendFormat: @"END:%@\r\n", groupTag]; return rendering; diff --git a/SOPE/NGCards/ChangeLog b/SOPE/NGCards/ChangeLog index 67f5bfa01..fd6b23d98 100644 --- a/SOPE/NGCards/ChangeLog +++ b/SOPE/NGCards/ChangeLog @@ -1,3 +1,31 @@ +2011-11-13 Wolfgang Sourdeau + + * iCalTrigger.m (-setValue:, value): removed useless accessors. + + * iCalAttachment.m (-setValue:, value): removed useless accessors. + + * iCalRecurrenceRule.m (-setRrule): now makes use of the existing + parsing algorithm and get the values from the parsed element. + + * iCalEntityObject.m (-setCategories:): now take an array as + parameter. + + * NSString+NGCards.m (-vCardSubvalues): new method adapted to the + new CardElement data structure, replaces + "vCardSubvaluesWithSeparator:", since we now know how to properly + separate or escape elements. + + * CardElement.m (-init): "values" in now an NSMutableDictionary. + (-setValues:, -values): new primitive accessors; + (-setValues:atIndex:forKey:, -setSingleValue:atIndex:forKey:) + (setSingleValue:forKey:): new helper setters. + (-flattenedValueAtIndex:forKey:, -flattenedValues:forKey:): new + "flattened" helper getters. "Flattening" meaning here that the + first and/or second level array are merged with "," and ";", to + support clients that badly escape(d) their output for fields + taking only one value or a specific set of values. + (-valuesForKey:,-valuesAtIndex:forKey:): new helper getters + 2011-11-09 Wolfgang Sourdeau * NSString+NGCards.m (-escapedForCards): restored the escaping of diff --git a/SOPE/NGCards/NGCardsSaxHandler.h b/SOPE/NGCards/NGCardsSaxHandler.h index 189fc777a..0dc2fa354 100644 --- a/SOPE/NGCards/NGCardsSaxHandler.h +++ b/SOPE/NGCards/NGCardsSaxHandler.h @@ -69,7 +69,7 @@ /* content */ - (void) startCollectingContent; -- (NSArray *) finishCollectingContent; +- (NSMutableDictionary *) finishCollectingContent; - (void) startGroupElement: (NSString *) _localName; - (void) endGroupElement; diff --git a/SOPE/NGCards/NGCardsSaxHandler.m b/SOPE/NGCards/NGCardsSaxHandler.m index cf5beac68..f8cddc53e 100644 --- a/SOPE/NGCards/NGCardsSaxHandler.m +++ b/SOPE/NGCards/NGCardsSaxHandler.m @@ -181,7 +181,7 @@ else if ([_localName isEqualToString: @"container"]) [self endGroupElement]; else - [currentElement addValues: [self finishCollectingContent]]; + [currentElement setValues: [self finishCollectingContent]]; } /* content */ @@ -197,9 +197,9 @@ vcs.collectContent = 1; } -- (NSArray *) finishCollectingContent +- (NSMutableDictionary *) finishCollectingContent { - NSArray *contentValues; + NSMutableDictionary *contentValues; NSString *s; vcs.collectContent = 0; @@ -211,7 +211,7 @@ free (content); content = NULL; // NSLog (@"content: '%@'", s); - contentValues = [s vCardSubvaluesWithSeparator: ';']; + contentValues = [s vCardSubvalues]; } else contentValues = nil; diff --git a/SOPE/NGCards/NGVCard.h b/SOPE/NGCards/NGVCard.h index 7e11bd6a0..1d3696c63 100644 --- a/SOPE/NGCards/NGVCard.h +++ b/SOPE/NGCards/NGVCard.h @@ -117,11 +117,12 @@ typedef enum additional: (NSString *) additional prefixes: (NSString *) prefixes suffixes: (NSString *) suffixes; -- (NSArray *) n; +/* returns an array of single values */ +- (CardElement *) n; - (void) setOrg: (NSString *) anOrg units: (NSArray *) someUnits; -- (NSArray *) org; +- (CardElement *) org; - (void) setCategories: (NSArray *) newCategories; - (NSArray *) categories; diff --git a/SOPE/NGCards/NGVCard.m b/SOPE/NGCards/NGVCard.m index 2d44cfd72..97bcc92a0 100644 --- a/SOPE/NGCards/NGVCard.m +++ b/SOPE/NGCards/NGVCard.m @@ -116,134 +116,134 @@ /* accessors */ -- (void) setVersion: (NSString *) _version +- (void) setVersion: (NSString *) _value { - [[self uniqueChildWithTag: @"version"] setValue: 0 to: _version]; + [[self uniqueChildWithTag: @"version"] setSingleValue: _value forKey: @""]; } - (NSString *) version { - return [[self uniqueChildWithTag: @"version"] value: 0]; + return [[self uniqueChildWithTag: @"version"] flattenedValuesForKey: @""]; } -- (void) setUid: (NSString *) _uid +- (void) setUid: (NSString *) _value { - [[self uniqueChildWithTag: @"uid"] setValue: 0 to: _uid]; + [[self uniqueChildWithTag: @"uid"] setSingleValue: _value forKey: @""]; } - (NSString *) uid { - return [[self uniqueChildWithTag: @"uid"] value: 0]; + return [[self uniqueChildWithTag: @"uid"] flattenedValuesForKey: @""]; } -- (void) setVClass: (NSString *) _class +- (void) setVClass: (NSString *) _value { - [[self uniqueChildWithTag: @"class"] setValue: 0 to: _class]; + [[self uniqueChildWithTag: @"class"] setSingleValue: _value forKey: @""]; } - (NSString *) vClass { - return [[self uniqueChildWithTag: @"class"] value: 0]; + return [[self uniqueChildWithTag: @"class"] flattenedValuesForKey: @""]; } - (void) setProdID: (NSString *) _value { - [[self uniqueChildWithTag: @"prodid"] setValue: 0 to: _value]; + [[self uniqueChildWithTag: @"prodid"] setSingleValue: _value forKey: @""]; } - (NSString *) prodID { - return [[self uniqueChildWithTag: @"prodid"] value: 0]; + return [[self uniqueChildWithTag: @"prodid"] flattenedValuesForKey: @""]; } - (void) setProfile: (NSString *) _value { - [[self uniqueChildWithTag: @"profile"] setValue: 0 to: _value]; + [[self uniqueChildWithTag: @"profile"] setSingleValue: _value forKey: @""]; } - (NSString *) profile { - return [[self uniqueChildWithTag: @"profile"] value: 0]; + return [[self uniqueChildWithTag: @"profile"] flattenedValuesForKey: @""]; } - (void) setSource: (NSString *) _value { - [[self uniqueChildWithTag: @"source"] setValue: 0 to: _value]; + [[self uniqueChildWithTag: @"source"] setSingleValue: _value forKey: @""]; } - (NSString *) source { - return [[self uniqueChildWithTag: @"source"] value: 0]; + return [[self uniqueChildWithTag: @"source"] flattenedValuesForKey: @""]; } - (void) setFn: (NSString *) _value { - [[self uniqueChildWithTag: @"fn"] setValue: 0 to: _value]; + [[self uniqueChildWithTag: @"fn"] setSingleValue: _value forKey: @""]; } - (NSString *) fn { - return [[self uniqueChildWithTag: @"fn"] value: 0]; + return [[self uniqueChildWithTag: @"fn"] flattenedValuesForKey: @""]; } - (void) setRole: (NSString *) _value { - [[self uniqueChildWithTag: @"role"] setValue: 0 to: _value]; + [[self uniqueChildWithTag: @"role"] setSingleValue: _value forKey: @""]; } - (NSString *) role { - return [[self uniqueChildWithTag: @"role"] value: 0]; + return [[self uniqueChildWithTag: @"role"] flattenedValuesForKey: @""]; } -- (void) setTitle: (NSString *) _title +- (void) setTitle: (NSString *) _value { - [[self uniqueChildWithTag: @"title"] setValue: 0 to: _title]; + [[self uniqueChildWithTag: @"title"] setSingleValue: _value forKey: @""]; } - (NSString *) title { - return [[self uniqueChildWithTag: @"title"] value: 0]; + return [[self uniqueChildWithTag: @"title"] flattenedValuesForKey: @""]; } - (void) setBday: (NSString *) _value { - [[self uniqueChildWithTag: @"bday"] setValue: 0 to: _value]; + [[self uniqueChildWithTag: @"bday"] setSingleValue: _value forKey: @""]; } - (NSString *) bday { - return [[self uniqueChildWithTag: @"bday"] value: 0]; + return [[self uniqueChildWithTag: @"bday"] flattenedValuesForKey: @""]; } - (void) setNote: (NSString *) _value { - [[self uniqueChildWithTag: @"note"] setValue: 0 to: _value]; + [[self uniqueChildWithTag: @"note"] setSingleValue: _value forKey: @""]; } - (NSString *) note { - return [[self uniqueChildWithTag: @"note"] value: 0]; + return [[self uniqueChildWithTag: @"note"] flattenedValuesForKey: @""]; } - (void) setTz: (NSString *) _value { - [[self uniqueChildWithTag: @"tz"] setValue: 0 to: _value]; + [[self uniqueChildWithTag: @"tz"] setSingleValue: _value forKey: @""]; } - (NSString *) tz { - return [[self uniqueChildWithTag: @"tz"] value: 0]; + return [[self uniqueChildWithTag: @"tz"] flattenedValuesForKey: @""]; } - (void) setNickname: (NSString *) _value { - [[self uniqueChildWithTag: @"nickname"] setValue: 0 to: _value]; + [[self uniqueChildWithTag: @"nickname"] setSingleValue: _value forKey: @""]; } - (NSString *) nickname { - return [[self uniqueChildWithTag: @"nickname"] value: 0]; + return [[self uniqueChildWithTag: @"nickname"] flattenedValuesForKey: @""]; } - (void) addTel: (NSString *) phoneNumber @@ -270,20 +270,20 @@ n = [self uniqueChildWithTag: @"n"]; if (family) - [n setValue: 0 to: family]; + [n setSingleValue: family atIndex: 0 forKey: @""]; if (given) - [n setValue: 1 to: given]; + [n setSingleValue: given atIndex: 1 forKey: @""]; if (additional) - [n setValue: 2 to: additional]; + [n setSingleValue: additional atIndex: 2 forKey: @""]; if (prefixes) - [n setValue: 3 to: prefixes]; + [n setSingleValue: prefixes atIndex: 3 forKey: @""]; if (suffixes) - [n setValue: 4 to: suffixes]; + [n setSingleValue: suffixes atIndex: 4 forKey: @""]; } -- (NSArray *) n +- (CardElement *) n { - return [[self uniqueChildWithTag: @"n"] values]; + return [self uniqueChildWithTag: @"n"]; } - (void) setOrg: (NSString *) anOrg @@ -294,35 +294,30 @@ org = [self uniqueChildWithTag: @"org"]; if (anOrg) - [org setValue: 0 to: anOrg]; + [org setSingleValue: anOrg atIndex: 0 forKey: @""]; if (someUnits) { max = [someUnits count]; for (count = 0; count < max; count++) - [org setValue: count + 1 to: [someUnits objectAtIndex: count]]; + [org setSingleValue: [someUnits objectAtIndex: count] + atIndex: count + 1 forKey: @""]; } } -- (NSArray *) org +- (CardElement *) org { - NSArray *elements, *org; - - elements = [self childrenWithTag: @"org"]; - if ([elements count] > 0) - org = [[elements objectAtIndex: 0] values]; - else - org = nil; - - return org; + return [self uniqueChildWithTag: @"org"]; } - (void) setCategories: (NSArray *) newCategories { CardElement *cats; + NSMutableArray *copy; cats = [self uniqueChildWithTag: @"categories"]; - - [cats setCommaSeparatedValues: newCategories]; + copy = [newCategories mutableCopy]; + [cats setValues: copy atIndex: 0 forKey: @""]; + [copy release]; } - (NSArray *) categories @@ -331,7 +326,7 @@ cats = [self uniqueChildWithTag: @"categories"]; - return [[cats value: 0] vCardSubvaluesWithSeparator: ',']; + return [cats valuesAtIndex: 0 forKey: @""]; } // - (void) setOrg: (NGVCardOrg *) _v @@ -461,12 +456,12 @@ - (NSString *) preferredEMail { - return [[self _preferredElementWithTag: @"email"] value: 0]; + return [[self _preferredElementWithTag: @"email"] flattenedValuesForKey: @""]; } - (NSString *) preferredTel { - return [[self _preferredElementWithTag: @"tel"] value: 0]; + return [[self _preferredElementWithTag: @"tel"] flattenedValuesForKey: @""]; } - (CardElement *) preferredAdr diff --git a/SOPE/NGCards/NGVCardPhoto.m b/SOPE/NGCards/NGVCardPhoto.m index 263054f59..427d50389 100644 --- a/SOPE/NGCards/NGVCardPhoto.m +++ b/SOPE/NGCards/NGVCardPhoto.m @@ -21,6 +21,7 @@ */ #import +#import #import #import @@ -61,9 +62,11 @@ { /* We bypass -[values:] because we want to obtain the undecoded value first. */ - if ([values count] > 0) + if ([values count] > 0 && [[values objectForKey: @""] count] > 0 && + [[[values objectForKey: @""] objectAtIndex: 0] count] > 0) { - value = [values objectAtIndex: 0]; + value = [[[values objectForKey: @""] objectAtIndex: 0] + componentsJoinedByString: @","]; decodedContent = [value dataByDecodingBase64]; } else diff --git a/SOPE/NGCards/NGVCardReference.m b/SOPE/NGCards/NGVCardReference.m index 31da7fa51..389fcba7f 100644 --- a/SOPE/NGCards/NGVCardReference.m +++ b/SOPE/NGCards/NGVCardReference.m @@ -48,12 +48,12 @@ - (void) setReference: (NSString *) newReference { - [self setValue: 0 to: newReference]; + [self setSingleValue: newReference forKey: @""]; } - (NSString *) reference { - return [self value: 0]; + return [self flattenedValuesForKey: @""]; } @end diff --git a/SOPE/NGCards/NGVList.m b/SOPE/NGCards/NGVList.m index 3e85fa6ea..fc9d927b1 100644 --- a/SOPE/NGCards/NGVList.m +++ b/SOPE/NGCards/NGVList.m @@ -77,45 +77,45 @@ - (void) setProdID: (NSString *) newProdID { - [[self uniqueChildWithTag: @"prodid"] setValue: 0 to: newProdID]; + [[self uniqueChildWithTag: @"prodid"] setSingleValue: newProdID forKey: @""]; } - (NSString *) prodID { - return [[self uniqueChildWithTag: @"prodid"] value: 0]; + return [[self uniqueChildWithTag: @"prodid"] flattenedValuesForKey: @""]; } - (void) setVersion: (NSString *) newVersion { - [[self uniqueChildWithTag: @"version"] setValue: 0 - to: newVersion]; + [[self uniqueChildWithTag: @"version"] setSingleValue: newVersion + forKey: @""]; } - (NSString *) version { - return [[self uniqueChildWithTag: @"version"] value: 0]; + return [[self uniqueChildWithTag: @"version"] flattenedValuesForKey: @""]; } - (void) setUid: (NSString *) newUid { - [[self uniqueChildWithTag: @"uid"] setValue: 0 - to: newUid]; + [[self uniqueChildWithTag: @"uid"] setSingleValue: newUid + forKey: @""]; } - (NSString *) uid { - return [[self uniqueChildWithTag: @"uid"] value: 0]; + return [[self uniqueChildWithTag: @"uid"] flattenedValuesForKey: @""]; } - (void) setAccessClass: (NSString *) newAccessClass { - [[self uniqueChildWithTag: @"class"] setValue: 0 - to: newAccessClass]; + [[self uniqueChildWithTag: @"class"] setSingleValue: newAccessClass + forKey: @""]; } - (NSString *) accessClass { - return [[self uniqueChildWithTag: @"class"] value: 0]; + return [[self uniqueChildWithTag: @"class"] flattenedValuesForKey: @""]; } - (NGCardsAccessClass) symbolicAccessClass @@ -141,34 +141,34 @@ - (void) setFn: (NSString *) newFn { - [[self uniqueChildWithTag: @"fn"] setValue: 0 to: newFn]; + [[self uniqueChildWithTag: @"fn"] setSingleValue: newFn forKey: @""]; } - (NSString *) fn { - return [[self uniqueChildWithTag: @"fn"] value: 0]; + return [[self uniqueChildWithTag: @"fn"] flattenedValuesForKey: @""]; } - (void) setNickname: (NSString *) newNickname { - [[self uniqueChildWithTag: @"nickname"] setValue: 0 - to: newNickname]; + [[self uniqueChildWithTag: @"nickname"] setSingleValue: newNickname + forKey: @""]; } - (NSString *) nickname { - return [[self uniqueChildWithTag: @"nickname"] value: 0]; + return [[self uniqueChildWithTag: @"nickname"] flattenedValuesForKey: @""]; } - (void) setDescription: (NSString *) newDescription { - [[self uniqueChildWithTag: @"description"] setValue: 0 - to: newDescription]; + [[self uniqueChildWithTag: @"description"] setSingleValue: newDescription + forKey: @""]; } - (NSString *) description { - return [[self uniqueChildWithTag: @"description"] value: 0]; + return [[self uniqueChildWithTag: @"description"] flattenedValuesForKey: @""]; } - (void) addCardReference: (NGVCardReference *) newCardRef diff --git a/SOPE/NGCards/NSArray+NGCards.h b/SOPE/NGCards/NSArray+NGCards.h index 9b6c23ad0..d77965165 100644 --- a/SOPE/NGCards/NSArray+NGCards.h +++ b/SOPE/NGCards/NSArray+NGCards.h @@ -35,8 +35,6 @@ - (NSArray *) cardElementsWithAttribute: (NSString *) anAttribute havingValue: (NSString *) aValue; -- (NSArray *) renderedForCards; - @end #endif /* NSARRAY_NGCARDS_H */ diff --git a/SOPE/NGCards/NSArray+NGCards.m b/SOPE/NGCards/NSArray+NGCards.m index edda2f7a7..84ff07e38 100644 --- a/SOPE/NGCards/NSArray+NGCards.m +++ b/SOPE/NGCards/NSArray+NGCards.m @@ -99,32 +99,4 @@ return matchingElements; } -- (NSArray *) renderedForCards -{ - NSMutableArray *purified; - NSString *string; - int count, max, lastInsert; - - max = [self count]; - purified = [NSMutableArray arrayWithCapacity: max]; - - lastInsert = -1; - for (count = 0; count < max; count++) - { - string = [self objectAtIndex: count]; - if ([string length] > 0) - { - while (lastInsert < (count - 1)) - { - [purified addObject: @""]; - lastInsert++; - } - [purified addObject: [string escapedForCards]]; - lastInsert = count; - } - } - - return purified; -} - @end diff --git a/SOPE/NGCards/NSDictionary+NGCards.h b/SOPE/NGCards/NSDictionary+NGCards.h index 00249762c..8def7d6a1 100644 --- a/SOPE/NGCards/NSDictionary+NGCards.h +++ b/SOPE/NGCards/NSDictionary+NGCards.h @@ -29,6 +29,9 @@ - (id) objectForCaseInsensitiveKey: (NSString *) aKey; +- (void) versitRenderInString: (NSMutableString *) aString + asAttributes: (BOOL) asAttribute; /* handling of ":" */ + @end #endif /* NSDICTIONARY_NGCARDS_H */ diff --git a/SOPE/NGCards/NSDictionary+NGCards.m b/SOPE/NGCards/NSDictionary+NGCards.m index fe890085d..9360154bd 100644 --- a/SOPE/NGCards/NSDictionary+NGCards.m +++ b/SOPE/NGCards/NSDictionary+NGCards.m @@ -20,10 +20,95 @@ * Boston, MA 02111-1307, USA. */ +#import +#import + #import "NSArray+NGCards.h" +#import "NSString+NGCards.h" #import "NSDictionary+NGCards.h" +@interface NSArray (NGCardsVersit) + +- (BOOL) _renderAsSubValuesInString: (NSMutableString *) aString + asAttributes: (BOOL) asAttributes; +- (BOOL) _renderAsOrderedValuesInString: (NSMutableString *) aString + withKey: (NSString *) key; + +@end + +@implementation NSArray (NGCardsVersit) + +- (BOOL) _renderAsSubValuesInString: (NSMutableString *) aString + asAttributes: (BOOL) asAttributes +{ + NSUInteger count, max; + NSString *subValue, *escaped; + BOOL previousWasEmpty = YES, rendered = NO; + + max = [self count]; + for (count = 0; count < max; count++) + { + if (!previousWasEmpty) + [aString appendString: @","]; + subValue = [self objectAtIndex: count]; + + /* We MUST quote attribute values that have a ":" in them + and that not already quoted */ + if (asAttributes && [subValue length] > 2 + && [subValue rangeOfString: @":"].length + && [subValue characterAtIndex: 0] != '"' + && ![subValue hasSuffix: @"\""]) + subValue = [NSString stringWithFormat: @"\"%@\"", subValue]; + + escaped = [subValue escapedForCards]; + if ([escaped length] > 0) + { + [aString appendString: escaped]; + previousWasEmpty = NO; + rendered = YES; + } + else + previousWasEmpty = YES; + } + + return rendered; +} + +- (BOOL) _renderAsOrderedValuesInString: (NSMutableString *) aString + withKey: (NSString *) key +{ + NSUInteger count, max, lastRendered = 0; + BOOL rendered = NO; + NSArray *subValues; + NSMutableString *substring; + + max = [self count]; + for (count = 0; count < max; count++) + { + subValues = [self objectAtIndex: count]; + substring = [NSMutableString string]; + if ([subValues _renderAsSubValuesInString: substring + asAttributes: NO]) + { + if (lastRendered == 0 && [key length] > 0) + [aString appendFormat: @"%@=", key]; + + while (lastRendered < count) + { + [aString appendString: @";"]; + lastRendered++; + } + [aString appendString: substring]; + rendered = YES; + } + } + + return rendered; +} + +@end + @implementation NSDictionary (NGCardsExtension) - (id) objectForCaseInsensitiveKey: (NSString *) aKey @@ -37,4 +122,43 @@ return ((realKey) ? [self objectForKey: realKey] : nil); } +- (void) versitRenderInString: (NSMutableString *) aString + asAttributes: (BOOL) asAttributes +{ + NSArray *keys; + NSUInteger count, max, rendered = 0; + NSArray *orderedValues; + NSString *key; + NSMutableString *substring; + + keys = [self allKeys]; + max = [keys count]; + for (count = 0; count < max; count++) + { + key = [keys objectAtIndex: count]; + orderedValues = [self objectForKey: key]; + substring = [NSMutableString string]; + if (asAttributes) + { + if ([orderedValues _renderAsSubValuesInString: substring + asAttributes: YES]) + { + if (rendered > 0) + [aString appendString: @";"]; + [aString appendFormat: @"%@=%@", + [key uppercaseString], substring]; + rendered++; + } + } + else if ([orderedValues _renderAsOrderedValuesInString: substring + withKey: [key uppercaseString]]) + { + if (rendered > 0) + [aString appendString: @";"]; + [aString appendString: substring]; + rendered++; + } + } +} + @end diff --git a/SOPE/NGCards/NSString+NGCards.h b/SOPE/NGCards/NSString+NGCards.h index 1fdb9bfb0..b4cca93ff 100644 --- a/SOPE/NGCards/NSString+NGCards.h +++ b/SOPE/NGCards/NSString+NGCards.h @@ -27,6 +27,7 @@ @class NSArray; @class NSCalendarDate; +@class NSMutableDictionary; @class NSTimeZone; @interface NSString (NGCardsExtensions) @@ -40,7 +41,7 @@ - (NSCalendarDate *) asCalendarDate; - (BOOL) isAllDayDate; -- (NSArray *) vCardSubvaluesWithSeparator: (unichar) separator; +- (NSMutableDictionary *) vCardSubvalues; @end diff --git a/SOPE/NGCards/NSString+NGCards.m b/SOPE/NGCards/NSString+NGCards.m index 7614e100a..e46b2e29d 100644 --- a/SOPE/NGCards/NSString+NGCards.m +++ b/SOPE/NGCards/NSString+NGCards.m @@ -21,6 +21,7 @@ */ #import +#import #import #import #import @@ -316,25 +317,35 @@ return ([self length] == 8); } -- (NSArray *) vCardSubvaluesWithSeparator: (unichar) separator +- (NSMutableDictionary *) vCardSubvalues { - NSMutableArray *components; + /* This schema enables things like this: + ELEM;...:KEY1=subvalue1;KEY2=subvalue1,subvalue2 + or + ELEM;...:subvalue1;subvalue1,subvalue2 (where KEY = @"") */ + NSMutableDictionary *values; /* key <> ordered values associations */ + NSMutableArray *orderedValues = nil; /* those are separated by ';' and contain + subvalues, may or may not be named */ + NSMutableArray *subValues = nil; /* those are separeted by ',' */ unichar *stringBuffer, *substringBuffer; - NSString *substring; + NSString *valuesKey, *substring; unichar currentChar; NSUInteger substringLength, count, max; - BOOL escaped; + BOOL escaped = NO; - components = [NSMutableArray arrayWithCapacity: 5]; + values = [NSMutableDictionary dictionary]; + valuesKey = @""; max = [self length]; - stringBuffer = NSZoneMalloc (NULL, sizeof (unichar) * max); + stringBuffer = NSZoneMalloc (NULL, sizeof (unichar) * max + 1); [self getCharacters: stringBuffer]; - substringLength = 0; - escaped = NO; + stringBuffer[max] = 0; substringBuffer = NSZoneMalloc (NULL, sizeof (unichar) * max); + substringLength = 0; + max += 1; /* we add one step to force the inclusion of the ending '\0' in + the loop */ for (count = 0; count < max; count++) { currentChar = stringBuffer[count]; @@ -343,7 +354,7 @@ escaped = NO; if (currentChar == 'n' || currentChar == 'N') substringBuffer[substringLength] = '\n'; - else if (currentChar == 'r') + else if (currentChar == 'r' || currentChar == 'R') substringBuffer[substringLength] = '\r'; else substringBuffer[substringLength] = currentChar; @@ -353,16 +364,48 @@ { if (currentChar == '\\') escaped = YES; - else if (currentChar == separator) + else if (currentChar == ',' || currentChar == ';' || currentChar == 0) { substring - = [[NSString alloc] initWithCharactersNoCopy: substringBuffer - length: substringLength - freeWhenDone: YES]; - [components addObject: substring]; - [substring release]; - substringBuffer = NSZoneMalloc (NULL, sizeof (unichar) * max); + = [[NSString alloc] initWithCharacters: substringBuffer + length: substringLength]; substringLength = 0; + + orderedValues = [values objectForKey: valuesKey]; + if (!orderedValues) + { + orderedValues = [NSMutableArray new]; + [values setObject: orderedValues forKey: valuesKey]; + [orderedValues release]; + } + if (!subValues) + { + subValues = [NSMutableArray new]; + [orderedValues addObject: subValues]; + [subValues release]; + } + if ([substring length] > 0) + [subValues addObject: substring]; + [substring release]; + + if (currentChar != ',') + { + orderedValues = nil; + subValues = nil; + valuesKey = @""; + } + } + /* hack: 16 chars is an arbitrary limit to distinguish between + "named properties" and the base64 padding character. This might + need further tweaking... */ + else if (currentChar == '=' && substringLength < 16) + { + substring + = [[NSString alloc] initWithCharacters: substringBuffer + length: substringLength]; + [substring autorelease]; + substringLength = 0; + valuesKey = [substring lowercaseString]; } else { @@ -372,21 +415,12 @@ } } - if (substringLength > 0) - { - substring = [[NSString alloc] initWithCharactersNoCopy: substringBuffer - length: substringLength - freeWhenDone: YES]; - [components addObject: substring]; - [substring release]; - } - NSZoneFree (NULL, stringBuffer); + NSZoneFree (NULL, substringBuffer); - return components; + return values; } - - (NSString *) rfc822Email { unsigned idx; diff --git a/SOPE/NGCards/iCalAlarm.m b/SOPE/NGCards/iCalAlarm.m index 2eab33947..7922f567a 100644 --- a/SOPE/NGCards/iCalAlarm.m +++ b/SOPE/NGCards/iCalAlarm.m @@ -82,41 +82,41 @@ - (void) setAction: (NSString *) _value { - [[self uniqueChildWithTag: @"action"] setValue: 0 - to: _value]; + [[self uniqueChildWithTag: @"action"] setSingleValue: _value + forKey: @""]; } - (NSString *) action { - return [[self uniqueChildWithTag: @"action"] value: 0]; + return [[self uniqueChildWithTag: @"action"] flattenedValuesForKey: @""]; } - (void) setSummary: (NSString *) _value { - [[self uniqueChildWithTag: @"summary"] setValue: 0 - to: _value]; + [[self uniqueChildWithTag: @"summary"] setSingleValue: _value + forKey: @""]; } - (NSString *) summary { - return [[self uniqueChildWithTag: @"summary"] value: 0]; + return [[self uniqueChildWithTag: @"summary"] flattenedValuesForKey: @""]; } - (void) setComment: (NSString *) _value { - [[self uniqueChildWithTag: @"description"] setValue: 0 - to: _value]; + [[self uniqueChildWithTag: @"description"] setSingleValue: _value + forKey: @""]; } - (NSString *) comment { - return [[self uniqueChildWithTag: @"description"] value: 0]; + return [[self uniqueChildWithTag: @"description"] flattenedValuesForKey: @""]; } -- (void) setRecurrenceRule: (NSString *) _recurrenceRule +- (void) setRecurrenceRule: (NSString *) _value { - [[self uniqueChildWithTag: @"rrule"] setValue: 0 - to: _recurrenceRule]; + [[self uniqueChildWithTag: @"rrule"] setSingleValue: _value + forKey: @""]; } - (void) setAttendees: (NSArray *) attendees @@ -137,7 +137,7 @@ - (NSString *) recurrenceRule { - return [[self uniqueChildWithTag: @"rrule"] value: 0]; + return [[self uniqueChildWithTag: @"rrule"] flattenedValuesForKey: @""]; } - (NSCalendarDate *) nextAlarmDate @@ -161,7 +161,8 @@ == NSOrderedSame) { relation = [aTrigger relationType]; - anInterval = [[aTrigger value] durationAsTimeInterval]; + anInterval = [[aTrigger flattenedValuesForKey: @""] + durationAsTimeInterval]; if ([relation caseInsensitiveCompare: @"END"] == NSOrderedSame) { if ([parent isKindOfClass: [iCalEvent class]]) diff --git a/SOPE/NGCards/iCalAttachment.h b/SOPE/NGCards/iCalAttachment.h index 0b326b7ca..ccba3cdb2 100644 --- a/SOPE/NGCards/iCalAttachment.h +++ b/SOPE/NGCards/iCalAttachment.h @@ -28,9 +28,6 @@ @interface iCalAttachment : CardElement -- (void) setValue: (NSString *) aValue; -- (NSString *) value; - - (void) setValueType: (NSString *) aType; - (NSString *) valueType; diff --git a/SOPE/NGCards/iCalAttachment.m b/SOPE/NGCards/iCalAttachment.m index 6963abd69..c46084986 100644 --- a/SOPE/NGCards/iCalAttachment.m +++ b/SOPE/NGCards/iCalAttachment.m @@ -26,16 +26,6 @@ /* accessors */ -- (void) setValue: (NSString *) _value -{ - [self setValue: 0 to: _value]; -} - -- (NSString *) value -{ - return [self value: 0]; -} - - (void) setValueType: (NSString *) _value { [self setValue: 0 ofAttribute: @"type" to: _value]; diff --git a/SOPE/NGCards/iCalCalendar.m b/SOPE/NGCards/iCalCalendar.m index da567a1d5..75b266641 100644 --- a/SOPE/NGCards/iCalCalendar.m +++ b/SOPE/NGCards/iCalCalendar.m @@ -69,45 +69,44 @@ /* accessors */ -- (void) setCalscale: (NSString *) _calscale +- (void) setCalscale: (NSString *) _value { - [[self uniqueChildWithTag: @"calscale"] setValue: 0 to: _calscale]; + [[self uniqueChildWithTag: @"calscale"] setSingleValue: _value forKey: @""]; } - (NSString *) calscale { - return [[self uniqueChildWithTag: @"calscale"] value: 0]; + return [[self uniqueChildWithTag: @"calscale"] flattenedValuesForKey: @""]; } -- (void) setVersion: (NSString *) _version +- (void) setVersion: (NSString *) _value { - [[self uniqueChildWithTag: @"version"] setValue: 0 to: _version]; + [[self uniqueChildWithTag: @"version"] setSingleValue: _value forKey: @""]; } - (NSString *) version { - return [[self uniqueChildWithTag: @"version"] value: 0]; + return [[self uniqueChildWithTag: @"version"] flattenedValuesForKey: @""]; } - (void) setProdID: (NSString *) _value { - [[self uniqueChildWithTag: @"prodid"] setValue: 0 to: _value]; + [[self uniqueChildWithTag: @"prodid"] setSingleValue: _value forKey: @""]; } - (NSString *) prodId { - return [[self uniqueChildWithTag: @"prodid"] value: 0]; + return [[self uniqueChildWithTag: @"prodid"] flattenedValuesForKey: @""]; } - (void) setMethod: (NSString *) _value { - [[self uniqueChildWithTag: @"method"] setValue: 0 - to: [_value uppercaseString]]; + [[self uniqueChildWithTag: @"method"] setSingleValue: _value forKey: @""]; } - (NSString *) method { - return [[self uniqueChildWithTag: @"method"] value: 0]; + return [[self uniqueChildWithTag: @"method"] flattenedValuesForKey: @""]; } - (void) addToEvents: (iCalEvent *) _event diff --git a/SOPE/NGCards/iCalDateTime.m b/SOPE/NGCards/iCalDateTime.m index f572f9881..251c46d0a 100644 --- a/SOPE/NGCards/iCalDateTime.m +++ b/SOPE/NGCards/iCalDateTime.m @@ -137,7 +137,7 @@ else timeString = @""; - [self setValue: 0 to: timeString]; + [self setSingleValue: timeString forKey: @""]; } - (void) setDateTime: (NSCalendarDate *) dateTime @@ -160,15 +160,17 @@ iCalTimeZone *iTZ; NSString *date; NSCalendarDate *initialDate, *dateTime; + NSArray *subValues; NSMutableArray *dates; //NSTimeZone *tz; unsigned count, i; - count = [[self values] count]; + subValues = [self valuesAtIndex: 0 forKey: @""]; + count = [subValues count]; dates = [NSMutableArray arrayWithCapacity: count]; for (i = 0; i < count; i++) { - date = [self value: i]; + date = [subValues objectAtIndex: i]; iTZ = [self timeZone]; if (iTZ) @@ -204,7 +206,7 @@ - (BOOL) isAllDay { - return [[self value: 0] isAllDayDate]; + return [[self flattenedValuesForKey: @""] isAllDayDate]; } @end diff --git a/SOPE/NGCards/iCalEntityObject.h b/SOPE/NGCards/iCalEntityObject.h index 36491e206..0fd9dc4f2 100644 --- a/SOPE/NGCards/iCalEntityObject.h +++ b/SOPE/NGCards/iCalEntityObject.h @@ -67,8 +67,8 @@ typedef enum - (void) setPriority: (NSString *) _value; - (NSString *) priority; -- (void) setCategories: (NSString *) _value; -- (NSString *)categories; +- (void) setCategories: (NSArray *) _value; +- (NSArray *) categories; - (void) setUserComment: (NSString *) _userComment; - (NSString *) userComment; diff --git a/SOPE/NGCards/iCalEntityObject.m b/SOPE/NGCards/iCalEntityObject.m index 9aba6a262..446eab0ef 100644 --- a/SOPE/NGCards/iCalEntityObject.m +++ b/SOPE/NGCards/iCalEntityObject.m @@ -72,55 +72,55 @@ /* accessors */ -- (void) setUid: (NSString *) _uid +- (void) setUid: (NSString *) _value { - [[self uniqueChildWithTag: @"uid"] setValue: 0 to: _uid]; + [[self uniqueChildWithTag: @"uid"] setSingleValue: _value forKey: @""]; } - (NSString *) uid { - return [[self uniqueChildWithTag: @"uid"] value: 0]; + return [[self uniqueChildWithTag: @"uid"] flattenedValuesForKey: @""]; } - (void) setSummary: (NSString *) _value { - [[self uniqueChildWithTag: @"summary"] setValue: 0 to: _value]; + [[self uniqueChildWithTag: @"summary"] setSingleValue: _value forKey: @""]; } - (NSString *) summary { - return [[self uniqueChildWithTag: @"summary"] value: 0]; + return [[self uniqueChildWithTag: @"summary"] flattenedValuesForKey: @""]; } - (void) setLocation: (NSString *) _value { - [[self uniqueChildWithTag: @"location"] setValue: 0 to: _value]; + [[self uniqueChildWithTag: @"location"] setSingleValue: _value forKey: @""]; } - (NSString *) location { - return [[self uniqueChildWithTag: @"location"] value: 0]; + return [[self uniqueChildWithTag: @"location"] flattenedValuesForKey: @""]; } #warning the "comment" accessors are actually "description" accessors, the "comment" ones are missing - (void) setComment: (NSString *) _value { - [[self uniqueChildWithTag: @"description"] setValue: 0 to: _value]; + [[self uniqueChildWithTag: @"description"] setSingleValue: _value forKey: @""]; } - (NSString *) comment { - return [[self uniqueChildWithTag: @"description"] value: 0]; + return [[self uniqueChildWithTag: @"description"] flattenedValuesForKey: @""]; } - (void) setAccessClass: (NSString *) _value { - [[self uniqueChildWithTag: @"class"] setValue: 0 to: _value]; + [[self uniqueChildWithTag: @"class"] setSingleValue: _value forKey: @""]; } - (NSString *) accessClass { - return [[self uniqueChildWithTag: @"class"] value: 0]; + return [[self uniqueChildWithTag: @"class"] flattenedValuesForKey: @""]; } - (iCalAccessClass) symbolicAccessClass @@ -146,42 +146,47 @@ - (void) setPriority: (NSString *) _value { - [[self uniqueChildWithTag: @"priority"] setValue: 0 to: _value]; + [[self uniqueChildWithTag: @"priority"] setSingleValue: _value forKey: @""]; } - (NSString *) priority { - return [[self uniqueChildWithTag: @"priority"] value: 0]; + return [[self uniqueChildWithTag: @"priority"] flattenedValuesForKey: @""]; } -- (void) setCategories: (NSString *) _value +- (void) setCategories: (NSArray *) _value { - [[self uniqueChildWithTag: @"categories"] setValue: 0 to: _value]; + NSMutableArray *copy; + + copy = [_value mutableCopy]; + [[self uniqueChildWithTag: @"categories"] setValues: copy atIndex: 0 + forKey: @""]; + [copy release]; } -- (NSString *) categories +- (NSArray *) categories { - return [[self uniqueChildWithTag: @"categories"] value: 0]; + return [[self uniqueChildWithTag: @"categories"] valuesAtIndex: 0 forKey: @""]; } - (void) setUserComment: (NSString *) _value { - [[self uniqueChildWithTag: @"usercomment"] setValue: 0 to: _value]; + [[self uniqueChildWithTag: @"usercomment"] setSingleValue: _value forKey: @""]; } - (NSString *) userComment { - return [[self uniqueChildWithTag: @"usercomment"] value: 0]; + return [[self uniqueChildWithTag: @"usercomment"] flattenedValuesForKey: @""]; } - (void) setStatus: (NSString *) _value { - [[self uniqueChildWithTag: @"status"] setValue: 0 to: _value]; + [[self uniqueChildWithTag: @"status"] setSingleValue: _value forKey: @""]; } - (NSString *) status { - return [[self uniqueChildWithTag: @"status"] value: 0]; + return [[self uniqueChildWithTag: @"status"] flattenedValuesForKey: @""]; } - (void) setSequence: (NSNumber *)_value @@ -189,15 +194,15 @@ NSString *sequence; sequence = [NSString stringWithFormat: @"%@", _value]; - [[self uniqueChildWithTag: @"sequence"] setValue: 0 - to: sequence];; + [[self uniqueChildWithTag: @"sequence"] setSingleValue: sequence + forKey: @""]; } - (NSNumber *) sequence { NSString *sequence; - sequence = [[self uniqueChildWithTag: @"sequence"] value: 0]; + sequence = [[self uniqueChildWithTag: @"sequence"] flattenedValuesForKey: @""]; return [NSNumber numberWithInt: [sequence intValue]]; } @@ -391,16 +396,16 @@ - (void) setAttach: (id) _value { - NSString *asString; + NSString *aString; if ([_value isKindOfClass: [NSString class]]) - asString = _value; + aString = _value; else if ([_value isKindOfClass: [NSURL class]]) - asString = [_value absoluteString]; + aString = [_value absoluteString]; else - asString = @""; + aString = @""; - [[self uniqueChildWithTag: @"attach"] setValue: 0 to: asString]; + [[self uniqueChildWithTag: @"attach"] setSingleValue: aString forKey: @""]; } - (NSURL *) attach @@ -408,7 +413,7 @@ NSString *stringAttach; NSURL *url; - stringAttach = [[self uniqueChildWithTag: @"attach"] value: 0]; + stringAttach = [[self uniqueChildWithTag: @"attach"] flattenedValuesForKey: @""]; url = [NSURL URLWithString: stringAttach]; if (!url && [stringAttach length] > 0) @@ -419,23 +424,23 @@ - (void) setUrl: (id) _value { - NSString *asString; + NSString *aString; if ([_value isKindOfClass: [NSString class]]) - asString = _value; + aString = _value; else if ([_value isKindOfClass: [NSURL class]]) - asString = [_value absoluteString]; + aString = [_value absoluteString]; else - asString = @""; + aString = @""; - [[self uniqueChildWithTag: @"url"] setValue: 0 to: asString]; + [[self uniqueChildWithTag: @"url"] setSingleValue: aString forKey: @""]; } - (NSURL *) url { NSString *stringUrl; - stringUrl = [[self uniqueChildWithTag: @"url"] value: 0]; + stringUrl = [[self uniqueChildWithTag: @"url"] flattenedValuesForKey: @""]; return [NSURL URLWithString: stringUrl]; } diff --git a/SOPE/NGCards/iCalEvent.m b/SOPE/NGCards/iCalEvent.m index e8754c869..9d230a2d7 100644 --- a/SOPE/NGCards/iCalEvent.m +++ b/SOPE/NGCards/iCalEvent.m @@ -104,13 +104,12 @@ - (void) setDuration: (NSString *) _value { - [[self uniqueChildWithTag: @"duration"] setValue: 0 - to: _value]; + [[self uniqueChildWithTag: @"duration"] setSingleValue: _value forKey: @""]; } - (NSString *) duration { - return [[self uniqueChildWithTag: @"duration"] value: 0]; + return [[self uniqueChildWithTag: @"duration"] flattenedValuesForKey: @""]; } - (BOOL) hasDuration @@ -148,15 +147,14 @@ return interval; } -- (void) setTransparency: (NSString *) _transparency +- (void) setTransparency: (NSString *) _value { - [[self uniqueChildWithTag: @"transp"] setValue: 0 - to: _transparency]; + [[self uniqueChildWithTag: @"transp"] setSingleValue: _value forKey: @""]; } - (NSString *) transparency { - return [[self uniqueChildWithTag: @"transp"] value: 0]; + return [[self uniqueChildWithTag: @"transp"] flattenedValuesForKey: @""]; } /* convenience */ diff --git a/SOPE/NGCards/iCalPerson.m b/SOPE/NGCards/iCalPerson.m index 9fc728e02..fbcc92570 100644 --- a/SOPE/NGCards/iCalPerson.m +++ b/SOPE/NGCards/iCalPerson.m @@ -57,13 +57,13 @@ { /* iCal.app compatibility: - "mailto" prefix must be in lowercase; */ - [self setValue: 0 - to: [NSString stringWithFormat: @"mailto:%@", _s]]; + [self setSingleValue: [NSString stringWithFormat: @"mailto:%@", _s] + forKey: @""]; } - (NSString *) email { - return [self value: 0]; + return [self flattenedValuesForKey: @""]; } - (NSString *) rfc822Email diff --git a/SOPE/NGCards/iCalRecurrenceRule.m b/SOPE/NGCards/iCalRecurrenceRule.m index 03238e42f..ff66370ab 100644 --- a/SOPE/NGCards/iCalRecurrenceRule.m +++ b/SOPE/NGCards/iCalRecurrenceRule.m @@ -194,6 +194,7 @@ #import "NSCalendarDate+NGCards.h" #import "NSString+NGCards.h" +#import "CardGroup.h" #import "iCalByDayMask.h" #import "iCalRecurrenceRule.h" @@ -234,8 +235,7 @@ NSString *iCalWeekDayString[] = { @"SU", @"MO", @"TU", @"WE", @"TH", @"FR", iCalRecurrenceRule *rule; rule = [self elementWithTag: @"rrule"]; - if ([_iCalRep length] > 0) - [rule addValues: [_iCalRep componentsSeparatedByString: @";"]]; + [rule setRrule: _iCalRep]; return rule; } @@ -269,15 +269,19 @@ NSString *iCalWeekDayString[] = { @"SU", @"MO", @"TU", @"WE", @"TH", @"FR", - (void) setRrule: (NSString *) _rrule { - NSEnumerator *newValues; - NSString *newValue; + CardGroup *mockParent; + NSString *wrappedRule; + CardElement *mockRule; - newValues = [[_rrule componentsSeparatedByString: @";"] objectEnumerator]; - newValue = [newValues nextObject]; - while (newValue) + if ([_rrule length] > 0) { - [self addValue: newValue]; - newValue = [newValues nextObject]; + wrappedRule = [NSString stringWithFormat: + @"BEGIN:MOCK\r\nRRULE:%@\r\nEND:MOCK", + _rrule]; + mockParent = [CardGroup parseSingleFromSource: wrappedRule]; + mockRule = [mockParent uniqueChildWithTag: @"rrule"]; + [values release]; + values = [[mockRule values] mutableCopy]; } } @@ -350,75 +354,73 @@ NSString *iCalWeekDayString[] = { @"SU", @"MO", @"TU", @"WE", @"TH", @"FR", - (void) setFrequency: (iCalRecurrenceFrequency) _frequency { - [self setNamedValue: @"freq" to: [self frequencyForValue: _frequency]]; + [self setSingleValue: [self frequencyForValue: _frequency] forKey: @"freq"]; } - (iCalRecurrenceFrequency) frequency { - return [self valueForFrequency: [self namedValue: @"freq"]]; -} - -- (void) setRepeatCount: (int) _repeatCount -{ - [self setNamedValue: @"count" - to: [NSString stringWithFormat: @"%d", _repeatCount]]; -} - -- (int) repeatCount -{ - return [[self namedValue: @"count"] intValue]; + return [self valueForFrequency: [self flattenedValuesForKey: @"freq"]]; } - (void) setUntilDate: (NSCalendarDate *) _untilDate { - [self setNamedValue: @"until" - to: [_untilDate icalString]]; + [self setSingleValue: [_untilDate icalString] forKey: @"until"]; } - (NSCalendarDate *) untilDate { #warning handling of default timezone needs to be implemented - return [[self namedValue: @"until"] asCalendarDate]; + return [[self flattenedValuesForKey: @"until"] asCalendarDate]; } - (void) setInterval: (NSString *) _interval { - if (_interval && [_interval intValue] == 1) - [self setNamedValue: @"interval" to: nil]; + if ([_interval intValue] < 2) + [self setSingleValue: nil forKey: @"interval"]; else - [self setNamedValue: @"interval" to: _interval]; -} - -- (void) setCount: (NSString *) _count -{ - [self setNamedValue: @"count" to: _count]; -} - -- (void) setUntil: (NSString *) _until -{ - [self setNamedValue: @"until" to: _until]; + [self setSingleValue: _interval forKey: @"interval"]; } - (void) setRepeatInterval: (int) _repeatInterval { - [self setNamedValue: @"interval" - to: [NSString stringWithFormat: @"%d", _repeatInterval]]; + [self setInterval: [NSString stringWithFormat: @"%d", _repeatInterval]]; } - (int) repeatInterval { int interval; - interval = [[self namedValue: @"interval"] intValue]; + interval = [[self flattenedValuesForKey: @"interval"] intValue]; if (interval < 1) interval = 1; return interval; } +- (void) setRepeatCount: (int) _repeatCount +{ + [self setSingleValue: [NSString stringWithFormat: @"%d", _repeatCount] + forKey: @"count"]; +} + +- (int) repeatCount +{ + return [[self flattenedValuesForKey: @"count"] intValue]; +} + +- (void) setCount: (NSString *) _count +{ + [self setSingleValue: _count forKey: @"count"]; +} + +- (void) setUntil: (NSString *) _until +{ + [self setSingleValue: _until forKey: @"until"]; +} + - (void) setWkst: (NSString *) _weekStart { - [self setNamedValue: @"wkst" to: _weekStart]; + [self setSingleValue: _weekStart forKey: @"wkst"]; } #warning we also should handle the user weekstarts @@ -426,7 +428,7 @@ NSString *iCalWeekDayString[] = { @"SU", @"MO", @"TU", @"WE", @"TH", @"FR", { NSString *start; - start = [self namedValue: @"wkst"]; + start = [self flattenedValuesForKey: @"wkst"]; if (![start length]) start = @"MO"; @@ -445,12 +447,16 @@ NSString *iCalWeekDayString[] = { @"SU", @"MO", @"TU", @"WE", @"TH", @"FR", - (void) setByDay: (NSString *) newByDay { - [self setNamedValue: @"byday" to: newByDay]; + NSMutableArray *byDays; + + byDays = [[newByDay componentsSeparatedByString: @","] mutableCopy]; + [self setValues: byDays atIndex: 0 forKey: @"byday"]; + [byDays release]; } - (NSString *) byDay { - return [self namedValue: @"byday"]; + return [self flattenedValuesForKey: @"byday"]; } - (void) setByDayMask: (iCalByDayMask *) newByDayMask @@ -472,12 +478,9 @@ NSString *iCalWeekDayString[] = { @"SU", @"MO", @"TU", @"WE", @"TH", @"FR", - (NSArray *) byMonthDay { NSArray *byMonthDay; - NSString *byMonthDayStr; - byMonthDayStr = [self namedValue: @"bymonthday"]; - if ([byMonthDayStr length]) - byMonthDay = [byMonthDayStr componentsSeparatedByString: @","]; - else + byMonthDay = [self valuesAtIndex: 0 forKey: @"bymonthday"]; + if (![byMonthDay count]) byMonthDay = nil; return byMonthDay; @@ -486,12 +489,9 @@ NSString *iCalWeekDayString[] = { @"SU", @"MO", @"TU", @"WE", @"TH", @"FR", - (NSArray *) byMonth { NSArray *byMonth; - NSString *byMonthStr; - byMonthStr = [self namedValue: @"bymonth"]; - if ([byMonthStr length]) - byMonth = [byMonthStr componentsSeparatedByString: @","]; - else + byMonth = [self valuesAtIndex: 0 forKey: @"bymonth"]; + if (![byMonth count]) byMonth = nil; return byMonth; @@ -507,9 +507,9 @@ NSString *iCalWeekDayString[] = { @"SU", @"MO", @"TU", @"WE", @"TH", @"FR", * - BYSECOND * - BYSETPOS */ - return ([[self namedValue: @"bymonthday"] length] || - [[self namedValue: @"byday"] length] || - [[self namedValue: @"bymonth"] length]); + return ([[self valuesAtIndex: 0 forKey: @"bymonthday"] count] || + [[self valuesAtIndex: 0 forKey: @"byday"] count] || + [[self valuesAtIndex: 0 forKey: @"bymonth"] count]); } - (BOOL) isInfinite diff --git a/SOPE/NGCards/iCalRepeatableEntityObject.m b/SOPE/NGCards/iCalRepeatableEntityObject.m index a6e485a86..b2e9a00e6 100644 --- a/SOPE/NGCards/iCalRepeatableEntityObject.m +++ b/SOPE/NGCards/iCalRepeatableEntityObject.m @@ -247,7 +247,7 @@ while ((dateString = [dateList nextObject])) { - exDates = [(iCalDateTime*) dateString values]; + exDates = [(iCalDateTime*) dateString valuesAtIndex: 0 forKey: @""]; for (i = 0; i < [exDates count]; i++) { dateString = [exDates objectAtIndex: i]; diff --git a/SOPE/NGCards/iCalTimeZone.m b/SOPE/NGCards/iCalTimeZone.m index 510db0759..9e645af09 100644 --- a/SOPE/NGCards/iCalTimeZone.m +++ b/SOPE/NGCards/iCalTimeZone.m @@ -179,12 +179,12 @@ static NSArray *knownTimeZones; - (void) setTzId: (NSString *) tzId { - [[self uniqueChildWithTag: @"tzid"] setValue: 0 to: tzId]; + [[self uniqueChildWithTag: @"tzid"] setSingleValue: tzId forKey: @""]; } - (NSString *) tzId { - return [[self uniqueChildWithTag: @"tzid"] value: 0]; + return [[self uniqueChildWithTag: @"tzid"] flattenedValuesForKey: @""]; } - (NSCalendarDate *) _occurrenceForPeriodNamed: (NSString *) pName diff --git a/SOPE/NGCards/iCalTimeZonePeriod.m b/SOPE/NGCards/iCalTimeZonePeriod.m index 7a774ca99..b161f55ab 100644 --- a/SOPE/NGCards/iCalTimeZonePeriod.m +++ b/SOPE/NGCards/iCalTimeZonePeriod.m @@ -20,6 +20,7 @@ * Boston, MA 02111-1307, USA. */ +#import #import #import #import @@ -63,7 +64,7 @@ seconds = 0; offsetTo = [[self uniqueChildWithTag: offsetName] - value: 0]; + flattenedValuesForKey: @""]; length = [offsetTo length]; negative = [offsetTo hasPrefix: @"-"]; if (negative) @@ -140,7 +141,7 @@ [tzStart setTimeZone: [NSTimeZone timeZoneWithName: @"GMT"]]; tmpDate = [NSCalendarDate dateWithYear: [refDate yearOfCommonEra] - month: [[rrule namedValue: @"bymonth"] intValue] + month: [[[rrule byMonth] objectAtIndex: 0] intValue] day: 1 hour: [tzStart hourOfDay] minute: [tzStart minuteOfHour] second: 0 timeZone: [NSTimeZone timeZoneWithName: @"GMT"]]; diff --git a/SOPE/NGCards/iCalToDo.m b/SOPE/NGCards/iCalToDo.m index 21a01560b..08f5d3f7b 100644 --- a/SOPE/NGCards/iCalToDo.m +++ b/SOPE/NGCards/iCalToDo.m @@ -47,13 +47,14 @@ - (void) setPercentComplete: (NSString *) _value { - [[self uniqueChildWithTag: @"percent-complete"] setValue: 0 - to: _value]; + [[self uniqueChildWithTag: @"percent-complete"] setSingleValue: _value + forKey: @""]; } - (NSString *) percentComplete { - return [[self uniqueChildWithTag: @"percent-complete"] value: 0]; + return [[self uniqueChildWithTag: @"percent-complete"] + flattenedValuesForKey: @""]; } - (void) setDue: (NSCalendarDate *) newDueDate diff --git a/SOPE/NGCards/iCalTrigger.h b/SOPE/NGCards/iCalTrigger.h index a7e12f39a..e1a446fcd 100644 --- a/SOPE/NGCards/iCalTrigger.h +++ b/SOPE/NGCards/iCalTrigger.h @@ -26,9 +26,6 @@ @interface iCalTrigger : CardElement -- (void) setValue: (NSString *) theValue; -- (NSString *) value; - - (void) setValueType: (NSString *) theType; - (NSString *) valueType; diff --git a/SOPE/NGCards/iCalTrigger.m b/SOPE/NGCards/iCalTrigger.m index f9e590e0b..11efcd4e2 100644 --- a/SOPE/NGCards/iCalTrigger.m +++ b/SOPE/NGCards/iCalTrigger.m @@ -27,16 +27,6 @@ /* accessors */ -- (void) setValue: (NSString *) theValue -{ - [self setValue: 0 to: theValue]; -} - -- (NSString *) value -{ - return [self value: 0]; -} - - (void) setValueType: (NSString *) theValue { [self setValue: 0 ofAttribute: @"value" to: theValue]; diff --git a/SOPE/NGCards/iCalXMLRenderer.m b/SOPE/NGCards/iCalXMLRenderer.m index 1911ef76a..b31f57018 100644 --- a/SOPE/NGCards/iCalXMLRenderer.m +++ b/SOPE/NGCards/iCalXMLRenderer.m @@ -21,7 +21,7 @@ */ /* This class implements most of the XML iCalendar spec as defined here: - http://tools.ietf.org/html/draft-daboo-et-al-icalendar-in-xml-04 */ + http://tools.ietf.org/html/rfc6321 */ #import #import @@ -161,28 +161,38 @@ - (NSString *) _xmlRenderValue { NSMutableString *rendering; - NSString *valueTag, *currentValue; - int count, max; - BOOL displayed; + NSArray *keys, *orderedValues, *subValues; + NSString *key, *valueTag; + NSUInteger count, max, oCount, oMax, sCount, sMax; + +#warning this code should be fix to comply better with the RFC + rendering = [NSMutableString stringWithCapacity: 64]; valueTag = [self xmlValueTag]; - rendering = [NSMutableString stringWithCapacity: 64]; - max = [values count]; - displayed = NO; + + keys = [values allKeys]; + max = [keys count]; for (count = 0; count < max; count++) { - currentValue = [[values objectAtIndex: count] - stringByEscapingXMLString]; - if ([currentValue length] > 0) + key = [keys objectAtIndex: count]; + orderedValues = [values objectForKey: key]; + oMax = [orderedValues count]; + for (oCount = 0; oCount < oMax; oCount++) { - if (!displayed) - { - [self _appendPaddingValues: count withTag: valueTag - intoString: rendering]; - displayed = YES; - } - [rendering appendFormat: @"<%@>%@", - valueTag, currentValue, valueTag]; + if ([key length] > 0) + [rendering appendFormat: @"<%@>", [key lowercaseString]]; + else + [rendering appendFormat: @"<%@>", valueTag]; + + subValues = [orderedValues objectAtIndex: oCount]; + sMax = [subValues count]; + for (sCount = 0; sCount < sMax; sCount++) + [rendering appendString: [[subValues objectAtIndex: sCount] stringByEscapingXMLString]]; + + if ([key length] > 0) + [rendering appendFormat: @"", [key lowercaseString]]; + else + [rendering appendFormat: @"", valueTag]; } } @@ -247,39 +257,39 @@ @end -@implementation iCalRecurrenceRule (iCalXMLExtension) +// @implementation iCalRecurrenceRule (iCalXMLExtension) -- (NSString *) _xmlRenderValue -{ - NSMutableString *rendering; - NSArray *valueParts; - NSString *valueTag, *currentValue; - int count, max; +// - (NSString *) _xmlRenderValue +// { +// NSMutableString *rendering; +// NSArray *valueParts; +// NSString *valueTag, *currentValue; +// int count, max; - max = [values count]; - rendering = [NSMutableString stringWithCapacity: 64]; - for (count = 0; count < max; count++) - { - currentValue = [[values objectAtIndex: count] - stringByEscapingXMLString]; - if ([currentValue length] > 0) - { - valueParts = [currentValue componentsSeparatedByString: @"="]; - if ([valueParts count] == 2) - { - valueTag = [[valueParts objectAtIndex: 0] lowercaseString]; - [rendering appendFormat: @"<%@>%@", - valueTag, - [valueParts objectAtIndex: 1], - valueTag]; - } - } - } +// max = [values count]; +// rendering = [NSMutableString stringWithCapacity: 64]; +// for (count = 0; count < max; count++) +// { +// currentValue = [[values objectAtIndex: count] +// stringByEscapingXMLString]; +// if ([currentValue length] > 0) +// { +// valueParts = [currentValue componentsSeparatedByString: @"="]; +// if ([valueParts count] == 2) +// { +// valueTag = [[valueParts objectAtIndex: 0] lowercaseString]; +// [rendering appendFormat: @"<%@>%@", +// valueTag, +// [valueParts objectAtIndex: 1], +// valueTag]; +// } +// } +// } - return rendering; -} +// return rendering; +// } -@end +// @end @implementation iCalUTCOffset (iCalXMLExtension) diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 5561a004e..37d24370a 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -857,8 +857,9 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir NSArray *rules, *exRules, *exDates, *ranges; NSArray *elements, *components; NSString *content; + NSCalendarDate *checkStartDate, *checkEndDate, *firstStartDate, + *firstEndDate; iCalDateTime *dtstart; - NSCalendarDate *checkStartDate, *checkEndDate, *firstStartDate, *firstEndDate; iCalEvent *component; iCalTimeZone *eventTimeZone; unsigned count, max, offset; @@ -898,8 +899,8 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir { // Retrieve the range of the first/master event component = [components objectAtIndex: 0]; - dtstart = (iCalDateTime *)[component uniqueChildWithTag: @"dtstart"]; - firstStartDate = [[[dtstart values] lastObject] asCalendarDate]; + dtstart = (iCalDateTime *) [component uniqueChildWithTag: @"dtstart"]; + firstStartDate = [dtstart dateTime]; firstEndDate = [firstStartDate addTimeInterval: [component occurenceInterval]]; firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: firstStartDate @@ -2655,7 +2656,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir tz = nil; element = [components objectAtIndex: i]; // Use the timezone of the start date. - startDate = (iCalDateTime *)[element uniqueChildWithTag: @"dtstart"]; + startDate = (iCalDateTime *) [element uniqueChildWithTag: @"dtstart"]; if (startDate) { timezone = [startDate timeZone]; diff --git a/SoObjects/Appointments/iCalEvent+SOGo.m b/SoObjects/Appointments/iCalEvent+SOGo.m index 4cb974c1e..a9b4e1a76 100644 --- a/SoObjects/Appointments/iCalEvent+SOGo.m +++ b/SoObjects/Appointments/iCalEvent+SOGo.m @@ -271,21 +271,16 @@ */ - (NGCalendarDateRange *) firstOccurenceRange { - iCalDateTime *firstStartDate; NSCalendarDate *start, *end; NGCalendarDateRange *firstRange; firstRange = nil; - firstStartDate = (iCalDateTime *)[self uniqueChildWithTag: @"dtstart"]; - if ([[firstStartDate values] count] > 0) - { - start = [[[firstStartDate values] lastObject] asCalendarDate]; - end = [start addTimeInterval: [self occurenceInterval]]; + start = [self startDate]; + end = [start addTimeInterval: [self occurenceInterval]]; - firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: start - endDate: end]; - } + firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: start + endDate: end]; return firstRange; } diff --git a/SoObjects/Appointments/iCalRepeatableEntityObject+SOGo.m b/SoObjects/Appointments/iCalRepeatableEntityObject+SOGo.m index 00276a1d6..e57d02faf 100644 --- a/SoObjects/Appointments/iCalRepeatableEntityObject+SOGo.m +++ b/SoObjects/Appointments/iCalRepeatableEntityObject+SOGo.m @@ -27,10 +27,12 @@ #import #import +#import #import #import #import #import +#import #import #import "iCalRepeatableEntityObject+SOGo.h" @@ -40,10 +42,12 @@ - (NSArray *) _indexedRules: (NSArray *) rules { NSMutableArray *ma; - unsigned int i, count; - NSString *valuesString; + NSUInteger i, count; + NSMutableString *ruleString; iCalRecurrenceRule *rule; +#warning we could return an NSArray instead and feed it as such to the iCalRecurrenceRule in SOGoAppointmentFolder... + ma = nil; count = [rules count]; @@ -53,9 +57,11 @@ for (i = 0; i < count; i++) { rule = [rules objectAtIndex:i]; -#warning we could return an NSArray instead and feed it as such to the iCalRecurrenceRule in SOGoAppointmentFolder... - valuesString = [[rule values] componentsJoinedByString: @";"]; - [ma addObject: valuesString]; + ruleString = [NSMutableString new]; + [[rule values] versitRenderInString: ruleString + asAttributes: NO]; + [ma addObject: ruleString]; + [ruleString release]; } } @@ -138,7 +144,7 @@ else { startDate = theOccurenceDate; - if ([self isAllDay]) + if ([self isKindOfClass: [iCalEvent class]] && [(iCalEvent *) self isAllDay]) { // The event lasts all-day and has no timezone (floating); we convert the range of the first event // to the occurence's timezone. diff --git a/SoObjects/Contacts/NGVCard+SOGo.m b/SoObjects/Contacts/NGVCard+SOGo.m index 7f0a72dc5..811ade06d 100644 --- a/SoObjects/Contacts/NGVCard+SOGo.m +++ b/SoObjects/Contacts/NGVCard+SOGo.m @@ -38,6 +38,7 @@ NSArray *array; NSMutableArray *marray; NSMutableDictionary *entry; + CardElement *element; id tmp; entry = [NSMutableDictionary dictionary]; @@ -49,13 +50,14 @@ @"organizationalPerson", @"inetOrgPerson", @"mozillaAbPersonObsolete", nil] forKey: @"objectclass"]; - - tmp = ([[self n] count] > 1 ? [[self n] objectAtIndex: 1] : nil); - if (tmp) + + element = [self n]; + tmp = [element flattenedValueAtIndex: 1 forKey: @""]; + if ([tmp length] > 0) [entry setObject: tmp forKey: @"givenName"]; - tmp = ([[self n] count] ? [[self n] objectAtIndex: 0] : nil); - if (tmp) + tmp = [element flattenedValueAtIndex: 0 forKey: @""]; + if ([tmp length] > 0) [entry setObject: tmp forKey: @"sn"]; tmp = [self fn]; @@ -74,11 +76,12 @@ marray = [NSMutableArray arrayWithArray: [self childrenWithTag: @"email"]]; [marray removeObjectsInArray: [self childrenWithTag: @"email" - andAttribute: @"type" - havingValue: @"pref"]]; + andAttribute: @"type" + havingValue: @"pref"]]; if ([marray count]) { - buffer = [[marray objectAtIndex: [marray count]-1] value: 0]; + buffer = [[marray objectAtIndex: [marray count]-1] + flattenedValuesForKey: @""]; if ([buffer caseInsensitiveCompare: [self preferredEMail]] != NSOrderedSame) [entry setObject: buffer forKey: @"mozillaSecondEmail"]; @@ -86,58 +89,75 @@ array = [self childrenWithTag: @"tel" andAttribute: @"type" havingValue: @"home"]; if ([array count]) - [entry setObject: [[array objectAtIndex: 0] value: 0] forKey: @"homePhone"]; + [entry setObject: [[array objectAtIndex: 0] flattenedValuesForKey: @""] + forKey: @"homePhone"]; array = [self childrenWithTag: @"tel" andAttribute: @"type" havingValue: @"fax"]; if ([array count]) - [entry setObject: [[array objectAtIndex: 0] value: 0] forKey: @"fax"]; + [entry setObject: [[array objectAtIndex: 0] flattenedValuesForKey: @""] + forKey: @"fax"]; array = [self childrenWithTag: @"tel" andAttribute: @"type" havingValue: @"cell"]; if ([array count]) - [entry setObject: [[array objectAtIndex: 0] value: 0] forKey: @"mobile"]; + [entry setObject: [[array objectAtIndex: 0] flattenedValuesForKey: @""] + forKey: @"mobile"]; array = [self childrenWithTag: @"tel" andAttribute: @"type" havingValue: @"pager"]; if ([array count]) - [entry setObject: [[array objectAtIndex: 0] value: 0] forKey: @"pager"]; + [entry setObject: [[array objectAtIndex: 0] flattenedValuesForKey: @""] + forKey: @"pager"]; array = [self childrenWithTag: @"adr" andAttribute: @"type" havingValue: @"home"]; if ([array count]) { tmp = [array objectAtIndex: 0]; - [entry setObject: [tmp value: 1] forKey: @"mozillaHomeStreet2"]; - [entry setObject: [tmp value: 2] forKey: @"homeStreet"]; - [entry setObject: [tmp value: 3] forKey: @"mozillaHomeLocalityName"]; - [entry setObject: [tmp value: 4] forKey: @"mozillaHomeState"]; - [entry setObject: [tmp value: 5] forKey: @"mozillaHomePostalCode"]; - [entry setObject: [tmp value: 6] forKey: @"mozillaHomeCountryName"]; + [entry setObject: [tmp flattenedValueAtIndex: 1 forKey: @""] + forKey: @"mozillaHomeStreet2"]; + [entry setObject: [tmp flattenedValueAtIndex: 2 forKey: @""] + forKey: @"homeStreet"]; + [entry setObject: [tmp flattenedValueAtIndex: 3 forKey: @""] + forKey: @"mozillaHomeLocalityName"]; + [entry setObject: [tmp flattenedValueAtIndex: 4 forKey: @""] + forKey: @"mozillaHomeState"]; + [entry setObject: [tmp flattenedValueAtIndex: 5 forKey: @""] + forKey: @"mozillaHomePostalCode"]; + [entry setObject: [tmp flattenedValueAtIndex: 6 forKey: @""] + forKey: @"mozillaHomeCountryName"]; } - array = [self org]; - if (array && [array count]) - [entry setObject: [array objectAtIndex: 0] forKey: @"o"]; + element = [self org]; + tmp = [element flattenedValueAtIndex: 0 forKey: @""]; + if ([tmp length] > 0) + [entry setObject: tmp forKey: @"o"]; array = [self childrenWithTag: @"adr" andAttribute: @"type" havingValue: @"work"]; if ([array count]) { tmp = [array objectAtIndex: 0]; - [entry setObject: [tmp value: 1] forKey: @"mozillaWorkStreet2"]; - [entry setObject: [tmp value: 2] forKey: @"street"]; - [entry setObject: [tmp value: 3] forKey: @"l"]; - [entry setObject: [tmp value: 4] forKey: @"st"]; - [entry setObject: [tmp value: 5] forKey: @"postalCode"]; - [entry setObject: [tmp value: 6] forKey: @"c"]; + [entry setObject: [tmp flattenedValueAtIndex: 1 forKey: @""] + forKey: @"mozillaWorkStreet2"]; + [entry setObject: [tmp flattenedValueAtIndex: 2 forKey: @""] + forKey: @"street"]; + [entry setObject: [tmp flattenedValueAtIndex: 3 forKey: @""] + forKey: @"l"]; + [entry setObject: [tmp flattenedValueAtIndex: 4 forKey: @""] + forKey: @"st"]; + [entry setObject: [tmp flattenedValueAtIndex: 5 forKey: @""] + forKey: @"postalCode"]; + [entry setObject: [tmp flattenedValueAtIndex: 6 forKey: @""] + forKey: @"c"]; } array = [self childrenWithTag: @"tel" andAttribute: @"type" havingValue: @"work"]; if ([array count]) - [entry setObject: [[array objectAtIndex: 0] value: 0] + [entry setObject: [[array objectAtIndex: 0] flattenedValuesForKey: @""] forKey: @"telephoneNumber"]; array = [self childrenWithTag: @"url" andAttribute: @"type" havingValue: @"work"]; if ([array count]) - [entry setObject: [[array objectAtIndex: 0] value: 0] + [entry setObject: [[array objectAtIndex: 0] flattenedValuesForKey: @""] forKey: @"workurl"]; array = [self childrenWithTag: @"url" andAttribute: @"type" havingValue: @"home"]; if ([array count]) - [entry setObject: [[array objectAtIndex: 0] value: 0] + [entry setObject: [[array objectAtIndex: 0] flattenedValuesForKey: @""] forKey: @"homeurl"]; tmp = [self note]; diff --git a/SoObjects/Contacts/SOGoContactEntryPhoto.m b/SoObjects/Contacts/SOGoContactEntryPhoto.m index 850ce59f5..d90750460 100644 --- a/SoObjects/Contacts/SOGoContactEntryPhoto.m +++ b/SoObjects/Contacts/SOGoContactEntryPhoto.m @@ -77,7 +77,8 @@ if ([photo isInline]) data = [photo decodedContent]; else - data = [[photo value: 0] dataUsingEncoding: NSISOLatin1StringEncoding]; + data = [[photo flattenedValuesForKey: @""] + dataUsingEncoding: NSISOLatin1StringEncoding]; if (data) { response = [localContext response]; diff --git a/SoObjects/Contacts/SOGoContactLDIFEntry.m b/SoObjects/Contacts/SOGoContactLDIFEntry.m index 994a5181b..17d562709 100644 --- a/SoObjects/Contacts/SOGoContactLDIFEntry.m +++ b/SoObjects/Contacts/SOGoContactLDIFEntry.m @@ -178,36 +178,34 @@ if (!country) country = [ldifEntry objectForKey: @"countryname"]; - element = [CardElement elementWithTag: @"adr" - attributes: nil values: nil]; + element = [CardElement elementWithTag: @"adr"]; [element setValue: 0 ofAttribute: @"type" to: @"work"]; if (streetAddress) - [element setValue: 2 to: streetAddress]; + [element setSingleValue: streetAddress atIndex: 2 forKey: @""]; if (location) - [element setValue: 3 to: location]; + [element setSingleValue: location atIndex: 3 forKey: @""]; if (region) - [element setValue: 4 to: region]; + [element setSingleValue: region atIndex: 4 forKey: @""]; if (postalCode) - [element setValue: 5 to: postalCode]; + [element setSingleValue: postalCode atIndex: 5 forKey: @""]; if (country) - [element setValue: 6 to: country]; + [element setSingleValue: country atIndex: 6 forKey: @""]; if (streetAddress || location || region || postalCode || country) [vcard addChild: element]; // We handle the org/orgunit stuff - element = [CardElement elementWithTag: @"org" - attributes: nil values: nil]; + element = [CardElement elementWithTag: @"org"]; org = [ldifEntry objectForKey: @"o"]; orgunit = [ldifEntry objectForKey: @"ou"]; if (!orgunit) orgunit = [ldifEntry objectForKey: @"orgunit"]; if (org) - [element setValue: 0 to: org]; + [element setSingleValue: org atIndex: 0 forKey: @""]; if (orgunit) - [element setValue: 1 to: orgunit]; + [element setSingleValue: orgunit atIndex: 1 forKey: @""]; if (org || orgunit) [vcard addChild: element]; diff --git a/Tests/Unit/TestVersit.m b/Tests/Unit/TestVersit.m index 4c544cc69..41cb7e67a 100644 --- a/Tests/Unit/TestVersit.m +++ b/Tests/Unit/TestVersit.m @@ -43,42 +43,95 @@ /* 1. simple value */ element = [CardElement elementWithTag: @"elem"]; - [element setValue: 0 to: @"value"]; + [element setSingleValue: @"value" forKey: @""]; result = [renderer render: element]; testEquals(result, @"ELEM:value\r\n"); /* 2. two values */ element = [CardElement elementWithTag: @"elem"]; - [element setValue: 0 to: @"value1"]; - [element setValue: 1 to: @"value2"]; + [element setSingleValue: @"value2" atIndex: 1 + forKey: @""]; + [element setSingleValue: @"value1" atIndex: 0 + forKey: @""]; result = [renderer render: element]; testEquals(result, @"ELEM:value1;value2\r\n"); /* 3. one value with commma */ element = [CardElement elementWithTag: @"elem"]; - [element setValue: 0 to: @"value1, with a comma"]; + [element setSingleValue: @"value1, with a comma" forKey: @""]; result = [renderer render: element]; testEquals(result, @"ELEM:value1\\, with a comma\r\n"); /* 4. one value with a semicolon */ element = [CardElement elementWithTag: @"elem"]; - [element setValue: 0 to: @"value1; with a semi-colon"]; + [element setSingleValue: @"value1; with a semi-colon" forKey: @""]; result = [renderer render: element]; testEquals(result, @"ELEM:value1\\; with a semi-colon\r\n"); - /* 4. 3 named values: + /* 5. 3 named values: 1. with multiple subvalues 2. with commas 3. with semicolon */ element = [CardElement elementWithTag: @"elem"]; - [element setNamedValue: @"named1" - to: [NSArray arrayWithObjects: @"1", @"2", @"3", nil]]; - [element setNamedValue: @"named2" - to: @"1,2,3"]; - [element setNamedValue: @"named3" - to: @"text1;text2"]; + [element setValues: [NSArray arrayWithObjects: @"1", @"2", @"3", nil] + atIndex: 0 forKey: @"named1"]; + [element setSingleValue: @"1,2,3" forKey: @"named2"]; + [element setSingleValue: @"text1;text2" forKey: @"named3"]; result = [renderer render: element]; - testEquals(result, @"ELEM:NAMED1=1,2,3;NAMED2=1\\,2\\,3;NAMED3:text1\\;text2\r\n"); + testEquals(result, @"ELEM:NAMED1=1,2,3;NAMED2=1\\,2\\,3;NAMED3=text1\\;text2\r\n"); + + /* 6. values with 1 ordered value with a whitespace starting subvalues */ + element = [CardElement elementWithTag: @"elem"]; + [element setValues: [NSArray arrayWithObjects: @"", @"1", nil] + atIndex: 0 forKey: @""]; + result = [renderer render: element]; + testEquals(result, @"ELEM:1\r\n"); + + /* 7. values with 1 ordered value with a subvalue, a whitespace and another subvalue */ + element = [CardElement elementWithTag: @"elem"]; + [element setValues: [NSArray arrayWithObjects: @"1", @"", @"2", nil] + atIndex: 0 forKey: @""]; + result = [renderer render: element]; + testEquals(result, @"ELEM:1,2\r\n"); + + /* 8.a. values with 1 empty ordered value and another non-empty one */ + element = [CardElement elementWithTag: @"elem"]; + [element setValues: [NSArray arrayWithObjects: nil] + atIndex: 0 forKey: @""]; + [element setValues: [NSArray arrayWithObjects: @"1", nil] + atIndex: 1 forKey: @""]; + result = [renderer render: element]; + testEquals(result, @"ELEM:;1\r\n"); + + /* 8.b. a variant thereof: array with spaces */ + [element setValues: [NSArray arrayWithObjects: @"", @"", nil] + atIndex: 0 forKey: @""]; + result = [renderer render: element]; + testEquals(result, @"ELEM:;1\r\n"); + + /* 8.c. a variant thereof: nil array */ + [element setValues: nil atIndex: 0 forKey: @""]; + result = [renderer render: element]; + testEquals(result, @"ELEM:;1\r\n"); + + /* 9. values with 1 non-empty ordered value and another empty one */ + element = [CardElement elementWithTag: @"elem"]; + [element setValues: [NSArray arrayWithObjects: @"1", nil] + atIndex: 0 forKey: @""]; + [element setValues: [NSArray arrayWithObjects: nil] + atIndex: 1 forKey: @""]; + result = [renderer render: element]; + testEquals(result, @"ELEM:1\r\n"); + + /* 10. named values with 1 nil value, 1 empty value and another non-nil one */ + element = [CardElement elementWithTag: @"elem"]; + [element setSingleValue: nil forKey: @"empty"]; + [element setSingleValue: nil forKey: @"empty2"]; + [element setSingleValue: @"coucou" forKey: @"nonempty"]; + result = [renderer render: element]; + testEquals(result, @"ELEM:NONEMPTY=coucou\r\n"); + + /** tests about parameters handling could be nice */ } - (void) test_parsing @@ -87,52 +140,62 @@ CardElement *element; NSString *versit; - versit = @"BEGIN:group1\r\nELEMENT:value\r\nEND:group1\r\n"; + versit = @"BEGIN:GROUP1\r\nELEMENT:value\r\nEND:GROUP1"; group = [CardGroup parseSingleFromSource: versit]; + testEquals([group versitString], versit); element = [group firstChildWithTag: @"element"]; - testEquals([element value: 0], @"value"); + testEquals([element flattenedValueAtIndex: 0 forKey: @""], @"value"); - versit = @"BEGIN:group1\r\nELEMENT:value1;value2\r\nEND:group1\r\n"; + versit = @"BEGIN:GROUP1\r\nELEMENT:value1;value2\r\nEND:GROUP1"; group = [CardGroup parseSingleFromSource: versit]; + testEquals([group versitString], versit); element = [group firstChildWithTag: @"element"]; - testEquals([element value: 0], @"value1"); - testEquals([element value: 1], @"value2"); + testEquals([element flattenedValueAtIndex: 0 forKey: @""], @"value1"); + testEquals([element flattenedValueAtIndex: 1 forKey: @""], @"value2"); - versit = @"BEGIN:group1\r\nELEMENT:value\\, with comma\r\nEND:group1\r\n"; + versit = @"BEGIN:GROUP1\r\nELEMENT:value\\, with comma\r\nEND:GROUP1"; group = [CardGroup parseSingleFromSource: versit]; + testEquals([group versitString], versit); element = [group firstChildWithTag: @"element"]; - testEquals([element value: 0], @"value, with comma"); + testEquals([element flattenedValueAtIndex: 0 forKey: @""], @"value, with comma"); - versit = @"BEGIN:group1\r\nELEMENT:value,with comma\r\nEND:group1\r\n"; + versit = @"BEGIN:GROUP1\r\nELEMENT:value,with comma\r\nEND:GROUP1"; group = [CardGroup parseSingleFromSource: versit]; + testEquals([group versitString], versit); element = [group firstChildWithTag: @"element"]; - testEquals([element value: 0], ([NSArray arrayWithObjects: @"value", @"with comma", nil])); + testEquals([element valuesAtIndex: 0 forKey: @""], ([NSArray arrayWithObjects: @"value", @"with comma", nil])); - versit = @"BEGIN:group1\r\nELEMENT:NAMED1=subvalue;NAMED2=subvalue1,subvalue2\r\nEND:group1\r\n"; + versit = @"BEGIN:GROUP1\r\nELEMENT:NAMED1=subvalue;NAMED2=subvalue1,subvalue2\r\nEND:GROUP1"; group = [CardGroup parseSingleFromSource: versit]; + /* we avoid this test here as nothing guarantees that the order of named + values will be preserved... */ + // testEquals([group versitString], versit); element = [group firstChildWithTag: @"element"]; - testEquals([element namedValue: @"named1"], @"subvalue"); - testEquals([element namedValue: @"named2"], + testEquals([element flattenedValueAtIndex: 0 forKey: @"NAMED1"], @"subvalue"); + testEquals([element valuesAtIndex: 0 forKey: @"named2"], ([NSArray arrayWithObjects: @"subvalue1", @"subvalue2", nil])); - versit = @"BEGIN:group1\r\nELEMENT;PARAM1=test:value\r\nEND:group1\r\n"; + versit = @"BEGIN:GROUP1\r\nELEMENT;PARAM1=test:value\r\nEND:GROUP1"; group = [CardGroup parseSingleFromSource: versit]; + testEquals([group versitString], versit); element = [group firstChildWithTag: @"element"]; - testEquals([element value: 0], @"value"); + testEquals([element flattenedValueAtIndex: 0 forKey: @""], @"value"); testEquals([element value: 0 ofAttribute: @"param1"], @"test"); - versit = @"BEGIN:group1\r\nELEMENT;PARAM1=paramvalue1,paramvalue2:value\r\nEND:group1\r\n"; + versit = @"BEGIN:GROUP1\r\nELEMENT;PARAM1=paramvalue1,paramvalue2:value\r\nEND:GROUP1"; group = [CardGroup parseSingleFromSource: versit]; + testEquals([group versitString], versit); element = [group firstChildWithTag: @"element"]; - testEquals([element value: 0], @"value"); + testEquals([element flattenedValueAtIndex: 0 forKey: @""], @"value"); testEquals([element value: 0 ofAttribute: @"param1"], @"paramvalue1"); testEquals([element value: 1 ofAttribute: @"param1"], @"paramvalue2"); - versit = @"BEGIN:group1\r\nELEMENT;PARAM1=\"paramvalue1, with comma\":value\r\nEND:group1\r\n"; + versit = @"BEGIN:GROUP1\r\nELEMENT;PARAM1=paramvalue1\\, with comma:value\r\nEND:GROUP1"; group = [CardGroup parseSingleFromSource: versit]; + testEquals([group versitString], versit); element = [group firstChildWithTag: @"element"]; - testEquals([element value: 0], @"value"); - testEquals([element value: 0 ofAttribute: @"param1"], @"value1, with comma"); + testEquals([element flattenedValueAtIndex: 0 forKey: @""], @"value"); + testEquals([element value: 0 ofAttribute: @"param1"], @"paramvalue1, with comma"); } @end diff --git a/Tools/SOGoToolRemoveDoubles.m b/Tools/SOGoToolRemoveDoubles.m index 4f90de62c..a4be92c3f 100644 --- a/Tools/SOGoToolRemoveDoubles.m +++ b/Tools/SOGoToolRemoveDoubles.m @@ -64,7 +64,7 @@ cardReferences = [[self cardReferences] objectEnumerator]; while ((currentReference = [cardReferences nextObject])) - [cardNames addObject: [currentReference value: 0]]; + [cardNames addObject: [currentReference flattenedValuesForKey: @""]]; return cardNames; } diff --git a/UI/Contacts/UIxContactEditor.m b/UI/Contacts/UIxContactEditor.m index c97d58390..dfbc48644 100644 --- a/UI/Contacts/UIxContactEditor.m +++ b/UI/Contacts/UIxContactEditor.m @@ -366,7 +366,7 @@ for (i = 0; i < [elements count]; i++) { ce = [elements objectAtIndex: i]; - value = [ce value: 0]; + value = [ce flattenedValuesForKey: @""]; if (!aTypeToExclude) break; @@ -398,13 +398,13 @@ if (max > 0) { - potential = [[elements objectAtIndex: 0] value: 0]; + potential = [[elements objectAtIndex: 0] flattenedValuesForKey: @""]; if (!workMail) { if (homeMail && homeMail == potential) { if (max > 1) - workMail = [[elements objectAtIndex: 1] value: 0]; + workMail = [[elements objectAtIndex: 1] flattenedValuesForKey: @""]; } else workMail = potential; @@ -412,7 +412,7 @@ if (!homeMail && max > 1) { if (workMail && workMail == potential) - homeMail = [[elements objectAtIndex: 1] value: 0]; + homeMail = [[elements objectAtIndex: 1] flattenedValuesForKey: @""]; else homeMail = potential; } @@ -430,32 +430,32 @@ [self _setSnapshotValue: @"homeMail" to: homeMail]; [self _setSnapshotValue: @"mozillaUseHtmlMail" - to: [[card uniqueChildWithTag: @"x-mozilla-html"] value: 0]]; + to: [[card uniqueChildWithTag: @"x-mozilla-html"] flattenedValuesForKey: @""]]; } - (void) _setupOrgFields { NSMutableArray *orgServices; - NSArray *org; - NSRange aRange; - unsigned int max; + CardElement *org; + NSString *service; + NSUInteger count, max; org = [card org]; - max = [org count]; - if (max > 0) + [self _setSnapshotValue: @"workCompany" + to: [org flattenedValueAtIndex: 0 forKey: @""]]; + max = [[org valuesForKey: @""] count]; + if (max > 1) { - [self _setSnapshotValue: @"workCompany" to: [org objectAtIndex: 0]]; - if (max > 1) + orgServices = [NSMutableArray arrayWithCapacity: max]; + for (count = 1; count < max; count++) { - aRange = NSMakeRange (1, max - 1); - orgServices = [NSMutableArray arrayWithArray: [org subarrayWithRange: aRange]]; - - while ([orgServices containsObject: @""]) - [orgServices removeObject: @""]; - - [self _setSnapshotValue: @"workService" - to: [orgServices componentsJoinedByString: @", "]]; + service = [org flattenedValueAtIndex: count forKey: @""]; + if ([service length] > 0) + [orgServices addObject: service]; } + + [self _setSnapshotValue: @"workService" + to: [orgServices componentsJoinedByString: @", "]]; } } @@ -481,21 +481,14 @@ - (void) initSnapshot { - NSArray *n, *elements; + NSArray *elements; CardElement *element; - unsigned int max; - n = [card n]; - if (n) - { - max = [n count]; - if (max > 0) - { - [self _setSnapshotValue: @"sn" to: [n objectAtIndex: 0]]; - if (max > 1) - [self _setSnapshotValue: @"givenName" to: [n objectAtIndex: 1]]; - } - } + element = [card n]; + [self _setSnapshotValue: @"sn" + to: [element flattenedValueAtIndex: 0 forKey: @""]]; + [self _setSnapshotValue: @"givenName" + to: [element flattenedValueAtIndex: 1 forKey: @""]]; [self _setSnapshotValue: @"fn" to: [card fn]]; [self _setSnapshotValue: @"nickname" to: [card nickname]]; @@ -538,7 +531,7 @@ [self _setupEmailFields]; [self _setSnapshotValue: @"screenName" - to: [[card uniqueChildWithTag: @"x-aim"] value: 0]]; + to: [[card uniqueChildWithTag: @"x-aim"] flattenedValuesForKey: @""]]; elements = [card childrenWithTag: @"adr" andAttribute: @"type" havingValue: @"work"]; @@ -546,17 +539,17 @@ { element = [elements objectAtIndex: 0]; [self _setSnapshotValue: @"workExtendedAddress" - to: [element value: 1]]; + to: [element flattenedValueAtIndex: 1 forKey: @""]]; [self _setSnapshotValue: @"workStreetAddress" - to: [element value: 2]]; + to: [element flattenedValueAtIndex: 2 forKey: @""]]; [self _setSnapshotValue: @"workCity" - to: [element value: 3]]; + to: [element flattenedValueAtIndex: 3 forKey: @""]]; [self _setSnapshotValue: @"workState" - to: [element value: 4]]; + to: [element flattenedValueAtIndex: 4 forKey: @""]]; [self _setSnapshotValue: @"workPostalCode" - to: [element value: 5]]; + to: [element flattenedValueAtIndex: 5 forKey: @""]]; [self _setSnapshotValue: @"workCountry" - to: [element value: 6]]; + to: [element flattenedValueAtIndex: 6 forKey: @""]]; } elements = [card childrenWithTag: @"adr" @@ -565,17 +558,17 @@ { element = [elements objectAtIndex: 0]; [self _setSnapshotValue: @"homeExtendedAddress" - to: [element value: 1]]; + to: [element flattenedValueAtIndex: 1 forKey: @""]]; [self _setSnapshotValue: @"homeStreetAddress" - to: [element value: 2]]; + to: [element flattenedValueAtIndex: 2 forKey: @""]]; [self _setSnapshotValue: @"homeCity" - to: [element value: 3]]; + to: [element flattenedValueAtIndex: 3 forKey: @""]]; [self _setSnapshotValue: @"homeState" - to: [element value: 4]]; + to: [element flattenedValueAtIndex: 4 forKey: @""]]; [self _setSnapshotValue: @"homePostalCode" - to: [element value: 5]]; + to: [element flattenedValueAtIndex: 5 forKey: @""]]; [self _setSnapshotValue: @"homeCountry" - to: [element value: 6]]; + to: [element flattenedValueAtIndex: 6 forKey: @""]]; } elements = [card childrenWithTag: @"url"]; @@ -591,7 +584,7 @@ [elements count] > 0) { [self _setSnapshotValue: @"homeURL" - to: [[elements objectAtIndex: 0] value: 0]]; + to: [[elements objectAtIndex: 0] flattenedValuesForKey: @""]]; } // If we do have a "work" URL but no "home" URL but two // values URLs present, let's add the second one as the home URL @@ -603,11 +596,11 @@ for (i = 0; i < [elements count]; i++) { - if ([[[elements objectAtIndex: i] value: 0] + if ([[[elements objectAtIndex: i] flattenedValuesForKey: @""] caseInsensitiveCompare: [snapshot objectForKey: @"workURL"]] != NSOrderedSame) { [self _setSnapshotValue: @"homeURL" - to: [[elements objectAtIndex: i] value: 0]]; + to: [[elements objectAtIndex: i] flattenedValuesForKey: @""]]; break; } } @@ -615,7 +608,7 @@ [self _setSnapshotValue: @"calFBURL" - to: [[card uniqueChildWithTag: @"FBURL"] value: 0]]; + to: [[card uniqueChildWithTag: @"FBURL"] flattenedValuesForKey: @""]]; [self _setSnapshotValue: @"title" to: [card title]]; [self _setupOrgFields]; @@ -686,7 +679,7 @@ photoURL = [NSString stringWithFormat: @"%@/photo%d", baseInlineURL, count]; else - photoURL = [photo value: 0]; + photoURL = [photo flattenedValuesForKey: @""]; [photosURL addObject: photoURL]; } } @@ -721,17 +714,16 @@ CardElement *phone; phone = [self _elementWithTag: @"tel" ofType: @"work"]; - [phone setValue: 0 to: [snapshot objectForKey: @"telephoneNumber"]]; + [phone setSingleValue: [snapshot objectForKey: @"telephoneNumber"] forKey: @""]; phone = [self _elementWithTag: @"tel" ofType: @"home"]; - [phone setValue: 0 to: [snapshot objectForKey: @"homeTelephoneNumber"]]; + [phone setSingleValue: [snapshot objectForKey: @"homeTelephoneNumber"] forKey: @""]; phone = [self _elementWithTag: @"tel" ofType: @"cell"]; - [phone setValue: 0 to: [snapshot objectForKey: @"mobile"]]; + [phone setSingleValue: [snapshot objectForKey: @"mobile"] forKey: @""]; phone = [self _elementWithTag: @"tel" ofType: @"fax"]; - [phone setValue: 0 - to: [snapshot objectForKey: @"facsimileTelephoneNumber"]]; + [phone setSingleValue: [snapshot objectForKey: @"facsimileTelephoneNumber"] + forKey: @""]; phone = [self _elementWithTag: @"tel" ofType: @"pager"]; - [phone setValue: 0 - to: [snapshot objectForKey: @"pager"]]; + [phone setSingleValue: [snapshot objectForKey: @"pager"] forKey: @""]; } - (void) _saveEmails @@ -739,9 +731,9 @@ CardElement *workMail, *homeMail; workMail = [self _elementWithTag: @"email" ofType: @"work"]; - [workMail setValue: 0 to: [snapshot objectForKey: @"workMail"]]; + [workMail setSingleValue: [snapshot objectForKey: @"workMail"] forKey: @""]; homeMail = [self _elementWithTag: @"email" ofType: @"home"]; - [homeMail setValue: 0 to: [snapshot objectForKey: @"homeMail"]]; + [homeMail setSingleValue: [snapshot objectForKey: @"homeMail"] forKey: @""]; if (preferredEmail) { if ([preferredEmail isEqualToString: @"work"]) @@ -751,8 +743,8 @@ } [[card uniqueChildWithTag: @"x-mozilla-html"] - setValue: 0 - to: [snapshot objectForKey: @"mozillaUseHtmlMail"]]; + setSingleValue: [snapshot objectForKey: @"mozillaUseHtmlMail"] + forKey: @""]; } - (void) _saveSnapshot @@ -773,20 +765,32 @@ [card setTz: [snapshot objectForKey: @"tz"]]; element = [self _elementWithTag: @"adr" ofType: @"home"]; - [element setValue: 1 to: [snapshot objectForKey: @"homeExtendedAddress"]]; - [element setValue: 2 to: [snapshot objectForKey: @"homeStreetAddress"]]; - [element setValue: 3 to: [snapshot objectForKey: @"homeCity"]]; - [element setValue: 4 to: [snapshot objectForKey: @"homeState"]]; - [element setValue: 5 to: [snapshot objectForKey: @"homePostalCode"]]; - [element setValue: 6 to: [snapshot objectForKey: @"homeCountry"]]; + [element setSingleValue: [snapshot objectForKey: @"homeExtendedAddress"] + atIndex: 1 forKey: @""]; + [element setSingleValue: [snapshot objectForKey: @"homeStreetAddress"] + atIndex: 2 forKey: @""]; + [element setSingleValue: [snapshot objectForKey: @"homeCity"] + atIndex: 3 forKey: @""]; + [element setSingleValue: [snapshot objectForKey: @"homeState"] + atIndex: 4 forKey: @""]; + [element setSingleValue: [snapshot objectForKey: @"homePostalCode"] + atIndex: 5 forKey: @""]; + [element setSingleValue: [snapshot objectForKey: @"homeCountry"] + atIndex: 6 forKey: @""]; element = [self _elementWithTag: @"adr" ofType: @"work"]; - [element setValue: 1 to: [snapshot objectForKey: @"workExtendedAddress"]]; - [element setValue: 2 to: [snapshot objectForKey: @"workStreetAddress"]]; - [element setValue: 3 to: [snapshot objectForKey: @"workCity"]]; - [element setValue: 4 to: [snapshot objectForKey: @"workState"]]; - [element setValue: 5 to: [snapshot objectForKey: @"workPostalCode"]]; - [element setValue: 6 to: [snapshot objectForKey: @"workCountry"]]; + [element setSingleValue: [snapshot objectForKey: @"workExtendedAddress"] + atIndex: 1 forKey: @""]; + [element setSingleValue: [snapshot objectForKey: @"workStreetAddress"] + atIndex: 2 forKey: @""]; + [element setSingleValue: [snapshot objectForKey: @"workCity"] + atIndex: 3 forKey: @""]; + [element setSingleValue: [snapshot objectForKey: @"workState"] + atIndex: 4 forKey: @""]; + [element setSingleValue: [snapshot objectForKey: @"workPostalCode"] + atIndex: 5 forKey: @""]; + [element setSingleValue: [snapshot objectForKey: @"workCountry"] + atIndex: 6 forKey: @""]; element = [CardElement simpleElementWithTag: @"fburl" value: [snapshot objectForKey: @"calFBURL"]]; @@ -799,13 +803,13 @@ [self _savePhoneValues]; [self _saveEmails]; [[self _elementWithTag: @"url" ofType: @"home"] - setValue: 0 to: [snapshot objectForKey: @"homeURL"]]; + setSingleValue: [snapshot objectForKey: @"homeURL"] forKey: @""]; [[self _elementWithTag: @"url" ofType: @"work"] - setValue: 0 to: [snapshot objectForKey: @"workURL"]]; + setSingleValue: [snapshot objectForKey: @"workURL"] forKey: @""]; [[card uniqueChildWithTag: @"x-aim"] - setValue: 0 - to: [snapshot objectForKey: @"screenName"]]; + setSingleValue: [snapshot objectForKey: @"screenName"] + forKey: @""]; } - (id ) saveAction @@ -814,7 +818,6 @@ id result; NSString *jsRefreshMethod; SoSecurityManager *sm; - NSException *ex; contact = [self clientObject]; card = [contact vCard]; @@ -836,7 +839,7 @@ if (![sm validatePermission: SoPerm_AddDocumentsImagesAndFiles onObject: componentAddressBook inContext: context]) - ex = [contact moveToFolder: (SOGoGCSFolder *)componentAddressBook]; // TODO: handle exception + [contact moveToFolder: (SOGoGCSFolder *)componentAddressBook]; // TODO: handle exception } } diff --git a/UI/Contacts/UIxContactView.m b/UI/Contacts/UIxContactView.m index 7728b54e7..3c4583c61 100644 --- a/UI/Contacts/UIxContactView.m +++ b/UI/Contacts/UIxContactView.m @@ -58,14 +58,6 @@ /* accessors */ -- (NSString *) _cardStringWithLabel: (NSString *) label - value: (NSString *) value -{ - return [self _cardStringWithLabel: label - value: value - url: nil]; -} - - (NSString *) _cardStringWithLabel: (NSString *) label value: (NSString *) value url: (NSString *) url @@ -89,6 +81,14 @@ return cardString; } +- (NSString *) _cardStringWithLabel: (NSString *) label + value: (NSString *) value +{ + return [self _cardStringWithLabel: label + value: value + url: nil]; +} + - (NSString *) displayName { return [self _cardStringWithLabel: @"Display Name:" @@ -103,25 +103,24 @@ - (NSString *) fullName { - NSArray *n; - NSString *fn; - unsigned int max; + CardElement *n; + NSString *fn, *firstName, *lastName; fn = [card fn]; if ([fn length] == 0) { n = [card n]; - if (n) - { - max = [n count]; - if (max > 0) - { - if (max > 1) - fn = [NSString stringWithFormat: @"%@ %@", [n objectAtIndex: 1], [n objectAtIndex: 0]]; - else - fn = [n objectAtIndex: 0]; - } - } + lastName = [n flattenedValueAtIndex: 0 forKey: @""]; + firstName = [n flattenedValueAtIndex: 1 forKey: @""]; + if ([firstName length] > 0) + { + if ([lastName length] > 0) + fn = [NSString stringWithFormat: @"%@ %@", firstName, lastName]; + else + fn = firstName; + } + else + fn = lastName; } return fn; @@ -172,7 +171,7 @@ for (i = 0; i < [emails count]; i++) { - email = [[emails objectAtIndex: i] value: 0]; + email = [[emails objectAtIndex: i] flattenedValuesForKey: @""]; if ([email caseInsensitiveCompare: [card preferredEMail]] != NSOrderedSame) { @@ -192,7 +191,7 @@ { NSString *screenName, *goim; - screenName = [[card uniqueChildWithTag: @"x-aim"] value: 0]; + screenName = [[card uniqueChildWithTag: @"x-aim"] flattenedValuesForKey: @""]; if ([screenName length] > 0) goim = [NSString stringWithFormat: @"%@", screenName, screenName]; @@ -250,7 +249,7 @@ for (i = 0; i < [elements count]; i++) { ce = [elements objectAtIndex: i]; - phone = [ce value: 0]; + phone = [ce flattenedValuesForKey: @""]; if (!aTypeToExclude) break; @@ -315,17 +314,23 @@ - (NSString *) homePobox { - return [self _cardStringWithLabel: nil value: [homeAdr value: 0]]; + return [self _cardStringWithLabel: nil + value: [homeAdr flattenedValueAtIndex: 0 + forKey: @""]]; } - (NSString *) homeExtendedAddress { - return [self _cardStringWithLabel: nil value: [homeAdr value: 1]]; + return [self _cardStringWithLabel: nil + value: [homeAdr flattenedValueAtIndex: 1 + forKey: @""]]; } - (NSString *) homeStreetAddress { - return [self _cardStringWithLabel: nil value: [homeAdr value: 2]]; + return [self _cardStringWithLabel: nil + value: [homeAdr flattenedValueAtIndex: 2 + forKey: @""]]; } - (NSString *) homeCityAndProv @@ -333,8 +338,8 @@ NSString *city, *prov; NSMutableString *data; - city = [homeAdr value: 3]; - prov = [homeAdr value: 4]; + city = [homeAdr flattenedValueAtIndex: 3 forKey: @""]; + prov = [homeAdr flattenedValueAtIndex: 4 forKey: @""]; data = [NSMutableString string]; [data appendString: city]; @@ -350,8 +355,8 @@ NSString *postalCode, *country; NSMutableString *data; - postalCode = [homeAdr value: 5]; - country = [homeAdr value: 6]; + postalCode = [homeAdr flattenedValueAtIndex: 5 forKey: @""]; + country = [homeAdr flattenedValueAtIndex: 6 forKey: @""]; data = [NSMutableString string]; [data appendString: postalCode]; @@ -391,7 +396,7 @@ andAttribute: @"type" havingValue: aType]; if ([elements count] > 0) - url = [[elements objectAtIndex: 0] value: 0]; + url = [[elements objectAtIndex: 0] flattenedValuesForKey: @""]; else url = nil; @@ -416,7 +421,7 @@ workURL = nil; if ([elements count] > 0) - workURL = [[elements objectAtIndex: 0] value: 0]; + workURL = [[elements objectAtIndex: 0] flattenedValuesForKey: @""]; elements = [card childrenWithTag: @"url"]; @@ -424,9 +429,10 @@ { for (i = 0; i < [elements count]; i++) { - if ([[[elements objectAtIndex: i] value: 0] caseInsensitiveCompare: workURL] != NSOrderedSame) + if ([[[elements objectAtIndex: i] flattenedValuesForKey: @""] + caseInsensitiveCompare: workURL] != NSOrderedSame) { - s = [[elements objectAtIndex: i] value: 0]; + s = [[elements objectAtIndex: i] flattenedValuesForKey: @""]; break; } } @@ -434,7 +440,7 @@ } else if (!workURL && [elements count] > 0) { - s = [[elements objectAtIndex: 0] value: 0]; + s = [[elements objectAtIndex: 0] flattenedValuesForKey: @""]; } if (s && [s length] > 0) @@ -474,18 +480,23 @@ - (NSString *) workService { NSMutableArray *orgServices; - NSArray *org; - NSRange aRange; - NSString *services; + NSArray *values; + CardElement *org; + NSString *service, *services; + NSUInteger count, max; org = [card org]; - if (org && [org count] > 1) + values = [org valuesForKey: @""]; + max = [values count]; + if (max > 1) { - aRange = NSMakeRange(1, [org count]-1); - orgServices = [NSMutableArray arrayWithArray: [org subarrayWithRange: aRange]]; - - while ([orgServices containsObject: @""]) - [orgServices removeObject: @""]; + orgServices = [NSMutableArray arrayWithCapacity: max]; + for (count = 1; count < max; count++) + { + service = [org flattenedValueAtIndex: count forKey: @""]; + if ([service length] > 0) + [orgServices addObject: service]; + } services = [orgServices componentsJoinedByString: @", "]; } @@ -497,13 +508,12 @@ - (NSString *) workCompany { - NSArray *org; + CardElement *org; NSString *company; org = [card org]; - if (org && [org count] > 0) - company = [org objectAtIndex: 0]; - else + company = [org flattenedValueAtIndex: 0 forKey: @""]; + if ([company length] == 0) company = nil; return [self _cardStringWithLabel: nil value: company]; @@ -511,17 +521,23 @@ - (NSString *) workPobox { - return [self _cardStringWithLabel: nil value: [workAdr value: 0]]; + return [self _cardStringWithLabel: nil + value: [workAdr flattenedValueAtIndex: 0 + forKey: @""]]; } - (NSString *) workExtendedAddress { - return [self _cardStringWithLabel: nil value: [workAdr value: 1]]; + return [self _cardStringWithLabel: nil + value: [workAdr flattenedValueAtIndex: 1 + forKey: @""]]; } - (NSString *) workStreetAddress { - return [self _cardStringWithLabel: nil value: [workAdr value: 2]]; + return [self _cardStringWithLabel: nil + value: [workAdr flattenedValueAtIndex: 2 + forKey: @""]]; } - (NSString *) workCityAndProv @@ -529,8 +545,8 @@ NSString *city, *prov; NSMutableString *data; - city = [workAdr value: 3]; - prov = [workAdr value: 4]; + city = [workAdr flattenedValueAtIndex: 3 forKey: @""]; + prov = [workAdr flattenedValueAtIndex: 4 forKey: @""]; data = [NSMutableString string]; [data appendString: city]; @@ -546,8 +562,8 @@ NSString *postalCode, *country; NSMutableString *data; - postalCode = [workAdr value: 5]; - country = [workAdr value: 6]; + postalCode = [workAdr flattenedValueAtIndex: 5 forKey: @""]; + country = [workAdr flattenedValueAtIndex: 6 forKey: @""]; data = [NSMutableString string]; [data appendString: postalCode]; @@ -681,7 +697,7 @@ photoURL = [NSString stringWithFormat: @"%@/photo%d", baseInlineURL, count]; else - photoURL = [photo value: 0]; + photoURL = [photo flattenedValuesForKey: @""]; [photosURL addObject: photoURL]; } } diff --git a/UI/Contacts/UIxListEditor.m b/UI/Contacts/UIxListEditor.m index 0ab577aa7..adb04de20 100644 --- a/UI/Contacts/UIxListEditor.m +++ b/UI/Contacts/UIxListEditor.m @@ -184,7 +184,7 @@ [newWorkMail setTag: @"email"]; [newWorkMail addType: @"work"]; [newCard addChild: newWorkMail]; - [newWorkMail setValue: 0 to: workMail]; + [newWorkMail setSingleValue: workMail forKey: @""]; [newCard setFn: fn]; // Add vCard to current folder diff --git a/UI/MailerUI/UIxMailMainFrame.m b/UI/MailerUI/UIxMailMainFrame.m index a03336e58..8183089e9 100644 --- a/UI/MailerUI/UIxMailMainFrame.m +++ b/UI/MailerUI/UIxMailMainFrame.m @@ -268,10 +268,9 @@ - (NSString *) formattedMailtoString: (NGVCard *) card { - NSString *email; + NSString *firstName, *lastName, *email; NSMutableString *fn, *rc = nil; - NSArray *n; - unsigned int max; + CardElement *n; if ([card isKindOfClass: [NGVCard class]]) email = [card preferredEMail]; @@ -291,17 +290,17 @@ && [card isKindOfClass: [NGVCard class]]) { n = [card n]; - if (n) + lastName = [n flattenedValueAtIndex: 0 forKey: @""]; + firstName = [n flattenedValueAtIndex: 1 forKey: @""]; + if ([firstName length] > 0) { - max = [n count]; - if (max > 0) - { - if (max > 1) - fn = [NSMutableString stringWithFormat: @"%@ %@", [n objectAtIndex: 1], [n objectAtIndex: 0]]; - else - fn = [NSMutableString stringWithString: [n objectAtIndex: 0]]; - } + if ([lastName length] > 0) + fn = [NSMutableString stringWithFormat: @"%@ %@", firstName, lastName]; + else + fn = [NSMutableString stringWithString: firstName]; } + else if ([lastName length] > 0) + fn = [NSMutableString stringWithString: lastName]; } if ([fn length] > 0) { diff --git a/UI/Scheduler/UIxComponentEditor.m b/UI/Scheduler/UIxComponentEditor.m index 2e1b84c87..367478dda 100644 --- a/UI/Scheduler/UIxComponentEditor.m +++ b/UI/Scheduler/UIxComponentEditor.m @@ -292,13 +292,13 @@ iRANGE(2); - (void) _loadCategories { - NSString *compCategories, *simpleCategory; + NSString *simpleCategory; + NSArray *compCategories; compCategories = [component categories]; - if ([compCategories length] > 0) + if ([compCategories count] > 0) { - simpleCategory = [[compCategories componentsSeparatedByString: @","] - objectAtIndex: 0]; + simpleCategory = [compCategories objectAtIndex: 0]; ASSIGN (category, simpleCategory); } } @@ -405,7 +405,7 @@ iRANGE(2); { repeatType = @"3"; - if ([[rule namedValue: @"bymonth"] length]) + if ([[rule flattenedValuesForKey: @"bymonth"] length]) { if ([[rule byDay] length]) { @@ -420,13 +420,13 @@ iRANGE(2); [self setRepeat2: @"1"]; [self setRepeat5: [NSString stringWithFormat: @"%d", firstOccurrence]]; [self setRepeat6: [NSString stringWithFormat: @"%d", [dayMask firstDay]]]; - [self setRepeat7: [NSString stringWithFormat: @"%d", [[rule namedValue: @"bymonth"] intValue]-1]]; + [self setRepeat7: [NSString stringWithFormat: @"%d", [[rule flattenedValuesForKey: @"bymonth"] intValue]-1]]; } else { [self setRepeat2: @"0"]; - [self setRepeat3: [rule namedValue: @"bymonthday"]]; - [self setRepeat4: [NSString stringWithFormat: @"%d", [[rule namedValue: @"bymonth"] intValue]-1]]; + [self setRepeat3: [rule flattenedValuesForKey: @"bymonthday"]]; + [self setRepeat4: [NSString stringWithFormat: @"%d", [[rule flattenedValuesForKey: @"bymonth"] intValue]-1]]; } } else if ([rule repeatInterval] == 1) @@ -440,7 +440,7 @@ iRANGE(2); { repeat = @"CUSTOM"; [self setRange1: @"1"]; - [self setRange2: [rule namedValue: @"count"]]; + [self setRange2: [rule flattenedValuesForKey: @"count"]]; } else if ([rule untilDate]) { @@ -519,7 +519,7 @@ iRANGE(2); || [reminderAction isEqualToString: @"email"]) && [[aTrigger valueType] caseInsensitiveCompare: @"DURATION"] == NSOrderedSame) { - duration = [aTrigger value]; + duration = [aTrigger flattenedValuesForKey: @""]; i = [reminderValues indexOfObject: duration]; if (i == NSNotFound || [reminderAction isEqualToString: @"email"]) @@ -611,8 +611,7 @@ iRANGE(2); ASSIGN (privacy, [component accessClass]); ASSIGN (priority, [component priority]); ASSIGN (status, [component status]); - ASSIGN (categories, - [[component categories] vCardSubvaluesWithSeparator: ',']); + ASSIGN (categories, [component categories]); if ([[[component organizer] rfc822Email] length]) { ASSIGN (organizer, [component organizer]); @@ -1853,6 +1852,7 @@ RANGE(2); { int type, range; + NSMutableArray *values; // We decode the range range = [[self range1] intValue]; @@ -1990,14 +1990,21 @@ RANGE(2); occurence = [[self repeat3] intValue] + 1; if (occurence > 5) // the first/second/third/fourth/fifth .. occurence = -1; // the last .. - [theRule setNamedValue: @"byday" - to: [NSString stringWithFormat: @"%d%@", - occurence, day]]; + [theRule setSingleValue: [NSString stringWithFormat: @"%d%@", + occurence, day] + forKey: @"byday"]; } else { if ([[self repeat5] intValue] > 0) - [theRule setNamedValue: @"bymonthday" to: [self repeat5]]; + { + values = [[[self repeat5] + componentsSeparatedByString: @","] + mutableCopy]; + [theRule setValues: values + atIndex: 0 forKey: @"bymonthday"]; + [values release]; + } } } } @@ -2037,22 +2044,27 @@ RANGE(2); occurence = [[self repeat5] intValue] + 1; if (occurence > 5) // the first/second/third/fourth/fifth .. occurence = -1; // the last .. - [theRule setNamedValue: @"byday" - to: [NSString stringWithFormat: @"%d%@", - occurence, day]]; - [theRule setNamedValue: @"bymonth" - to: [NSString stringWithFormat: @"%d", - [[self repeat7] intValue] + 1]]; + [theRule setSingleValue: [NSString stringWithFormat: @"%d%@", + occurence, day] + forKey: @"byday"]; + [theRule setSingleValue: [NSString stringWithFormat: @"%d", + [[self repeat7] intValue] + 1] + forKey: @"bymonth"]; } else { if ([[self repeat3] intValue] > 0 && [[self repeat4] intValue] > 0) { - [theRule setNamedValue: @"bymonthday" - to: [self repeat3]]; - [theRule setNamedValue: @"bymonth" - to: [NSString stringWithFormat: @"%d", ([[self repeat4] intValue]+1)]]; + values = [[[self repeat3] + componentsSeparatedByString: @","] + mutableCopy]; + [theRule setValues: values atIndex: 0 + forKey: @"bymonthday"]; + [values release]; + [theRule setSingleValue: [NSString stringWithFormat: @"%d", + [[self repeat4] intValue] + 1] + forKey: @"bymonth"]; } } } @@ -2111,7 +2123,7 @@ RANGE(2); [component setComment: comment]; [component setAttach: attachUrl]; [component setAccessClass: privacy]; - [component setCategories: category]; + [component setCategories: categories]; [self _handleAttendeesEdition]; [self _handleOrganizer]; clientObject = [self clientObject]; @@ -2146,7 +2158,7 @@ RANGE(2); if ([aValue length]) { // Predefined alarm [anAlarm setAction: @"DISPLAY"]; - [aTrigger setValue: aValue]; + [aTrigger setSingleValue: aValue forKey: @""]; } else { // Custom alarm @@ -2177,7 +2189,7 @@ RANGE(2); aValue = [aValue stringByAppendingFormat: @"%i%@", [reminderQuantity intValue], [reminderUnit substringToIndex: 1]]; - [aTrigger setValue: aValue]; + [aTrigger setSingleValue: aValue forKey: @""]; [aTrigger setRelationType: reminderRelation]; } else