]> err.no Git - scalable-opengroupware.org/blob - SoObjects/SOGo/NSString+Utilities.m
1192ccd70d20e3b517da61896445c4085e6603d6
[scalable-opengroupware.org] / SoObjects / SOGo / NSString+Utilities.m
1 /* NSString+Utilities.m - this file is part of SOGo
2  *
3  * Copyright (C) 2006  Inverse groupe conseil
4  *
5  * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
6  *
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)
10  * any later version.
11  *
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.
16  *
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.
21  */
22
23 #import <Foundation/NSArray.h>
24 #import <Foundation/NSCharacterSet.h>
25 #import <Foundation/NSEnumerator.h>
26
27 #import <NGExtensions/NGQuotedPrintableCoding.h>
28
29 #import "NSArray+Utilities.h"
30 #import "NSDictionary+URL.h"
31
32 #import "NSString+Utilities.h"
33
34 static NSMutableCharacterSet *urlNonEndingChars = nil;
35 static NSMutableCharacterSet *urlAfterEndingChars = nil;
36
37 @implementation NSString (SOGoURLExtension)
38
39 - (NSString *) composeURLWithAction: (NSString *) action
40                          parameters: (NSDictionary *) urlParameters
41                             andHash: (BOOL) useHash
42 {
43   NSMutableString *completeURL;
44
45   completeURL = [NSMutableString new];
46   [completeURL autorelease];
47
48   [completeURL appendString: [self urlWithoutParameters]];
49   if (![completeURL hasSuffix: @"/"])
50     [completeURL appendString: @"/"];
51   [completeURL appendString: action];
52   [completeURL appendString: [urlParameters asURLParameters]];
53   if (useHash)
54     [completeURL appendString: @"#"];
55
56   return completeURL;
57 }
58
59 - (NSString *) hostlessURL
60 {
61   NSString *newURL;
62   NSRange hostR, locationR;
63
64   if ([self hasPrefix: @"/"])
65     {
66       newURL = [self copy];
67       [newURL autorelease];
68     }
69   else
70     {
71       hostR = [self rangeOfString: @"://"];
72       locationR = [[self substringFromIndex: (hostR.location + hostR.length)]
73                     rangeOfString: @"/"];
74       newURL = [self substringFromIndex: (hostR.location + hostR.length
75                                           + locationR.location)];
76     }
77
78   return newURL;
79 }
80
81 - (NSString *) urlWithoutParameters;
82 {
83   NSRange r;
84   NSString *newUrl;
85   
86   r = [self rangeOfString:@"?" options: NSBackwardsSearch];
87   if (r.length > 0)
88     newUrl = [self substringToIndex: NSMaxRange(r) - 1];
89   else
90     newUrl = self;
91
92   return newUrl;
93 }
94
95 - (NSString *) davMethodToObjC
96 {
97   NSMutableString *newName;
98   NSEnumerator *components;
99   NSString *component;
100
101   newName = [NSMutableString stringWithString: @"dav"];
102   components = [[self componentsSeparatedByString: @"-"] objectEnumerator];
103   component = [components nextObject];
104   while (component)
105     {
106       [newName appendString: [component capitalizedString]];
107       component = [components nextObject];
108     }
109
110   return newName;
111 }
112
113 - (NSDictionary *) asDavInvocation
114 {
115   NSMutableDictionary *davInvocation;
116   NSRange nsEnclosing, methodEnclosing;
117   unsigned int length;
118
119   davInvocation = nil;
120   if ([self hasPrefix: @"{"])
121     {
122       nsEnclosing = [self rangeOfString: @"}"];
123       length = [self length];
124       if (nsEnclosing.length > 0
125           && nsEnclosing.location < (length - 1))
126         {
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]
133                          forKey: @"ns"];
134           [davInvocation setObject: [self substringWithRange: methodEnclosing]
135                          forKey: @"method"];
136         }
137     }
138
139   return davInvocation;
140 }
141
142 - (NSRange) _rangeOfURLInRange: (NSRange) refRange
143 {
144   int start, length;
145   NSRange workRange;
146
147 //       [urlNonEndingChars addCharactersInString: @">&=,.:;\t \r\n"];
148 //       [urlAfterEndingChars addCharactersInString: @"()[]{}&;<\t \r\n"];
149
150   if (!urlNonEndingChars)
151     {
152       urlNonEndingChars = [NSMutableCharacterSet new];
153       [urlNonEndingChars addCharactersInString: @">=,.:;\t \r\n"];
154     }
155   if (!urlAfterEndingChars)
156     {
157       urlAfterEndingChars = [NSMutableCharacterSet new];
158       [urlAfterEndingChars addCharactersInString: @"[]\t \r\n"];
159     }
160
161   start = refRange.location;
162   while (start > -1
163          && ![urlAfterEndingChars characterIsMember:
164                                     [self characterAtIndex: start]])
165     start--;
166   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;
173   while
174     (length > 0
175      && [urlNonEndingChars characterIsMember:
176                              [self characterAtIndex: (start + length - 1)]])
177     length--;
178
179   return NSMakeRange (start, length);
180 }
181
182 - (void) _handleURLs: (NSMutableString *) selfCopy
183          textToMatch: (NSString *) match
184               prefix: (NSString *) prefix
185             inRanges: (NSMutableArray *) ranges
186 {
187   NSRange httpRange, currentURL, rest;
188   NSString *urlText, *newUrlText;
189   unsigned int length, matchLength;
190
191   matchLength = [match length];
192   httpRange = [selfCopy rangeOfString: match];
193   while (httpRange.location != NSNotFound)
194     {
195       if ([ranges hasRangeIntersection: httpRange])
196         rest.location = NSMaxRange(httpRange);
197       else
198         {
199           currentURL = [selfCopy _rangeOfURLInRange: httpRange];
200           urlText = [selfCopy substringFromRange: currentURL];
201           if ([urlText length] > matchLength)
202             {
203               if ([urlText hasPrefix: prefix]) prefix = @"";
204
205               newUrlText = [NSString stringWithFormat: @"<a href=\"%@%@\">%@</a>",
206                                      prefix, urlText, urlText];
207               [selfCopy replaceCharactersInRange: currentURL
208                         withString: newUrlText];
209               currentURL
210                 = NSMakeRange (currentURL.location, [newUrlText length]);
211               [ranges addRange: currentURL];
212             }
213           rest.location = NSMaxRange(currentURL);
214         }
215
216       length = [selfCopy length];
217       rest.length = length - rest.location;
218       httpRange = [selfCopy rangeOfString: match
219                             options: 0 range: rest];
220     }
221 }
222
223 - (NSString *) stringByDetectingURLs
224 {
225   NSMutableString *selfCopy;
226   NSMutableArray *ranges;
227
228   ranges = [NSMutableArray new];
229   selfCopy = [NSMutableString stringWithString: self];
230   [self _handleURLs: selfCopy
231         textToMatch: @"://"
232         prefix: @""
233         inRanges: ranges];
234   [self _handleURLs: selfCopy
235         textToMatch: @"@"
236         prefix: @"mailto:"
237         inRanges: ranges];
238   [ranges release];
239
240   return selfCopy;
241 }
242
243 - (NSString *) jsonRepresentation
244 {
245   NSMutableString *representation;
246
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"];
256
257   return [NSString stringWithFormat: @"\"%@\"", representation];
258 }
259
260 - (NSString *) pureEMailAddress
261 {
262   NSString *pureAddress;
263   NSRange delimiter;
264
265   delimiter = [self rangeOfString: @"<"];
266   if (delimiter.location == NSNotFound)
267     pureAddress = self;
268   else
269     {
270       pureAddress = [self substringFromIndex: NSMaxRange (delimiter)];
271       delimiter = [pureAddress rangeOfString: @">"];
272       if (delimiter.location != NSNotFound)
273         pureAddress = [pureAddress substringToIndex: delimiter.location];
274     }
275
276   return pureAddress;
277 }
278
279 - (NSString *) asQPSubjectString: (NSString *) encoding
280 {
281   NSString *qpString, *subjectString;
282   NSData *subjectData, *destSubjectData;
283
284   subjectData = [self dataUsingEncoding: NSUTF8StringEncoding];
285   destSubjectData = [subjectData dataByEncodingQuotedPrintable];
286
287   qpString = [[NSString alloc] initWithData: destSubjectData
288                                encoding: NSASCIIStringEncoding];
289   [qpString autorelease];
290   if ([qpString length] > [self length])
291     subjectString = [NSString stringWithFormat: @"=?%@?Q?%@?=",
292                               encoding, qpString];
293   else
294     subjectString = self;
295
296   return subjectString;
297 }
298
299 #if LIB_FOUNDATION_LIBRARY
300 - (BOOL) boolValue
301 {
302   return !([self isEqualToString: @"0"]
303            || [self isEqualToString: @"NO"]);
304 }
305 #endif
306
307 @end