]> err.no Git - scalable-opengroupware.org/blob - SOGo/UI/SOGoUI/UIxComponent.m
fixed improper '&' escaping during generation of redirect URLs and changed logic...
[scalable-opengroupware.org] / SOGo / UI / SOGoUI / UIxComponent.m
1 /*
2   Copyright (C) 2004 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
6   OGo is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with OGo; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21
22 #include "UIxComponent.h"
23 #include "SOGoJSStringFormatter.h"
24 #include "common.h"
25 #include <NGObjWeb/SoHTTPAuthenticator.h>
26
27 @interface UIxComponent (PrivateAPI)
28 - (void)_parseQueryString:(NSString *)_s;
29 - (NSMutableDictionary *)_queryParameters;
30 @end
31
32 @implementation UIxComponent
33
34 static NSTimeZone *MET = nil;
35 static NSTimeZone *GMT = nil;
36
37 static NSMutableArray *dayLabelKeys       = nil;
38 static NSMutableArray *abbrDayLabelKeys   = nil;
39 static NSMutableArray *monthLabelKeys     = nil;
40 static NSMutableArray *abbrMonthLabelKeys = nil;
41
42 static BOOL uixDebugEnabled = NO;
43
44 + (void)initialize {
45   NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
46     
47   uixDebugEnabled = [ud boolForKey:@"SOGoUIxDebugEnabled"];
48
49   if (MET == nil) {
50     MET = [[NSTimeZone timeZoneWithAbbreviation:@"MET"] retain];
51     GMT = [[NSTimeZone timeZoneWithAbbreviation:@"GMT"] retain];
52   }
53   if (dayLabelKeys == nil) {
54     dayLabelKeys = [[NSMutableArray alloc] initWithCapacity:7];
55     [dayLabelKeys addObject:@"Sunday"];
56     [dayLabelKeys addObject:@"Monday"];
57     [dayLabelKeys addObject:@"Tuesday"];
58     [dayLabelKeys addObject:@"Wednesday"];
59     [dayLabelKeys addObject:@"Thursday"];
60     [dayLabelKeys addObject:@"Friday"];
61     [dayLabelKeys addObject:@"Saturday"];
62
63     abbrDayLabelKeys = [[NSMutableArray alloc] initWithCapacity:7];
64     [abbrDayLabelKeys addObject:@"a2_Sunday"];
65     [abbrDayLabelKeys addObject:@"a2_Monday"];
66     [abbrDayLabelKeys addObject:@"a2_Tuesday"];
67     [abbrDayLabelKeys addObject:@"a2_Wednesday"];
68     [abbrDayLabelKeys addObject:@"a2_Thursday"];
69     [abbrDayLabelKeys addObject:@"a2_Friday"];
70     [abbrDayLabelKeys addObject:@"a2_Saturday"];
71
72     monthLabelKeys = [[NSMutableArray alloc] initWithCapacity:12];
73     [monthLabelKeys addObject:@"January"];
74     [monthLabelKeys addObject:@"February"];
75     [monthLabelKeys addObject:@"March"];
76     [monthLabelKeys addObject:@"April"];
77     [monthLabelKeys addObject:@"May"];
78     [monthLabelKeys addObject:@"June"];
79     [monthLabelKeys addObject:@"July"];
80     [monthLabelKeys addObject:@"August"];
81     [monthLabelKeys addObject:@"September"];
82     [monthLabelKeys addObject:@"October"];
83     [monthLabelKeys addObject:@"November"];
84     [monthLabelKeys addObject:@"December"];
85
86     abbrMonthLabelKeys = [[NSMutableArray alloc] initWithCapacity:12];
87     [abbrMonthLabelKeys addObject:@"a3_January"];
88     [abbrMonthLabelKeys addObject:@"a3_February"];
89     [abbrMonthLabelKeys addObject:@"a3_March"];
90     [abbrMonthLabelKeys addObject:@"a3_April"];
91     [abbrMonthLabelKeys addObject:@"a3_May"];
92     [abbrMonthLabelKeys addObject:@"a3_June"];
93     [abbrMonthLabelKeys addObject:@"a3_July"];
94     [abbrMonthLabelKeys addObject:@"a3_August"];
95     [abbrMonthLabelKeys addObject:@"a3_September"];
96     [abbrMonthLabelKeys addObject:@"a3_October"];
97     [abbrMonthLabelKeys addObject:@"a3_November"];
98     [abbrMonthLabelKeys addObject:@"a3_December"];
99   }
100 }
101
102 - (void)dealloc {
103   [self->queryParameters release];
104   [super dealloc];
105 }
106
107 /* query parameters */
108
109 - (void)_parseQueryString:(NSString *)_s {
110   NSEnumerator *e;
111   NSString *part;
112     
113   e = [[_s componentsSeparatedByString:@"&"] objectEnumerator];
114   while ((part = [e nextObject])) {
115     NSRange  r;
116     NSString *key, *value;
117         
118     r = [part rangeOfString:@"="];
119     if (r.length == 0) {
120       /* missing value of query parameter */
121       key   = [part stringByUnescapingURL];
122       value = @"1";
123     }
124     else {
125       key   = [[part substringToIndex:r.location] stringByUnescapingURL];
126       value = [[part substringFromIndex:(r.location + r.length)] 
127                 stringByUnescapingURL];
128     }
129     [self->queryParameters setObject:value forKey:key];
130   }
131 }
132
133 - (NSString *)queryParameterForKey:(NSString *)_key {
134   return [[self _queryParameters] objectForKey:_key];
135 }
136
137 - (void)setQueryParameter:(NSString *)_param forKey:(NSString *)_key {
138   if(_key == nil)
139     return;
140
141   if(_param != nil)
142     [[self _queryParameters] setObject:_param forKey:_key];
143   else
144     [[self _queryParameters] removeObjectForKey:_key];
145 }
146
147 - (NSMutableDictionary *)_queryParameters {
148   if(!self->queryParameters) {
149     WORequest *req;
150     NSString  *uri;
151     NSRange   r;
152     
153     self->queryParameters = [[NSMutableDictionary alloc] initWithCapacity:8];
154     
155     req = [[self context] request];
156     uri = [req uri];
157     r   = [uri rangeOfString:@"?" options:NSBackwardsSearch];
158     if (r.length > 0) {
159       NSString *qs;
160       
161       qs = [uri substringFromIndex:NSMaxRange(r)];
162       [self _parseQueryString:qs];
163     }    
164   }
165   return self->queryParameters;
166 }
167
168 - (NSDictionary *)queryParameters {
169   return [self _queryParameters];
170 }
171
172 - (NSDictionary *)queryParametersBySettingSelectedDate:(NSCalendarDate *)_date{
173   NSMutableDictionary *qp;
174     
175   qp = [[self queryParameters] mutableCopy];
176   [self setSelectedDateQueryParameter:_date inDictionary:qp];
177   return [qp autorelease];
178 }
179
180 - (void)setSelectedDateQueryParameter:(NSCalendarDate *)_newDate
181                          inDictionary:(NSMutableDictionary *)_qp;
182 {
183   if(_newDate != nil)
184     [_qp setObject:[self dateStringForDate:_newDate] forKey:@"day"];
185   else
186     [_qp removeObjectForKey:@"day"];
187 }
188
189 - (NSString *)completeHrefForMethod:(NSString *)_method {
190   WOContext    *ctx;
191   NSDictionary *qp;
192   NSString     *qs, *qps;
193
194   qp = [self queryParameters];
195   if([qp count] == 0)
196     return _method;
197
198   ctx = [self context];
199   qps = [ctx queryPathSeparator];
200   [ctx setQueryPathSeparator:@"&"];
201   qs = [ctx queryStringFromDictionary:qp];
202   [ctx setQueryPathSeparator:qps];
203   return [_method stringByAppendingFormat:@"?%@", qs];
204 }
205
206 - (NSString *)ownMethodName {
207   NSString *uri;
208   NSRange  r;
209     
210   uri = [[[self context] request] uri];
211     
212   /* first: cut off query parameters */
213     
214   r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
215   if (r.length > 0)
216     uri = [uri substringToIndex:r.location];
217     
218   /* next: strip trailing slash */
219     
220   if ([uri hasSuffix:@"/"]) uri = [uri substringToIndex:([uri length] - 1)];
221   r = [uri rangeOfString:@"/" options:NSBackwardsSearch];
222     
223   /* then: cut of last path component */
224     
225   if (r.length == 0) // no slash? are we at root?
226     return @"/";
227     
228   return [uri substringFromIndex:(r.location + 1)];
229 }
230
231 - (NSString *)userFolderPath {
232   WOContext *ctx;
233   NSArray   *traversalObjects;
234   NSString  *url;
235   
236   ctx = [self context];
237   traversalObjects = [ctx objectTraversalStack];
238   url = [[traversalObjects objectAtIndex:1]
239                            baseURLInContext:ctx];
240   return [[NSURL URLWithString:url] path];
241 }
242
243 - (NSString *)ownPath {
244   NSString *uri;
245   NSRange  r;
246   
247   uri = [[[self context] request] uri];
248   
249   /* first: cut off query parameters */
250   
251   r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
252   if (r.length > 0)
253     uri = [uri substringToIndex:r.location];
254   return uri;
255 }
256
257 - (NSString *)relativePathToUserFolderSubPath:(NSString *)_sub {
258   NSString *dst, *rel;
259
260   dst = [[self userFolderPath] stringByAppendingPathComponent:_sub];
261   rel = [dst urlPathRelativeToPath:[self ownPath]];
262   return rel;
263 }
264   
265 /* date */
266
267 - (NSTimeZone *)viewTimeZone {
268   // Note: also in the folder, should be based on a cookie?
269   return MET;
270 }
271
272 - (NSTimeZone *)backendTimeZone {
273   return GMT;
274 }
275
276 - (NSCalendarDate *)selectedDate {
277   NSString       *s;
278   NSCalendarDate *cdate;
279
280   s = [self queryParameterForKey:@"day"];
281   cdate = ([s length] > 0)
282     ? [self dateForDateString:s]
283     : [NSCalendarDate date];
284   [cdate setTimeZone:[self viewTimeZone]];
285   s = [self queryParameterForKey:@"hm"];
286   if([s length] == 4) {
287     unsigned hour, minute;
288       
289     hour = [[s substringToIndex:2] unsignedIntValue];
290     minute = [[s substringFromIndex:2] unsignedIntValue];
291     cdate = [cdate hour:hour minute:minute];
292   }
293   else {
294     cdate = [cdate hour:12 minute:0];
295   }
296   return cdate;
297 }
298
299 - (NSString *)dateStringForDate:(NSCalendarDate *)_date {
300   [_date setTimeZone:[self viewTimeZone]];
301   return [_date descriptionWithCalendarFormat:@"%Y%m%d"];
302 }
303
304 - (NSCalendarDate *)dateForDateString:(NSString *)_dateString {
305   return [NSCalendarDate dateWithString:_dateString 
306                          calendarFormat:@"%Y%m%d"];
307 }
308
309
310 /* SoUser */
311
312 - (SoUser *)user {
313   WOContext *ctx;
314   
315   ctx = [self context];
316   return [[[self clientObject] authenticatorInContext:ctx] userInContext:ctx];
317 }
318
319 - (NSString *)shortUserNameForDisplay {
320   // TODO: better use a SoUser formatter?
321   // TODO: who calls that?
322   NSString *s;
323   NSRange  r;
324   
325   // TODO: USE USER MANAGER INSTEAD!
326   
327   s = [[self user] login];
328   if ([s length] < 10)
329     return s;
330     
331   // TODO: algorithm might be inappropriate, depends on the actual UID
332     
333   r = [s rangeOfString:@"."];
334   if (r.length == 0)
335     return s;
336     
337   return [s substringToIndex:r.location];
338 }
339
340 /* labels */
341
342 - (NSString *)labelForKey:(NSString *)_str {
343   WOResourceManager *rm;
344   NSArray           *languages;
345   WOContext         *ctx;
346   NSString          *label;
347   NSString          *lKey, *lTable, *lVal;
348   NSRange r;
349
350   if ([_str length] == 0)
351     return nil;
352   
353   /* lookup languages */
354     
355   ctx = [self context];
356   languages = [ctx hasSession]
357     ? [[ctx session] languages]
358     : [[ctx request] browserLanguages];
359     
360   /* find resource manager */
361     
362   if ((rm = [self resourceManager]) == nil)
363     rm = [[WOApplication application] resourceManager];
364   if (rm == nil)
365     [self warnWithFormat:@"missing resource manager!"];
366     
367   /* get parameters */
368     
369   r = [_str rangeOfString:@"/"];
370   if (r.length > 0) {
371     lTable = [_str substringToIndex:r.location];
372     lKey   = [_str substringFromIndex:(r.location + r.length)];
373   }
374   else {
375     lTable = nil;
376     lKey   = _str;
377   }
378   lVal = lKey;
379
380   if ([lKey hasPrefix:@"$"])
381     lKey = [self valueForKeyPath:[lKey substringFromIndex:1]];
382   
383   if ([lTable hasPrefix:@"$"])
384     lTable = [self valueForKeyPath:[lTable substringFromIndex:1]];
385   
386 #if 0
387   if ([lVal hasPrefix:@"$"])
388     lVal = [self valueForKeyPath:[lVal substringFromIndex:1]];
389   
390 #endif
391   
392   /* lookup string */
393   
394   label = [rm stringForKey:lKey inTableNamed:lTable withDefaultValue:lVal
395               languages:languages];
396   return label;
397 }
398
399 - (NSString *)localizedNameForDayOfWeek:(unsigned)_dayOfWeek {
400   NSString *key =  [dayLabelKeys objectAtIndex:_dayOfWeek % 7];
401   return [self labelForKey:key];
402 }
403
404 - (NSString *)localizedAbbreviatedNameForDayOfWeek:(unsigned)_dayOfWeek {
405   NSString *key =  [abbrDayLabelKeys objectAtIndex:_dayOfWeek % 7];
406   return [self labelForKey:key];
407 }
408
409 - (NSString *)localizedNameForMonthOfYear:(unsigned)_monthOfYear {
410   NSString *key =  [monthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
411   return [self labelForKey:key];
412 }
413
414 - (NSString *)localizedAbbreviatedNameForMonthOfYear:(unsigned)_monthOfYear {
415   NSString *key =  [abbrMonthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
416   return [self labelForKey:key];
417 }
418
419 /* HTTP method safety */
420
421 - (BOOL)isInvokedBySafeMethod {
422   // TODO: move to WORequest?
423   NSString *m;
424   
425   m = [[[self context] request] method];
426   if ([m isEqualToString:@"GET"])  return YES;
427   if ([m isEqualToString:@"HEAD"]) return YES;
428   return NO;
429 }
430
431 /* locale */
432
433 - (NSDictionary *)locale {
434   /* we need no fallback here, as locale is guaranteed to be set by sogod */
435   return [[self context] valueForKey:@"locale"];
436 }
437
438 /* Access is in several ways restricted if request is not coming from the
439  * Intranet
440  */
441
442 - (BOOL)isAccessRestricted {
443   NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
444   
445   return [ud boolForKey:@"SOGoAccessIsRestricted"];
446 }
447
448 /* debugging */
449
450 - (BOOL)isUIxDebugEnabled {
451   return uixDebugEnabled;
452 }
453
454 @end /* UIxComponent */