1 /* NSString+Utilities.m - this file is part of SOGo
3 * Copyright (C) 2006 Inverse groupe conseil
5 * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
7 * This file is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * This file is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 #import <Foundation/NSArray.h>
24 #import <Foundation/NSCharacterSet.h>
25 #import <Foundation/NSEnumerator.h>
27 #import <NGExtensions/NGQuotedPrintableCoding.h>
29 #import "NSArray+Utilities.h"
30 #import "NSDictionary+URL.h"
32 #import "NSString+Utilities.h"
34 static NSMutableCharacterSet *urlNonEndingChars = nil;
35 static NSMutableCharacterSet *urlAfterEndingChars = nil;
37 @implementation NSString (SOGoURLExtension)
39 - (NSString *) composeURLWithAction: (NSString *) action
40 parameters: (NSDictionary *) urlParameters
41 andHash: (BOOL) useHash
43 NSMutableString *completeURL;
45 completeURL = [NSMutableString new];
46 [completeURL autorelease];
48 [completeURL appendString: [self urlWithoutParameters]];
49 if (![completeURL hasSuffix: @"/"])
50 [completeURL appendString: @"/"];
51 [completeURL appendString: action];
52 [completeURL appendString: [urlParameters asURLParameters]];
54 [completeURL appendString: @"#"];
59 - (NSString *) hostlessURL
62 NSRange hostR, locationR;
64 if ([self hasPrefix: @"/"])
71 hostR = [self rangeOfString: @"://"];
72 locationR = [[self substringFromIndex: (hostR.location + hostR.length)]
74 newURL = [self substringFromIndex: (hostR.location + hostR.length
75 + locationR.location)];
81 - (NSString *) urlWithoutParameters;
86 r = [self rangeOfString:@"?" options: NSBackwardsSearch];
88 newUrl = [self substringToIndex: NSMaxRange(r) - 1];
95 - (NSString *) davMethodToObjC
97 NSMutableString *newName;
98 NSEnumerator *components;
101 newName = [NSMutableString stringWithString: @"dav"];
102 components = [[self componentsSeparatedByString: @"-"] objectEnumerator];
103 component = [components nextObject];
106 [newName appendString: [component capitalizedString]];
107 component = [components nextObject];
113 - (NSDictionary *) asDavInvocation
115 NSMutableDictionary *davInvocation;
116 NSRange nsEnclosing, methodEnclosing;
120 if ([self hasPrefix: @"{"])
122 nsEnclosing = [self rangeOfString: @"}"];
123 length = [self length];
124 if (nsEnclosing.length > 0
125 && nsEnclosing.location < (length - 1))
127 methodEnclosing = NSMakeRange(nsEnclosing.location + 1,
128 length - nsEnclosing.location - 1);
129 nsEnclosing.length = nsEnclosing.location - 1;
130 nsEnclosing.location = 1;
131 davInvocation = [NSMutableDictionary dictionaryWithCapacity: 2];
132 [davInvocation setObject: [self substringWithRange: nsEnclosing]
134 [davInvocation setObject: [self substringWithRange: methodEnclosing]
139 return davInvocation;
142 - (NSRange) _rangeOfURLInRange: (NSRange) refRange
147 // [urlNonEndingChars addCharactersInString: @">&=,.:;\t \r\n"];
148 // [urlAfterEndingChars addCharactersInString: @"()[]{}&;<\t \r\n"];
150 if (!urlNonEndingChars)
152 urlNonEndingChars = [NSMutableCharacterSet new];
153 [urlNonEndingChars addCharactersInString: @">=,.:;\t \r\n"];
155 if (!urlAfterEndingChars)
157 urlAfterEndingChars = [NSMutableCharacterSet new];
158 [urlAfterEndingChars addCharactersInString: @"[]\t \r\n"];
161 start = refRange.location;
163 && ![urlAfterEndingChars characterIsMember:
164 [self characterAtIndex: start]])
167 length = [self length] - start;
168 workRange = NSMakeRange(start, length);
169 workRange = [self rangeOfCharacterFromSet: urlAfterEndingChars
170 options: NSLiteralSearch range: workRange];
171 if (workRange.location != NSNotFound)
172 length = workRange.location - start;
175 && [urlNonEndingChars characterIsMember:
176 [self characterAtIndex: (start + length - 1)]])
179 return NSMakeRange (start, length);
182 - (void) _handleURLs: (NSMutableString *) selfCopy
183 textToMatch: (NSString *) match
184 prefix: (NSString *) prefix
185 inRanges: (NSMutableArray *) ranges
187 NSRange httpRange, currentURL, rest;
188 NSString *urlText, *newUrlText;
189 unsigned int length, matchLength;
191 matchLength = [match length];
192 httpRange = [selfCopy rangeOfString: match];
193 while (httpRange.location != NSNotFound)
195 if ([ranges hasRangeIntersection: httpRange])
196 rest.location = NSMaxRange(httpRange);
199 currentURL = [selfCopy _rangeOfURLInRange: httpRange];
200 urlText = [selfCopy substringFromRange: currentURL];
201 if ([urlText length] > matchLength)
203 if ([urlText hasPrefix: prefix]) prefix = @"";
205 newUrlText = [NSString stringWithFormat: @"<a href=\"%@%@\">%@</a>",
206 prefix, urlText, urlText];
207 [selfCopy replaceCharactersInRange: currentURL
208 withString: newUrlText];
210 = NSMakeRange (currentURL.location, [newUrlText length]);
211 [ranges addRange: currentURL];
213 rest.location = NSMaxRange(currentURL);
216 length = [selfCopy length];
217 rest.length = length - rest.location;
218 httpRange = [selfCopy rangeOfString: match
219 options: 0 range: rest];
223 - (NSString *) stringByDetectingURLs
225 NSMutableString *selfCopy;
226 NSMutableArray *ranges;
228 ranges = [NSMutableArray new];
229 selfCopy = [NSMutableString stringWithString: self];
230 [self _handleURLs: selfCopy
234 [self _handleURLs: selfCopy
243 - (NSString *) jsonRepresentation
245 NSMutableString *representation;
247 representation = [NSMutableString stringWithString: self];
248 [representation replaceString: @"\\" withString: @"\\\\"];
249 [representation replaceString: @"\"" withString: @"\\\""];
250 [representation replaceString: @"/" withString: @"\\/"];
251 [representation replaceString: @"\b" withString: @"\\b"];
252 [representation replaceString: @"\f" withString: @"\\f"];
253 [representation replaceString: @"\n" withString: @"\\n"];
254 [representation replaceString: @"\r" withString: @"\\r"];
255 [representation replaceString: @"\t" withString: @"\\t"];
257 return [NSString stringWithFormat: @"\"%@\"", representation];
260 - (NSString *) pureEMailAddress
262 NSString *pureAddress;
265 delimiter = [self rangeOfString: @"<"];
266 if (delimiter.location == NSNotFound)
270 pureAddress = [self substringFromIndex: NSMaxRange (delimiter)];
271 delimiter = [pureAddress rangeOfString: @">"];
272 if (delimiter.location != NSNotFound)
273 pureAddress = [pureAddress substringToIndex: delimiter.location];
279 - (NSString *) asQPSubjectString: (NSString *) encoding
281 NSString *qpString, *subjectString;
282 NSData *subjectData, *destSubjectData;
284 subjectData = [self dataUsingEncoding: NSUTF8StringEncoding];
285 destSubjectData = [subjectData dataByEncodingQuotedPrintable];
287 qpString = [[NSString alloc] initWithData: destSubjectData
288 encoding: NSASCIIStringEncoding];
289 [qpString autorelease];
290 if ([qpString length] > [self length])
291 subjectString = [NSString stringWithFormat: @"=?%@?Q?%@?=",
294 subjectString = self;
296 return subjectString;
299 #if LIB_FOUNDATION_LIBRARY
302 return !([self isEqualToString: @"0"]
303 || [self isEqualToString: @"NO"]);