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