Developer Area

root/apps/iphone/superbook/trunk/DotTel_SDK/Classes/RecordTxt.m @ 546

Revision 546, 8.4 kB (checked in by henri, 4 years ago)

Significant update to 1.4.
Long labels, subdomain IDNs, Google MapKit?. Required OS Version 3.0.

Line 
1//
2//  RecordTxt.m
3//  DotTel SDK
4//
5//  Created by Henri Asseily on 9/13/08.
6/*
7 Copyright (c) 2008-2009, Telnic Ltd. All rights reserved.
8 
9 Redistribution and use in source and binary forms, with or without modification,
10 are permitted provided that the following conditions are met:
11 
12 Redistributions of source code must retain the above copyright notice, this list of conditions
13 and the following disclaimer. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the documentation and/or other
15 materials provided with the distribution.
16 Neither the name of the Telnic Ltd. nor the names of its contributors may be used to endorse or
17 promote products derived from this software without specific prior written permission.
18 THIS DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
19 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
24 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27//
28
29#import "RecordTxt.h"
30
31static NSCharacterSet *trimCharacterSet;
32
33@interface RecordTxt (PrivateMethods)
34
35- (BOOL)parseDisplayStringFromRecord:(const ldns_rr *)rr;
36- (BOOL)parseLabelFromRecord:(const ldns_rr *)rr;
37- (BOOL)parseKeywordsFromRecord:(const ldns_rr *)rr;
38
39- (NSMutableString *)stringFromStringRdf:(const ldns_rdf *)rdf;
40
41@end
42
43@implementation RecordTxt
44
45@synthesize isValid;
46@synthesize subType;
47@synthesize expiryDate;
48
49@synthesize primaryDescription;
50@synthesize primaryValue;
51@synthesize textValue;
52@synthesize keysAndValues;
53@synthesize order;
54@synthesize preference;
55
56+ (id)recordWithRr:(ldns_rr *)rr {
57        NSDate *lookupDate = [[NSDate date] retain];
58        self = [RecordTxt recordWithRr:rr date:lookupDate];
59        [lookupDate release];
60        return self;
61}
62
63+ (id)recordWithRr:(ldns_rr *)rr date:(NSDate *)lookupDate {
64        self = [[[RecordTxt alloc] initWithRr:rr date:lookupDate] autorelease];
65        return self;
66}
67
68- (id)init {
69        // Never initialize it empty
70        self = [super init];
71        isValid = NO;
72        subType = RecordTxtSubTypeString;
73        return self;
74}
75
76- (id)initWithRr:(ldns_rr *)rr date:(NSDate *)lookupDate {
77        self = [super init];
78        trimCharacterSet = [[NSCharacterSet whitespaceCharacterSet] retain];
79        isValid = NO;
80        order = preference = 0;
81       
82        if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_TXT)
83                return self;
84       
85        NSTimeInterval ttl = (NSTimeInterval)ldns_rr_ttl(rr);
86        expiryDate = [lookupDate addTimeInterval:ttl];
87       
88        NSString *firstString = [self stringFromStringRdf:ldns_rr_rdf(rr,0)];
89        if ([firstString isEqualToString:@".tkw"]) {
90                // parse keywords
91                subType = RecordTxtSubTypeKeyword;
92                isValid = [self parseKeywordsFromRecord:rr];
93        } else if ([firstString isEqualToString:@".tsm"]) {
94                // system message
95                // let's see if it's something we know
96                NSString *smType = [self stringFromStringRdf:ldns_rr_rdf(rr,2)];
97                if (smType != nil) {
98                        if ([smType isEqualToString:@"dds"]) {
99                                // Domain display string
100                                subType = RecordTxtSubTypeDDS;
101                                isValid = [self parseDisplayStringFromRecord:rr];
102                                return self;
103                        }
104                }
105                subType = RecordTxtSubTypeOtherTSM;
106                return self;
107        } else if ([firstString isEqualToString:@".tad"]) {
108                // advert, do nothing for now
109                subType = RecordTxtSubTypeAdvert;
110                return self;
111        } else if ([firstString isEqualToString:@".tlb"]) {
112                // record label
113                subType = RecordTxtSubTypeLabel;
114                isValid = [self parseLabelFromRecord:rr];
115                return self;
116        } else {
117                // header
118                subType = RecordTxtSubTypeString;
119                primaryDescription = [@"" retain];
120                primaryValue = NULL;
121                // Could have multiple strings in one record, they need to be joined together
122                NSMutableArray *stringComponents = [NSMutableArray arrayWithCapacity:2];
123                for (NSUInteger i=0; i < ldns_rr_rd_count(rr); i++) {
124                        [stringComponents addObject:[self stringFromStringRdf:ldns_rr_rdf(rr,i)]];
125                }
126               
127                textValue = [stringComponents componentsJoinedByString:@" "];
128                isValid = YES;
129        }
130       
131        return self;
132}
133
134- (BOOL)parseDisplayStringFromRecord:(const ldns_rr *)rr {
135        // That's the domain display string, which should replace the regular domain name
136        // ".tsm " "1" "dds" "John W. Smith"
137       
138        // Check version
139        if ([[self stringFromStringRdf:ldns_rr_rdf(rr,1)] isEqualToString:@"1"]) {
140                // Version 1
141                textValue = [[self stringFromStringRdf:ldns_rr_rdf(rr,3)] retain];
142                return TRUE;
143        }
144        textValue = nil;
145        return FALSE;
146}
147
148- (BOOL)parseLabelFromRecord:(const ldns_rr *)rr {
149        // Labels always start with ".lbl" and have an order and preference to map them to records
150        // ".tlb", "1", "100", "101", "This is a label"
151       
152        // Check version
153        if ([[self stringFromStringRdf:ldns_rr_rdf(rr,1)] isEqualToString:@"1"]) {
154                // Version 1
155                order = [[self stringFromStringRdf:ldns_rr_rdf(rr,2)] integerValue];
156                preference = [[self stringFromStringRdf:ldns_rr_rdf(rr,3)] integerValue];
157                textValue = [[self stringFromStringRdf:ldns_rr_rdf(rr,4)] retain];
158                return TRUE;
159        } else {
160                // Unknown version
161                textValue = nil;
162                return FALSE;
163        }
164}
165
166- (BOOL)parseKeywordsFromRecord:(const ldns_rr *)rr {
167        // Keywords always start with ".tkw" followed by the version number.
168        // After that, there are any number of pairs of type and value
169        // In general there should be a single pair, but compound keywords like addresses
170        // will have more. Here we opt to concatenate all the values for these compound keywords
171        // and only keep the first type string, discarding all other type strings if they exist
172        // However, we also keep a full array of type+value in case the user wants to store that
173        // info into the address book.
174       
175        // Check version
176        if ([[self stringFromStringRdf:ldns_rr_rdf(rr,1)] isEqualToString:@"1"]) {
177                // Version 1
178                keysAndValues = [[NSMutableArray arrayWithCapacity:ldns_rr_rd_count(rr)] retain];
179                for (NSUInteger i=2; i < ldns_rr_rd_count(rr); i=i+2) {
180                        // Merge together any values if there are consecutive keys that are the same
181                        // for example "ft" "123" "ft" "456"  becomes "ft" "123456"
182                        // This allows for infinite length strings
183                        NSMutableString *theKey = [self stringFromStringRdf:ldns_rr_rdf(rr,i)];
184                        NSMutableString *theVal = [self stringFromStringRdf:ldns_rr_rdf(rr,i+1)];
185                        while (((i+2) < ldns_rr_rd_count(rr)) &&
186                                   [theKey isEqualToString:[self stringFromStringRdf:ldns_rr_rdf(rr,i+2)]]) {
187                                // next key is the same, let's move forward and append
188                                i = i+2;
189                                [theVal appendString:[self stringFromStringRdf:ldns_rr_rdf(rr,i+1)]];
190                        }
191                        [keysAndValues addObject:theKey];
192                        [keysAndValues addObject:theVal];
193                }
194               
195                // Now that we've got all keys and values (with same consecutive keys merged),
196                // We create the description strings and text values for display
197               
198                primaryDescription = [LocTelStr([keysAndValues objectAtIndex:0]) retain];
199                if ([keysAndValues count] < 3) {        // Only a single primary keyword/value
200                        primaryValue = NULL;
201                        textValue = [keysAndValues objectAtIndex:1];
202                } else {
203                        primaryValue = [keysAndValues objectAtIndex:1];
204                        NSMutableArray *keyValueComponents = [NSMutableArray arrayWithCapacity:2];
205                        for (NSUInteger i=3; i < [keysAndValues count]; i=i+2) {
206                                [keyValueComponents addObject:[keysAndValues objectAtIndex:i]];
207                        }
208                        textValue = [[[keyValueComponents componentsJoinedByString:@" "]
209                                                  stringByTrimmingCharactersInSet:trimCharacterSet] retain];
210                }
211                return TRUE;
212        } else {
213                // Unknown version
214                return FALSE;
215        }
216}
217
218# pragma mark ------------- Utility functions for parsing record data fields ------------
219
220- (NSMutableString *)stringFromStringRdf:(const ldns_rdf *)rdf {
221        if (rdf == NULL) {
222                return nil;
223        }
224        NSMutableString *res;
225        const uint8_t *data = ldns_rdf_data(rdf);
226        uint8_t length = data[0];
227        res = [[[NSMutableString alloc] initWithBytes:(const unichar *)(data+1)
228                                                                                   length:length
229                                                                                 encoding:NSUTF8StringEncoding] autorelease];
230        return res;
231}
232
233#pragma mark ---- cleanup ----
234
235- (void)dealloc {
236        [trimCharacterSet release];
237        //      [primaryDescription release];
238        //      [primaryValue release];
239        //      [textValue release];
240        //      [keysAndValues release];
241        //      [expiryDate release];
242        [super dealloc];
243}
244
245@end
Note: See TracBrowser for help on using the browser.
Telnic
Search This Site
Partners
Neustar
ICANN
Main site | WHOIS | Sell .tel | FAQ | Archived Site | About Telnic | Contact Us