2 Copyright (C) 2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
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
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.
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
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>
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>
38 #import <SoObjects/SOGo/SOGoUser.h>
39 #import <SoObjects/SOGo/SOGoObject.h>
40 #import <SoObjects/SOGo/SOGoCustomGroupFolder.h>
41 #import <SoObjects/SOGo/NSCalendarDate+SOGo.h>
42 #import <SoObjects/SOGo/NSString+Utilities.h>
44 #import "UIxJSClose.h"
46 #import "UIxComponent.h"
48 @interface UIxComponent (PrivateAPI)
49 - (void)_parseQueryString:(NSString *)_s;
50 - (NSMutableDictionary *)_queryParameters;
53 @implementation UIxComponent
55 static NSMutableArray *dayLabelKeys = nil;
56 static NSMutableArray *abbrDayLabelKeys = nil;
57 static NSMutableArray *monthLabelKeys = nil;
58 static NSMutableArray *abbrMonthLabelKeys = nil;
60 static BOOL uixDebugEnabled = NO;
63 return [super version] + 0 /* v2 */;
67 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
69 NSAssert2([super version] == 2,
70 @"invalid superclass (%@) version %i !",
71 NSStringFromClass([self superclass]), [super version]);
73 uixDebugEnabled = [ud boolForKey:@"SOGoUIxDebugEnabled"];
75 if (dayLabelKeys == nil) {
76 dayLabelKeys = [[NSMutableArray alloc] initWithCapacity:7];
77 [dayLabelKeys addObject:@"Sunday"];
78 [dayLabelKeys addObject:@"Monday"];
79 [dayLabelKeys addObject:@"Tuesday"];
80 [dayLabelKeys addObject:@"Wednesday"];
81 [dayLabelKeys addObject:@"Thursday"];
82 [dayLabelKeys addObject:@"Friday"];
83 [dayLabelKeys addObject:@"Saturday"];
85 abbrDayLabelKeys = [[NSMutableArray alloc] initWithCapacity:7];
86 [abbrDayLabelKeys addObject:@"a2_Sunday"];
87 [abbrDayLabelKeys addObject:@"a2_Monday"];
88 [abbrDayLabelKeys addObject:@"a2_Tuesday"];
89 [abbrDayLabelKeys addObject:@"a2_Wednesday"];
90 [abbrDayLabelKeys addObject:@"a2_Thursday"];
91 [abbrDayLabelKeys addObject:@"a2_Friday"];
92 [abbrDayLabelKeys addObject:@"a2_Saturday"];
94 monthLabelKeys = [[NSMutableArray alloc] initWithCapacity:12];
95 [monthLabelKeys addObject:@"January"];
96 [monthLabelKeys addObject:@"February"];
97 [monthLabelKeys addObject:@"March"];
98 [monthLabelKeys addObject:@"April"];
99 [monthLabelKeys addObject:@"May"];
100 [monthLabelKeys addObject:@"June"];
101 [monthLabelKeys addObject:@"July"];
102 [monthLabelKeys addObject:@"August"];
103 [monthLabelKeys addObject:@"September"];
104 [monthLabelKeys addObject:@"October"];
105 [monthLabelKeys addObject:@"November"];
106 [monthLabelKeys addObject:@"December"];
108 abbrMonthLabelKeys = [[NSMutableArray alloc] initWithCapacity:12];
109 [abbrMonthLabelKeys addObject:@"a3_January"];
110 [abbrMonthLabelKeys addObject:@"a3_February"];
111 [abbrMonthLabelKeys addObject:@"a3_March"];
112 [abbrMonthLabelKeys addObject:@"a3_April"];
113 [abbrMonthLabelKeys addObject:@"a3_May"];
114 [abbrMonthLabelKeys addObject:@"a3_June"];
115 [abbrMonthLabelKeys addObject:@"a3_July"];
116 [abbrMonthLabelKeys addObject:@"a3_August"];
117 [abbrMonthLabelKeys addObject:@"a3_September"];
118 [abbrMonthLabelKeys addObject:@"a3_October"];
119 [abbrMonthLabelKeys addObject:@"a3_November"];
120 [abbrMonthLabelKeys addObject:@"a3_December"];
126 if ((self = [super init]))
136 [queryParameters release];
137 [_selectedDate release];
141 /* query parameters */
143 - (void) _parseQueryString: (NSString *) _s
148 NSString *key, *value;
150 e = [[_s componentsSeparatedByString:@"&"] objectEnumerator];
151 part = [e nextObject];
154 r = [part rangeOfString:@"="];
157 /* missing value of query parameter */
158 key = [part stringByUnescapingURL];
163 key = [[part substringToIndex:r.location] stringByUnescapingURL];
164 value = [[part substringFromIndex:(r.location + r.length)]
165 stringByUnescapingURL];
167 [queryParameters setObject:value forKey:key];
168 part = [e nextObject];
172 - (void) addKeepAliveFormValuesToQueryParameters
176 - (NSString *) queryParameterForKey: (NSString *) _key
178 return [[self _queryParameters] objectForKey:_key];
181 - (void) setQueryParameter: (NSString *) _param
182 forKey: (NSString *) _key
187 [[self _queryParameters] setObject: _param forKey: _key];
189 [[self _queryParameters] removeObjectForKey: _key];
193 - (NSMutableDictionary *) _queryParameters
195 // TODO: this code is weird, should use WORequest methods for parsing
202 return queryParameters;
204 queryParameters = [[NSMutableDictionary alloc] initWithCapacity:8];
206 req = [context request];
208 r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
211 qs = [uri substringFromIndex:NSMaxRange(r)];
212 [self _parseQueryString:qs];
215 /* add form values */
216 [self addKeepAliveFormValuesToQueryParameters];
218 return queryParameters;
221 - (NSDictionary *) queryParameters
223 return [self _queryParameters];
226 - (NSDictionary *) queryParametersBySettingSelectedDate: (NSCalendarDate *) _date
228 NSMutableDictionary *qp;
230 qp = [[self queryParameters] mutableCopy];
231 [self setSelectedDateQueryParameter:_date inDictionary:qp];
232 return [qp autorelease];
235 - (void) setSelectedDateQueryParameter: (NSCalendarDate *) _newDate
236 inDictionary: (NSMutableDictionary *) _qp
239 [_qp setObject: [self dateStringForDate: _newDate] forKey: @"day"];
241 [_qp removeObjectForKey:@"day"];
244 - (NSString *) completeHrefForMethod: (NSString *) _method
248 NSString *qs, *qps, *href;
250 qp = [self queryParameters];
254 qps = [ctx queryPathSeparator];
255 [ctx setQueryPathSeparator: @"&"];
256 qs = [ctx queryStringFromDictionary: qp];
257 [ctx setQueryPathSeparator: qps];
258 href = [_method stringByAppendingFormat:@"?%@", qs];
266 - (NSString *) ownMethodName
271 uri = [[context request] uri];
273 /* first: cut off query parameters */
275 r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
277 uri = [uri substringToIndex:r.location];
279 /* next: strip trailing slash */
281 if ([uri hasSuffix: @"/"])
282 uri = [uri substringToIndex: ([uri length] - 1)];
283 r = [uri rangeOfString:@"/" options: NSBackwardsSearch];
285 /* then: cut of last path component */
287 if (r.length == 0) // no slash? are we at root?
290 return [uri substringFromIndex: (r.location + 1)];
293 - (NSString *) userFolderPath
296 NSEnumerator *objects;
297 SOGoObject *currentObject;
301 objects = [[ctx objectTraversalStack] objectEnumerator];
302 currentObject = [objects nextObject];
306 if ([currentObject isKindOfClass: [SOGoUserFolder class]])
309 currentObject = [objects nextObject];
311 return [[currentObject baseURLInContext:ctx] hostlessURL];
314 - (NSString *) applicationPath
316 SOGoObject *currentClient, *parent;
318 Class objectClass, groupFolderClass, userFolderClass;
320 currentClient = [self clientObject];
322 && [currentClient isKindOfClass: [SOGoObject class]])
324 groupFolderClass = [SOGoCustomGroupFolder class];
325 userFolderClass = [SOGoUserFolder class];
327 objectClass = [currentClient class];
328 found = (objectClass == groupFolderClass || objectClass == userFolderClass);
329 while (!found && currentClient)
331 parent = [currentClient container];
332 objectClass = [parent class];
333 if (objectClass == groupFolderClass
334 || objectClass == userFolderClass)
337 currentClient = parent;
341 currentClient = [WOApplication application];
343 return [[currentClient baseURLInContext: context] hostlessURL];
346 - (NSString *) resourcesPath
348 WOResourceManager *rm;
350 if ((rm = [self resourceManager]) == nil)
351 rm = [[WOApplication application] resourceManager];
353 return [rm webServerResourcesPath];
356 - (NSString *) ownPath
361 uri = [[context request] uri];
363 /* first: cut off query parameters */
365 r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
367 uri = [uri substringToIndex:r.location];
372 - (NSString *) relativePathToUserFolderSubPath: (NSString *) _sub
376 dst = [[self userFolderPath] stringByAppendingPathComponent: _sub];
377 rel = [dst urlPathRelativeToPath:[self ownPath]];
382 - (NSCalendarDate *) selectedDate
384 NSTimeZone *userTimeZone;
388 userTimeZone = [[context activeUser] timeZone];
391 dateFromShortDateString: [self queryParameterForKey: @"day"]
392 andShortTimeString: [self queryParameterForKey: @"hm"]
393 inTimeZone: userTimeZone];
394 [_selectedDate retain];
397 return _selectedDate;
400 - (NSString *) dateStringForDate: (NSCalendarDate *) _date
402 NSTimeZone *userTimeZone;
404 userTimeZone = [[context activeUser] timeZone];
405 [_date setTimeZone: userTimeZone];
407 return [_date descriptionWithCalendarFormat: @"%Y%m%d"];
412 return ([[self queryParameterForKey: @"noframe"] boolValue]);
415 - (UIxComponent *) jsCloseWithRefreshMethod: (NSString *) methodName
419 jsClose = [UIxJSClose new];
420 [jsClose autorelease];
421 [jsClose setRefreshMethod: methodName];
428 - (NSString *) shortUserNameForDisplay
430 if ([context activeUser] == nil)
431 return @"wrongusernamepassword";
433 return [[context activeUser] login];
438 - (NSString *) labelForKey: (NSString *) _str
440 WOResourceManager *rm;
442 NSString *lKey, *lTable, *lVal;
445 if ([_str length] == 0)
448 /* lookup languages */
450 languages = [context resourceLookupLanguages];
452 /* find resource manager */
454 if ((rm = [self pageResourceManager]) == nil)
455 rm = [[WOApplication application] resourceManager];
457 [self warnWithFormat:@"missing resource manager!"];
461 r = [_str rangeOfString:@"/"];
463 lTable = [_str substringToIndex:r.location];
464 lKey = [_str substringFromIndex:(r.location + r.length)];
472 if ([lKey hasPrefix:@"$"])
473 lKey = [self valueForKeyPath:[lKey substringFromIndex:1]];
475 if ([lTable hasPrefix:@"$"])
476 lTable = [self valueForKeyPath:[lTable substringFromIndex:1]];
479 if ([lVal hasPrefix:@"$"])
480 lVal = [self valueForKeyPath:[lVal substringFromIndex:1]];
485 return [rm stringForKey: lKey
487 withDefaultValue: lVal
488 languages: languages];
491 - (NSString *) localizedNameForDayOfWeek:(unsigned)_dayOfWeek {
492 NSString *key = [dayLabelKeys objectAtIndex:_dayOfWeek % 7];
493 return [self labelForKey:key];
496 - (NSString *)localizedAbbreviatedNameForDayOfWeek:(unsigned)_dayOfWeek {
497 NSString *key = [abbrDayLabelKeys objectAtIndex:_dayOfWeek % 7];
498 return [self labelForKey:key];
501 - (NSString *)localizedNameForMonthOfYear:(unsigned)_monthOfYear {
502 NSString *key = [monthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
503 return [self labelForKey:key];
506 - (NSString *)localizedAbbreviatedNameForMonthOfYear:(unsigned)_monthOfYear {
507 NSString *key = [abbrMonthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
508 return [self labelForKey:key];
511 /* HTTP method safety */
513 - (BOOL)isInvokedBySafeMethod {
514 // TODO: move to WORequest?
517 m = [[context request] method];
518 if ([m isEqualToString:@"GET"]) return YES;
519 if ([m isEqualToString:@"HEAD"]) return YES;
525 - (NSDictionary *)locale {
526 /* we need no fallback here, as locale is guaranteed to be set by sogod */
527 return [context valueForKey: @"locale"];
530 - (WOResourceManager *) pageResourceManager
532 WOResourceManager *rm;
534 if ((rm = [[context page] resourceManager]) == nil)
535 rm = [[WOApplication application] resourceManager];
540 - (NSString *) urlForResourceFilename: (NSString *) filename
542 static NSMutableDictionary *pageToURL = nil;
545 WOResourceManager *rm;
546 NSBundle *pageBundle;
551 pageToURL = [[NSMutableDictionary alloc] initWithCapacity: 32];
553 url = [pageToURL objectForKey: filename];
556 rm = [self pageResourceManager];
557 page = [context page];
558 pageBundle = [NSBundle bundleForClass: [page class]];
559 url = [rm urlForResourceNamed: filename
560 inFramework: [pageBundle bundlePath]
562 request: [context request]];
566 if ([url hasPrefix: @"http"])
567 url = [url hostlessURL];
568 [pageToURL setObject: url forKey: filename];
571 // NSLog (@"url for '%@': '%@'", filename, url);
579 - (WOResponse *) responseWith204
581 WOResponse *response;
583 response = [context response];
584 [response setStatus: 204];
591 - (BOOL)isUIxDebugEnabled {
592 return uixDebugEnabled;
595 @end /* UIxComponent */