]> err.no Git - scalable-opengroupware.org/blob - UI/SOGoUI/UIxComponent.m
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1212 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / 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 #import <Foundation/NSDictionary.h>
23 #import <Foundation/NSException.h>
24 #import <Foundation/NSUserDefaults.h>
25 #import <Foundation/NSKeyValueCoding.h>
26 #import <Foundation/NSPathUtilities.h>
27 #import <NGObjWeb/SoHTTPAuthenticator.h>
28 #import <NGObjWeb/SoObjects.h>
29 #import <NGObjWeb/WOResourceManager.h>
30 #import <NGObjWeb/WORequest.h>
31 #import <NGObjWeb/WOContext+SoObjects.h>
32 #import <NGExtensions/NSObject+Logs.h>
33 #import <NGExtensions/NSString+misc.h>
34 #import <NGExtensions/NSURL+misc.h>
35 #import <SoObjects/SOGo/SOGoUser.h>
36 #import <SoObjects/SOGo/SOGoObject.h>
37 #import <SoObjects/SOGo/SOGoCustomGroupFolder.h>
38 #import <SoObjects/SOGo/NSCalendarDate+SOGo.h>
39 #import <SoObjects/SOGo/NSString+Utilities.h>
40
41 #import "UIxComponent.h"
42 #import "UIxJSClose.h"
43
44 @interface UIxComponent (PrivateAPI)
45 - (void)_parseQueryString:(NSString *)_s;
46 - (NSMutableDictionary *)_queryParameters;
47 @end
48
49 @implementation UIxComponent
50
51 static NSMutableArray *dayLabelKeys       = nil;
52 static NSMutableArray *abbrDayLabelKeys   = nil;
53 static NSMutableArray *monthLabelKeys     = nil;
54 static NSMutableArray *abbrMonthLabelKeys = nil;
55
56 static BOOL uixDebugEnabled = NO;
57
58 + (int)version {
59   return [super version] + 0 /* v2 */;
60 }
61
62 + (void)initialize {
63   NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
64
65   NSAssert2([super version] == 2,
66             @"invalid superclass (%@) version %i !",
67             NSStringFromClass([self superclass]), [super version]);
68   
69   uixDebugEnabled = [ud boolForKey:@"SOGoUIxDebugEnabled"];
70
71   if (dayLabelKeys == nil) {
72     dayLabelKeys = [[NSMutableArray alloc] initWithCapacity:7];
73     [dayLabelKeys addObject:@"Sunday"];
74     [dayLabelKeys addObject:@"Monday"];
75     [dayLabelKeys addObject:@"Tuesday"];
76     [dayLabelKeys addObject:@"Wednesday"];
77     [dayLabelKeys addObject:@"Thursday"];
78     [dayLabelKeys addObject:@"Friday"];
79     [dayLabelKeys addObject:@"Saturday"];
80
81     abbrDayLabelKeys = [[NSMutableArray alloc] initWithCapacity:7];
82     [abbrDayLabelKeys addObject:@"a2_Sunday"];
83     [abbrDayLabelKeys addObject:@"a2_Monday"];
84     [abbrDayLabelKeys addObject:@"a2_Tuesday"];
85     [abbrDayLabelKeys addObject:@"a2_Wednesday"];
86     [abbrDayLabelKeys addObject:@"a2_Thursday"];
87     [abbrDayLabelKeys addObject:@"a2_Friday"];
88     [abbrDayLabelKeys addObject:@"a2_Saturday"];
89
90     monthLabelKeys = [[NSMutableArray alloc] initWithCapacity:12];
91     [monthLabelKeys addObject:@"January"];
92     [monthLabelKeys addObject:@"February"];
93     [monthLabelKeys addObject:@"March"];
94     [monthLabelKeys addObject:@"April"];
95     [monthLabelKeys addObject:@"May"];
96     [monthLabelKeys addObject:@"June"];
97     [monthLabelKeys addObject:@"July"];
98     [monthLabelKeys addObject:@"August"];
99     [monthLabelKeys addObject:@"September"];
100     [monthLabelKeys addObject:@"October"];
101     [monthLabelKeys addObject:@"November"];
102     [monthLabelKeys addObject:@"December"];
103
104     abbrMonthLabelKeys = [[NSMutableArray alloc] initWithCapacity:12];
105     [abbrMonthLabelKeys addObject:@"a3_January"];
106     [abbrMonthLabelKeys addObject:@"a3_February"];
107     [abbrMonthLabelKeys addObject:@"a3_March"];
108     [abbrMonthLabelKeys addObject:@"a3_April"];
109     [abbrMonthLabelKeys addObject:@"a3_May"];
110     [abbrMonthLabelKeys addObject:@"a3_June"];
111     [abbrMonthLabelKeys addObject:@"a3_July"];
112     [abbrMonthLabelKeys addObject:@"a3_August"];
113     [abbrMonthLabelKeys addObject:@"a3_September"];
114     [abbrMonthLabelKeys addObject:@"a3_October"];
115     [abbrMonthLabelKeys addObject:@"a3_November"];
116     [abbrMonthLabelKeys addObject:@"a3_December"];
117   }
118 }
119
120 - (id) init
121 {
122   if ((self = [super init]))
123     {
124       _selectedDate = nil;
125     }
126
127   return self;
128 }
129
130 - (void) dealloc
131 {
132   [queryParameters release];
133   [_selectedDate release];
134   [super dealloc];
135 }
136
137 /* query parameters */
138
139 - (void) _parseQueryString: (NSString *) _s
140 {
141   NSEnumerator *e;
142   NSString *part;
143   NSRange  r;
144   NSString *key, *value;
145
146   e = [[_s componentsSeparatedByString:@"&"] objectEnumerator];
147   part = [e nextObject];
148   while (part)
149     {
150       r = [part rangeOfString:@"="];
151       if (r.length == 0)
152         {
153       /* missing value of query parameter */
154           key   = [part stringByUnescapingURL];
155           value = @"1";
156         }
157       else
158         {
159           key   = [[part substringToIndex:r.location] stringByUnescapingURL];
160           value = [[part substringFromIndex:(r.location + r.length)] 
161                     stringByUnescapingURL];
162         }
163       [queryParameters setObject:value forKey:key];
164       part = [e nextObject];
165     }
166 }
167
168 - (void) addKeepAliveFormValuesToQueryParameters
169 {
170 }
171
172 - (NSString *) queryParameterForKey: (NSString *) _key
173 {
174   return [[self _queryParameters] objectForKey:_key];
175 }
176
177 - (void) setQueryParameter: (NSString *) _param
178                     forKey: (NSString *) _key
179 {
180   if (_key)
181     {
182       if (_param)
183         [[self _queryParameters] setObject: _param forKey: _key];
184       else
185         [[self _queryParameters] removeObjectForKey: _key];
186     }
187 }
188
189 - (NSMutableDictionary *) _queryParameters
190 {
191   // TODO: this code is weird, should use WORequest methods for parsing
192   WORequest *req;
193   NSString  *uri;
194   NSRange   r;
195   NSString *qs;
196   
197   if (queryParameters)
198     return queryParameters;
199
200   queryParameters = [[NSMutableDictionary alloc] initWithCapacity:8];
201
202   req = [context request];
203   uri = [req uri];
204   r   = [uri rangeOfString:@"?" options:NSBackwardsSearch];
205   if (r.length > 0)
206     {
207       qs = [uri substringFromIndex:NSMaxRange(r)];
208       [self _parseQueryString:qs];
209     }
210   
211   /* add form values */
212   [self addKeepAliveFormValuesToQueryParameters];
213
214   return queryParameters;
215 }
216
217 - (NSDictionary *) queryParameters
218 {
219   return [self _queryParameters];
220 }
221
222 - (NSDictionary *) queryParametersBySettingSelectedDate: (NSCalendarDate *) _date
223 {
224   NSMutableDictionary *qp;
225     
226   qp = [[self queryParameters] mutableCopy];
227   [self setSelectedDateQueryParameter:_date inDictionary:qp];
228   return [qp autorelease];
229 }
230
231 - (void) setSelectedDateQueryParameter: (NSCalendarDate *) _newDate
232                           inDictionary: (NSMutableDictionary *) _qp
233 {
234   if (_newDate)
235     [_qp setObject: [self dateStringForDate: _newDate] forKey: @"day"];
236   else
237     [_qp removeObjectForKey:@"day"];
238 }
239
240 - (NSString *) completeHrefForMethod: (NSString *) _method
241 {
242   WOContext *ctx;
243   NSDictionary *qp;
244   NSString *qs, *qps, *href;
245
246   qp = [self queryParameters];
247   if ([qp count] > 0)
248     {
249       ctx = context;
250       qps = [ctx queryPathSeparator];
251       [ctx setQueryPathSeparator: @"&"];
252       qs = [ctx queryStringFromDictionary: qp];
253       [ctx setQueryPathSeparator: qps];
254       href = [_method stringByAppendingFormat:@"?%@", qs];
255     }
256   else
257     href = _method;
258
259   return href;
260 }
261
262 - (NSString *) ownMethodName
263 {
264   NSString *uri;
265   NSRange  r;
266     
267   uri = [[context request] uri];
268     
269   /* first: cut off query parameters */
270     
271   r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
272   if (r.length > 0)
273     uri = [uri substringToIndex:r.location];
274     
275   /* next: strip trailing slash */
276
277   if ([uri hasSuffix: @"/"])
278     uri = [uri substringToIndex: ([uri length] - 1)];
279   r = [uri rangeOfString:@"/" options: NSBackwardsSearch];
280     
281   /* then: cut of last path component */
282     
283   if (r.length == 0) // no slash? are we at root?
284     return @"/";
285     
286   return [uri substringFromIndex: (r.location + 1)];
287 }
288
289 - (NSString *) userFolderPath
290 {
291   WOContext *ctx;
292   NSEnumerator *objects;
293   SOGoObject *currentObject;
294   BOOL found;
295
296   ctx = context;
297   objects = [[ctx objectTraversalStack] objectEnumerator];
298   currentObject = [objects nextObject];
299   found = NO;
300   while (currentObject
301          && !found)
302     if ([currentObject isKindOfClass: [SOGoUserFolder class]])
303       found = YES;
304     else
305       currentObject = [objects nextObject];
306
307   return [[currentObject baseURLInContext:ctx] hostlessURL];
308 }
309
310 - (NSString *) applicationPath
311 {
312   SOGoObject *currentClient, *parent;
313   BOOL found;
314   Class objectClass, groupFolderClass, userFolderClass;
315
316   currentClient = [self clientObject];
317   if (currentClient
318       && [currentClient isKindOfClass: [SOGoObject class]])
319     {
320       groupFolderClass = [SOGoCustomGroupFolder class];
321       userFolderClass = [SOGoUserFolder class];
322
323       objectClass = [currentClient class];
324       found = (objectClass == groupFolderClass || objectClass == userFolderClass);
325       while (!found && currentClient)
326         {
327           parent = [currentClient container];
328           objectClass = [parent class];
329           if (objectClass == groupFolderClass
330               || objectClass == userFolderClass)
331             found = YES;
332           else
333             currentClient = parent;
334         }
335     }
336   else
337     currentClient = [WOApplication application];
338
339   return [[currentClient baseURLInContext: context] hostlessURL];
340 }
341
342 - (NSString *) resourcesPath
343 {
344   WOResourceManager *rm;
345
346   if ((rm = [self resourceManager]) == nil)
347     rm = [[WOApplication application] resourceManager];
348
349   return [rm webServerResourcesPath];
350 }
351
352 - (NSString *) ownPath
353 {
354   NSString *uri;
355   NSRange  r;
356   
357   uri = [[context request] uri];
358   
359   /* first: cut off query parameters */
360   
361   r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
362   if (r.length > 0)
363     uri = [uri substringToIndex:r.location];
364
365   return uri;
366 }
367
368 - (NSString *) relativePathToUserFolderSubPath: (NSString *) _sub
369 {
370   NSString *dst, *rel;
371
372   dst = [[self userFolderPath] stringByAppendingPathComponent: _sub];
373   rel = [dst urlPathRelativeToPath:[self ownPath]];
374
375   return rel;
376 }
377
378 - (NSCalendarDate *) selectedDate
379 {
380   NSTimeZone *userTimeZone;
381
382   if (!_selectedDate)
383     {
384       userTimeZone = [[context activeUser] timeZone];
385       _selectedDate
386         = [NSCalendarDate
387             dateFromShortDateString: [self queryParameterForKey: @"day"]
388             andShortTimeString: [self queryParameterForKey: @"hm"]
389             inTimeZone: userTimeZone];
390       [_selectedDate retain];
391     }
392
393   return _selectedDate;
394 }
395
396 - (NSString *) dateStringForDate: (NSCalendarDate *) _date
397 {
398   NSTimeZone *userTimeZone;
399
400   userTimeZone = [[context activeUser] timeZone];
401   [_date setTimeZone: userTimeZone];
402
403   return [_date descriptionWithCalendarFormat: @"%Y%m%d"];
404 }
405
406 - (BOOL) hideFrame
407 {
408   return ([[self queryParameterForKey: @"noframe"] boolValue]);
409 }
410
411 - (UIxComponent *) jsCloseWithRefreshMethod: (NSString *) methodName
412 {
413   UIxJSClose *jsClose;
414
415   jsClose = [UIxJSClose new];
416   [jsClose autorelease];
417   [jsClose setRefreshMethod: methodName];
418
419   return jsClose;
420 }
421
422 /* SoUser */
423
424 - (NSString *) shortUserNameForDisplay
425 {
426   if ([context activeUser] == nil)
427     return @"wrongusernamepassword";
428
429   return [[context activeUser] login];
430 }
431
432 /* labels */
433
434 - (NSString *) labelForKey: (NSString *) _str
435 {
436   WOResourceManager *rm;
437   NSArray *languages;
438   NSString *lKey, *lTable, *lVal;
439   NSRange r;
440
441   if ([_str length] == 0)
442     return nil;
443   
444   /* lookup languages */
445     
446   languages = [context resourceLookupLanguages];
447     
448   /* find resource manager */
449     
450   if ((rm = [self pageResourceManager]) == nil)
451     rm = [[WOApplication application] resourceManager];
452   if (rm == nil)
453     [self warnWithFormat:@"missing resource manager!"];
454     
455   /* get parameters */
456     
457   r = [_str rangeOfString:@"/"];
458   if (r.length > 0) {
459     lTable = [_str substringToIndex:r.location];
460     lKey   = [_str substringFromIndex:(r.location + r.length)];
461   }
462   else {
463     lTable = nil;
464     lKey   = _str;
465   }
466   lVal = lKey;
467
468   if ([lKey hasPrefix:@"$"])
469     lKey = [self valueForKeyPath:[lKey substringFromIndex:1]];
470   
471   if ([lTable hasPrefix:@"$"])
472     lTable = [self valueForKeyPath:[lTable substringFromIndex:1]];
473   
474 #if 0
475   if ([lVal hasPrefix:@"$"])
476     lVal = [self valueForKeyPath:[lVal substringFromIndex:1]];
477   
478 #endif
479   
480   /* lookup string */
481   return [rm stringForKey: lKey
482              inTableNamed: lTable
483              withDefaultValue: lVal
484              languages: languages];
485 }
486
487 - (NSString *) localizedNameForDayOfWeek:(unsigned)_dayOfWeek {
488   NSString *key =  [dayLabelKeys objectAtIndex:_dayOfWeek % 7];
489   return [self labelForKey:key];
490 }
491
492 - (NSString *)localizedAbbreviatedNameForDayOfWeek:(unsigned)_dayOfWeek {
493   NSString *key =  [abbrDayLabelKeys objectAtIndex:_dayOfWeek % 7];
494   return [self labelForKey:key];
495 }
496
497 - (NSString *)localizedNameForMonthOfYear:(unsigned)_monthOfYear {
498   NSString *key =  [monthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
499   return [self labelForKey:key];
500 }
501
502 - (NSString *)localizedAbbreviatedNameForMonthOfYear:(unsigned)_monthOfYear {
503   NSString *key =  [abbrMonthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
504   return [self labelForKey:key];
505 }
506
507 /* HTTP method safety */
508
509 - (BOOL)isInvokedBySafeMethod {
510   // TODO: move to WORequest?
511   NSString *m;
512   
513   m = [[context request] method];
514   if ([m isEqualToString:@"GET"])  return YES;
515   if ([m isEqualToString:@"HEAD"]) return YES;
516   return NO;
517 }
518
519 /* locale */
520
521 - (NSDictionary *)locale {
522   /* we need no fallback here, as locale is guaranteed to be set by sogod */
523   return [context valueForKey: @"locale"];
524 }
525
526 - (WOResourceManager *) pageResourceManager
527 {
528   WOResourceManager *rm;
529   
530   if ((rm = [[context page] resourceManager]) == nil)
531     rm = [[WOApplication application] resourceManager];
532
533   return rm;
534 }
535
536 - (NSString *) urlForResourceFilename: (NSString *) filename
537 {
538   static NSMutableDictionary *pageToURL = nil;
539   NSString *url;
540   WOComponent *page;
541   WOResourceManager *rm;
542   NSBundle *pageBundle;
543
544   if (filename)
545     {
546       if (!pageToURL)
547         pageToURL = [[NSMutableDictionary alloc] initWithCapacity: 32];
548
549       url = [pageToURL objectForKey: filename];
550       if (!url)
551         {
552           rm = [self pageResourceManager];
553           page = [context page];
554           pageBundle = [NSBundle bundleForClass: [page class]];
555           url = [rm urlForResourceNamed: filename
556                     inFramework: [pageBundle bundlePath]
557                     languages: nil
558                     request: [context request]];
559           if (!url)
560             url = @"";
561           else
562             if ([url hasPrefix: @"http"])
563               url = [url hostlessURL];
564           [pageToURL setObject: url forKey: filename];
565         }
566
567 //   NSLog (@"url for '%@': '%@'", filename, url);
568     }
569   else
570     url = @"";
571
572   return url;
573 }
574
575 - (WOResponse *) responseWith204
576 {
577   WOResponse *response;
578
579   response = [context response];
580   [response setStatus: 204];
581
582   return response;
583 }
584
585 /* debugging */
586
587 - (BOOL)isUIxDebugEnabled {
588   return uixDebugEnabled;
589 }
590
591 @end /* UIxComponent */