]> err.no Git - scalable-opengroupware.org/blob - SOGo/UI/SOGoUI/UIxComponent.m
246ccc22fe978449b12b7317246e3c8ff00388ca
[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   // TODO: this code is weird, should use WORequest methods for parsing
149   WORequest *req;
150   NSString  *uri;
151   NSRange   r;
152   
153   if (self->queryParameters)
154     return self->queryParameters;
155
156   self->queryParameters = [[NSMutableDictionary alloc] initWithCapacity:8];
157     
158   req = [[self context] request];
159   uri = [req uri];
160   r   = [uri rangeOfString:@"?" options:NSBackwardsSearch];
161   if (r.length > 0) {
162     NSString *qs;
163     
164     qs = [uri substringFromIndex:NSMaxRange(r)];
165     [self _parseQueryString:qs];
166   }    
167   return self->queryParameters;
168 }
169
170 - (NSDictionary *)queryParameters {
171   return [self _queryParameters];
172 }
173
174 - (NSDictionary *)queryParametersBySettingSelectedDate:(NSCalendarDate *)_date{
175   NSMutableDictionary *qp;
176     
177   qp = [[self queryParameters] mutableCopy];
178   [self setSelectedDateQueryParameter:_date inDictionary:qp];
179   return [qp autorelease];
180 }
181
182 - (void)setSelectedDateQueryParameter:(NSCalendarDate *)_newDate
183   inDictionary:(NSMutableDictionary *)_qp;
184 {
185   if(_newDate != nil)
186     [_qp setObject:[self dateStringForDate:_newDate] forKey:@"day"];
187   else
188     [_qp removeObjectForKey:@"day"];
189 }
190
191 - (NSString *)completeHrefForMethod:(NSString *)_method {
192   WOContext    *ctx;
193   NSDictionary *qp;
194   NSString     *qs, *qps;
195
196   qp = [self queryParameters];
197   if([qp count] == 0)
198     return _method;
199
200   ctx = [self context];
201   qps = [ctx queryPathSeparator];
202   [ctx setQueryPathSeparator:@"&"];
203   qs = [ctx queryStringFromDictionary:qp];
204   [ctx setQueryPathSeparator:qps];
205   return [_method stringByAppendingFormat:@"?%@", qs];
206 }
207
208 - (NSString *)ownMethodName {
209   NSString *uri;
210   NSRange  r;
211     
212   uri = [[[self context] request] uri];
213     
214   /* first: cut off query parameters */
215     
216   r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
217   if (r.length > 0)
218     uri = [uri substringToIndex:r.location];
219     
220   /* next: strip trailing slash */
221     
222   if ([uri hasSuffix:@"/"]) uri = [uri substringToIndex:([uri length] - 1)];
223   r = [uri rangeOfString:@"/" options:NSBackwardsSearch];
224     
225   /* then: cut of last path component */
226     
227   if (r.length == 0) // no slash? are we at root?
228     return @"/";
229     
230   return [uri substringFromIndex:(r.location + 1)];
231 }
232
233 - (NSString *)userFolderPath {
234   WOContext *ctx;
235   NSArray   *traversalObjects;
236   NSString  *url;
237   
238   ctx = [self context];
239   traversalObjects = [ctx objectTraversalStack];
240   url = [[traversalObjects objectAtIndex:1]
241                            baseURLInContext:ctx];
242   return [[NSURL URLWithString:url] path];
243 }
244
245 - (NSString *)ownPath {
246   NSString *uri;
247   NSRange  r;
248   
249   uri = [[[self context] request] uri];
250   
251   /* first: cut off query parameters */
252   
253   r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
254   if (r.length > 0)
255     uri = [uri substringToIndex:r.location];
256   return uri;
257 }
258
259 - (NSString *)relativePathToUserFolderSubPath:(NSString *)_sub {
260   NSString *dst, *rel;
261
262   dst = [[self userFolderPath] stringByAppendingPathComponent:_sub];
263   rel = [dst urlPathRelativeToPath:[self ownPath]];
264   return rel;
265 }
266   
267 /* date */
268
269 - (NSTimeZone *)viewTimeZone {
270   // Note: also in the folder, should be based on a cookie?
271   return MET;
272 }
273
274 - (NSTimeZone *)backendTimeZone {
275   return GMT;
276 }
277
278 - (NSCalendarDate *)selectedDate {
279   NSString       *s;
280   NSCalendarDate *cdate;
281
282   s = [self queryParameterForKey:@"day"];
283   cdate = ([s length] > 0)
284     ? [self dateForDateString:s]
285     : [NSCalendarDate date];
286   [cdate setTimeZone:[self viewTimeZone]];
287   s = [self queryParameterForKey:@"hm"];
288   if([s length] == 4) {
289     unsigned hour, minute;
290       
291     hour = [[s substringToIndex:2] unsignedIntValue];
292     minute = [[s substringFromIndex:2] unsignedIntValue];
293     cdate = [cdate hour:hour minute:minute];
294   }
295   else {
296     cdate = [cdate hour:12 minute:0];
297   }
298   return cdate;
299 }
300
301 - (NSString *)dateStringForDate:(NSCalendarDate *)_date {
302   [_date setTimeZone:[self viewTimeZone]];
303   return [_date descriptionWithCalendarFormat:@"%Y%m%d"];
304 }
305
306 - (NSCalendarDate *)dateForDateString:(NSString *)_dateString {
307   return [NSCalendarDate dateWithString:_dateString 
308                          calendarFormat:@"%Y%m%d"];
309 }
310
311
312 /* SoUser */
313
314 - (SoUser *)user {
315   WOContext *ctx;
316   
317   ctx = [self context];
318   return [[[self clientObject] authenticatorInContext:ctx] userInContext:ctx];
319 }
320
321 - (NSString *)shortUserNameForDisplay {
322   // TODO: better use a SoUser formatter?
323   // TODO: who calls that?
324   NSString *s;
325   NSRange  r;
326   
327   // TODO: USE USER MANAGER INSTEAD!
328   
329   s = [[self user] login];
330   if ([s length] < 10)
331     return s;
332     
333   // TODO: algorithm might be inappropriate, depends on the actual UID
334     
335   r = [s rangeOfString:@"."];
336   if (r.length == 0)
337     return s;
338     
339   return [s substringToIndex:r.location];
340 }
341
342 /* labels */
343
344 - (NSString *)labelForKey:(NSString *)_str {
345   WOResourceManager *rm;
346   NSArray           *languages;
347   WOContext         *ctx;
348   NSString          *label;
349   NSString          *lKey, *lTable, *lVal;
350   NSRange r;
351
352   if ([_str length] == 0)
353     return nil;
354   
355   /* lookup languages */
356     
357   ctx = [self context];
358   languages = [ctx hasSession]
359     ? [[ctx session] languages]
360     : [[ctx request] browserLanguages];
361     
362   /* find resource manager */
363     
364   if ((rm = [self resourceManager]) == nil)
365     rm = [[WOApplication application] resourceManager];
366   if (rm == nil)
367     [self warnWithFormat:@"missing resource manager!"];
368     
369   /* get parameters */
370     
371   r = [_str rangeOfString:@"/"];
372   if (r.length > 0) {
373     lTable = [_str substringToIndex:r.location];
374     lKey   = [_str substringFromIndex:(r.location + r.length)];
375   }
376   else {
377     lTable = nil;
378     lKey   = _str;
379   }
380   lVal = lKey;
381
382   if ([lKey hasPrefix:@"$"])
383     lKey = [self valueForKeyPath:[lKey substringFromIndex:1]];
384   
385   if ([lTable hasPrefix:@"$"])
386     lTable = [self valueForKeyPath:[lTable substringFromIndex:1]];
387   
388 #if 0
389   if ([lVal hasPrefix:@"$"])
390     lVal = [self valueForKeyPath:[lVal substringFromIndex:1]];
391   
392 #endif
393   
394   /* lookup string */
395   
396   label = [rm stringForKey:lKey inTableNamed:lTable withDefaultValue:lVal
397               languages:languages];
398   return label;
399 }
400
401 - (NSString *)localizedNameForDayOfWeek:(unsigned)_dayOfWeek {
402   NSString *key =  [dayLabelKeys objectAtIndex:_dayOfWeek % 7];
403   return [self labelForKey:key];
404 }
405
406 - (NSString *)localizedAbbreviatedNameForDayOfWeek:(unsigned)_dayOfWeek {
407   NSString *key =  [abbrDayLabelKeys objectAtIndex:_dayOfWeek % 7];
408   return [self labelForKey:key];
409 }
410
411 - (NSString *)localizedNameForMonthOfYear:(unsigned)_monthOfYear {
412   NSString *key =  [monthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
413   return [self labelForKey:key];
414 }
415
416 - (NSString *)localizedAbbreviatedNameForMonthOfYear:(unsigned)_monthOfYear {
417   NSString *key =  [abbrMonthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
418   return [self labelForKey:key];
419 }
420
421 /* HTTP method safety */
422
423 - (BOOL)isInvokedBySafeMethod {
424   // TODO: move to WORequest?
425   NSString *m;
426   
427   m = [[[self context] request] method];
428   if ([m isEqualToString:@"GET"])  return YES;
429   if ([m isEqualToString:@"HEAD"]) return YES;
430   return NO;
431 }
432
433 /* locale */
434
435 - (NSDictionary *)locale {
436   /* we need no fallback here, as locale is guaranteed to be set by sogod */
437   return [[self context] valueForKey:@"locale"];
438 }
439
440 /* debugging */
441
442 - (BOOL)isUIxDebugEnabled {
443   return uixDebugEnabled;
444 }
445
446 @end /* UIxComponent */