root/apps/iphone/superbook/trunk/DotTel_SDK/Classes/TelDomain.m
@
720
| Revision 720, 10.9 kB (checked in by henri, 3 years ago) |
|---|
| Line | |
|---|---|
| 1 | // |
| 2 | // TelDomain.m |
| 3 | // DotTel SDK |
| 4 | // |
| 5 | // Created by Henri Asseily on 3/17/10. |
| 6 | // Copyright 2010 Telnic Limited. All rights reserved. |
| 7 | /* |
| 8 | Redistribution and use in source and binary forms, with or without modification, |
| 9 | are permitted provided that the following conditions are met: |
| 10 | |
| 11 | Redistributions of source code must retain the above copyright notice, this list of conditions |
| 12 | and the following disclaimer. Redistributions in binary form must reproduce the above copyright |
| 13 | notice, this list of conditions and the following disclaimer in the documentation and/or other |
| 14 | materials provided with the distribution. |
| 15 | Neither the name of the Telnic Ltd. nor the names of its contributors may be used to endorse or |
| 16 | promote products derived from this software without specific prior written permission. |
| 17 | THIS DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS |
| 18 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY |
| 19 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| 20 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
| 23 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 24 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 25 | */ |
| 26 | // |
| 27 | |
| 28 | #import "TelDomain.h" |
| 29 | |
| 30 | @implementation TelDomain |
| 31 | |
| 32 | @synthesize telName = _telName; |
| 33 | @synthesize cleanTelName = _cleanTelName; |
| 34 | @synthesize displayName; |
| 35 | @synthesize headerText; |
| 36 | @synthesize logoUrl = _logoUrl; |
| 37 | @synthesize naptrArray; |
| 38 | @synthesize txtArray; |
| 39 | @synthesize allTxtArray; |
| 40 | @synthesize locArray; |
| 41 | @synthesize country; |
| 42 | @synthesize timeZone; |
| 43 | @synthesize geoLocDidFinish; |
| 44 | @synthesize delegate; |
| 45 | |
| 46 | #pragma mark - |
| 47 | #pragma mark Initializers |
| 48 | |
| 49 | // Don't allow init |
| 50 | - (id)init { |
| 51 | return nil; |
| 52 | } |
| 53 | |
| 54 | // Canonical initializer |
| 55 | - (id)initWithTelName:(NSString *)aTelName delegate:(id<TelDomainDelegate>)aDelegate { |
| 56 | if ((aTelName == nil) || (aDelegate == nil)) |
| 57 | return nil; |
| 58 | self = [super init]; |
| 59 | self.delegate = aDelegate; |
| 60 | _telName = [[self telFromQueryString:aTelName] retain]; |
| 61 | _cleanTelName = [[_telName stringByReplacingOccurrencesOfString:@"-" |
| 62 | withString:@" " |
| 63 | options:NSLiteralSearch |
| 64 | range:NSMakeRange(0, [_telName length])] retain]; |
| 65 | self.displayName = _cleanTelName; |
| 66 | _logoUrl = nil; |
| 67 | geoLocDidFinish = NO; |
| 68 | self.naptrArray = [NSMutableArray arrayWithCapacity:10]; |
| 69 | self.txtArray = [NSMutableArray arrayWithCapacity:10]; |
| 70 | self.allTxtArray = [NSMutableArray arrayWithCapacity:20]; |
| 71 | self.locArray = [NSMutableArray arrayWithCapacity:1]; |
| 72 | return self; |
| 73 | } |
| 74 | |
| 75 | - (void)dealloc { |
| 76 | [_telName release]; |
| 77 | [_cleanTelName release]; |
| 78 | if (_logoUrl) |
| 79 | [_logoUrl release]; |
| 80 | [super dealloc]; |
| 81 | } |
| 82 | |
| 83 | #pragma mark - |
| 84 | #pragma mark Data Methods |
| 85 | |
| 86 | - (NSError *)getNaptr { |
| 87 | NSError *error = nil; |
| 88 | [[NetworkUtility sharedInstance] networkwillActivate:YES]; |
| 89 | DnsResolver *res = [[DnsResolver alloc] init]; |
| 90 | NSUInteger naptrCount = [res getNAPTRForTel:self.telName inArray:self.naptrArray withError:&error]; |
| 91 | [res release]; |
| 92 | if (naptrCount == 0) { |
| 93 | #ifdef DEBUG |
| 94 | NSLog(@"Warning: Error or No NAPTR records in domain %@", telName); |
| 95 | #endif |
| 96 | } |
| 97 | // extract the logo (take the first one and leave the others as links) |
| 98 | RecordNaptr *theRec; |
| 99 | for (int i = 0; i < [naptrArray count]; i++) { |
| 100 | theRec = [naptrArray objectAtIndex:i]; |
| 101 | if (([theRec.serviceTypeArray count] > 0) && [[theRec.serviceTypeArray objectAtIndex:0] hasPrefix:@"x-photo:http"]) { |
| 102 | if (theRec.uriContent) |
| 103 | _logoUrl = [[NSURL URLWithString:theRec.uriContent] retain]; |
| 104 | [naptrArray removeObjectAtIndex:i]; |
| 105 | break; |
| 106 | } |
| 107 | } |
| 108 | [[NetworkUtility sharedInstance] networkwillActivate:NO]; |
| 109 | if ([self.delegate respondsToSelector:@selector(didFinishGettingNaptrWithError:)]) { |
| 110 | [self.delegate didFinishGettingNaptrWithError:error]; |
| 111 | } |
| 112 | return error; |
| 113 | } |
| 114 | |
| 115 | - (NSError *)getTxt { |
| 116 | NSError *error = nil; |
| 117 | [[NetworkUtility sharedInstance] networkwillActivate:YES]; |
| 118 | DnsResolver *res = [[DnsResolver alloc] init]; |
| 119 | NSUInteger txtCount = [res getTXTForTel:self.telName inArray:allTxtArray withError:&error]; |
| 120 | if (txtCount == 0) { |
| 121 | #ifdef DEBUG |
| 122 | NSLog(@"Warning: Error or No TXT records in domain %@", telName); |
| 123 | #endif |
| 124 | } |
| 125 | [[NetworkUtility sharedInstance] networkwillActivate:NO]; |
| 126 | [res release]; |
| 127 | // Now build out the keywords txtArray and extract the header, display string and other stuff |
| 128 | RecordTxt *theRec; |
| 129 | NSMutableString *_headerText = nil; |
| 130 | for (theRec in allTxtArray) { |
| 131 | if (theRec.subType == RecordTxtSubTypeKeyword) { |
| 132 | // It's a keyword, let's add it to the array in the txt section |
| 133 | [self.txtArray addObject:theRec]; |
| 134 | } else if (theRec.subType == RecordTxtSubTypeString) { |
| 135 | // simple string, currently a header |
| 136 | // Merge all simple strings into a header |
| 137 | if (!_headerText) { |
| 138 | _headerText = [NSMutableString stringWithString:theRec.textValue]; |
| 139 | } else { |
| 140 | //NSLog(theRec.textValue); |
| 141 | [_headerText appendFormat:@"\n%@", theRec.textValue]; |
| 142 | } |
| 143 | } else if (theRec.subType == RecordTxtSubTypeDDS) { |
| 144 | // domain display string |
| 145 | self.displayName = theRec.textValue; |
| 146 | } else { |
| 147 | // do nothing with the other records such as ads, just discard them |
| 148 | } |
| 149 | } |
| 150 | if (_headerText) |
| 151 | self.headerText = _headerText; |
| 152 | else |
| 153 | self.headerText = self.displayName; |
| 154 | if ([self.delegate respondsToSelector:@selector(didFinishGettingTxtWithError:)]) { |
| 155 | [self.delegate didFinishGettingTxtWithError:error]; |
| 156 | } |
| 157 | return error; |
| 158 | } |
| 159 | |
| 160 | - (NSError *)getLocWithReverseGeo:(BOOL)revGeo { |
| 161 | NSError *error = nil; |
| 162 | [[NetworkUtility sharedInstance] networkwillActivate:YES]; |
| 163 | DnsResolver *res = [[DnsResolver alloc] init]; |
| 164 | geoLocDidFinish = NO; |
| 165 | NSUInteger locCount = [res getLOCForTel:self.telName inArray:self.locArray withError:&error]; |
| 166 | [res release]; |
| 167 | [[NetworkUtility sharedInstance] networkwillActivate:NO]; |
| 168 | if (locCount > 1) { |
| 169 | //NSLog(@"Warning: %d LOC records in domain %@", locCount, telName); |
| 170 | } |
| 171 | if (locCount > 0) { |
| 172 | if (revGeo) { |
| 173 | // and now look up the timezone and other goodies that take a while because they use the web |
| 174 | [[NetworkUtility sharedInstance] networkwillActivate:YES]; |
| 175 | [self getCountryAndTimeZoneForLoc:(RecordLoc *)[self.locArray objectAtIndex:0]]; |
| 176 | [[NetworkUtility sharedInstance] networkwillActivate:NO]; |
| 177 | } |
| 178 | } |
| 179 | if ([self.delegate respondsToSelector:@selector(didFinishGettingLocWithError:)]) { |
| 180 | [self.delegate didFinishGettingLocWithError:error]; |
| 181 | } |
| 182 | return error; |
| 183 | } |
| 184 | |
| 185 | - (void)getNaptrAndTxtInBackground { |
| 186 | if ([NSThread isMainThread]) { |
| 187 | [self performSelectorInBackground:_cmd withObject:nil]; |
| 188 | return; |
| 189 | } |
| 190 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
| 191 | NSError *errorTxt = [self getTxt]; |
| 192 | NSError *errorNaptr = [self getNaptr]; |
| 193 | // merge the txt labels into the naptrs |
| 194 | DnsResolver *res = [[DnsResolver alloc] init]; |
| 195 | [res updateNaptrArray:self.naptrArray withTxtArray:self.allTxtArray]; |
| 196 | [res release]; |
| 197 | if ([self.delegate respondsToSelector:@selector(didFinishGettingNaptrAndTxtWithError:)]) { |
| 198 | if (errorNaptr != nil) { |
| 199 | [self.delegate didFinishGettingNaptrAndTxtWithError:errorNaptr]; |
| 200 | } else { |
| 201 | [self.delegate didFinishGettingNaptrAndTxtWithError:errorTxt]; |
| 202 | } |
| 203 | } |
| 204 | [pool release]; |
| 205 | } |
| 206 | |
| 207 | - (void)getLocAndReverseGeoInBackground{ |
| 208 | if ([NSThread isMainThread]) { |
| 209 | [self performSelectorInBackground:_cmd withObject:nil]; |
| 210 | return; |
| 211 | } |
| 212 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
| 213 | [self getLocWithReverseGeo:YES]; |
| 214 | [pool release]; |
| 215 | } |
| 216 | |
| 217 | - (void)getLocInBackground{ |
| 218 | if ([NSThread isMainThread]) { |
| 219 | [self performSelectorInBackground:_cmd withObject:nil]; |
| 220 | return; |
| 221 | } |
| 222 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
| 223 | [self getLocWithReverseGeo:NO]; |
| 224 | [pool release]; |
| 225 | } |
| 226 | |
| 227 | - (void)getCountryAndTimeZoneForLoc:(CLLocation *)aLoc { |
| 228 | // Get country and timezone |
| 229 | // Don't get current time because the url may be cached. Use the timezone to regenerate the current time |
| 230 | NSString *uS = [NSString stringWithFormat:@"http://ws.geonames.org/timezone?lat=%f&lng=%f", |
| 231 | aLoc.coordinate.latitude, aLoc.coordinate.longitude]; |
| 232 | NSURL *url = [NSURL URLWithString:uS]; |
| 233 | NSURLRequest *urlReq = [NSURLRequest requestWithURL:url |
| 234 | cachePolicy:NSURLRequestReturnCacheDataElseLoad |
| 235 | timeoutInterval:60.0]; |
| 236 | NSHTTPURLResponse *response = [[[NSHTTPURLResponse alloc] |
| 237 | initWithURL:url |
| 238 | MIMEType:@"text/xml" |
| 239 | expectedContentLength:1024 |
| 240 | textEncodingName:nil] autorelease]; |
| 241 | NSError *error; |
| 242 | NSData *tzData = [NSURLConnection sendSynchronousRequest:urlReq |
| 243 | returningResponse:&response |
| 244 | error:&error]; |
| 245 | if (tzData) { |
| 246 | // Got data |
| 247 | NSString *sData = [[NSString alloc] initWithData:tzData encoding:NSUTF8StringEncoding]; |
| 248 | // Now get country |
| 249 | NSRange rC1 = [sData rangeOfString:@"<countryName>"]; |
| 250 | if (rC1.location != NSNotFound) { |
| 251 | NSRange rC2 = [sData rangeOfString:@"</countryName>"]; |
| 252 | if (rC2.location != NSNotFound) { |
| 253 | NSRange rC = NSMakeRange(rC1.location+rC1.length, rC2.location - (rC1.location+rC1.length)); |
| 254 | self.country = [sData substringWithRange:rC]; |
| 255 | } |
| 256 | } |
| 257 | // And get timezone |
| 258 | NSRange rTZ1 = [sData rangeOfString:@"<timezoneId>"]; |
| 259 | if (rTZ1.location != NSNotFound) { |
| 260 | NSRange rTZ2 = [sData rangeOfString:@"</timezoneId>"]; |
| 261 | if (rTZ2.location != NSNotFound) { |
| 262 | NSRange rTZ = NSMakeRange(rTZ1.location+rTZ1.length, rTZ2.location - (rTZ1.location+rTZ1.length)); |
| 263 | self.timeZone = [NSTimeZone timeZoneWithName:[sData substringWithRange:rTZ]]; |
| 264 | } |
| 265 | } |
| 266 | [sData release]; |
| 267 | } |
| 268 | geoLocDidFinish = YES; |
| 269 | } |
| 270 | |
| 271 | |
| 272 | #pragma mark - |
| 273 | #pragma mark Utility Methods |
| 274 | |
| 275 | - (NSString *)telFromQueryString:(NSString *)query { |
| 276 | if (!query) |
| 277 | return nil; |
| 278 | NSMutableString *qry = [NSMutableString stringWithString:query]; |
| 279 | if ([qry length] == 0) |
| 280 | return nil; |
| 281 | if ([qry hasPrefix:@"http://"]) { |
| 282 | [qry deleteCharactersInRange:NSMakeRange(0, [@"http://" length])]; |
| 283 | } else if ([qry hasPrefix:@"https://"]) { |
| 284 | [qry deleteCharactersInRange:NSMakeRange(0, [@"https://" length])]; |
| 285 | } |
| 286 | if ([qry hasPrefix:@"www."]) { |
| 287 | [qry deleteCharactersInRange:NSMakeRange(0, [@"www." length])]; |
| 288 | } |
| 289 | if ([qry hasPrefix:@"+"]) { |
| 290 | // Check if it's a phone number, try the sip version |
| 291 | BOOL isValidNumber = YES; |
| 292 | NSMutableString *enumStr = [NSMutableString stringWithCapacity:30]; |
| 293 | NSRange prefixR = NSMakeRange(0, 0); |
| 294 | for (int i = 1; i < [qry length]; i++) { |
| 295 | unichar aChar = [qry characterAtIndex:i]; |
| 296 | if ((aChar < 47) || (aChar > 58)) { // Not in range of Unicode digits 0-9 |
| 297 | isValidNumber = NO; |
| 298 | break; |
| 299 | } |
| 300 | [enumStr replaceCharactersInRange:prefixR withString:[NSString stringWithFormat:@"%c.", aChar]]; |
| 301 | } |
| 302 | if (isValidNumber) { |
| 303 | [enumStr appendString:@"e164.arpa"]; |
| 304 | qry = enumStr; |
| 305 | } |
| 306 | } else if ([qry hasSuffix:@".tel"]) { |
| 307 | // .tel domain, do nothing |
| 308 | } else if ([qry hasSuffix:@".e164.arpa"]) { |
| 309 | // ENUM domain, let's add support for it, why not! |
| 310 | // Superbook will be the best ENUM client too! :) |
| 311 | } else { |
| 312 | qry = [NSString stringWithFormat:@"%@.tel", qry]; |
| 313 | } |
| 314 | return qry; |
| 315 | } |
| 316 | |
| 317 | @end |
Note: See TracBrowser
for help on using the browser.








