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>
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>
41 #import "UIxComponent.h"
42 #import "UIxJSClose.h"
44 @interface UIxComponent (PrivateAPI)
45 - (void)_parseQueryString:(NSString *)_s;
46 - (NSMutableDictionary *)_queryParameters;
49 @implementation UIxComponent
51 static NSMutableArray *dayLabelKeys = nil;
52 static NSMutableArray *abbrDayLabelKeys = nil;
53 static NSMutableArray *monthLabelKeys = nil;
54 static NSMutableArray *abbrMonthLabelKeys = nil;
56 static BOOL uixDebugEnabled = NO;
59 return [super version] + 0 /* v2 */;
63 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
65 NSAssert2([super version] == 2,
66 @"invalid superclass (%@) version %i !",
67 NSStringFromClass([self superclass]), [super version]);
69 uixDebugEnabled = [ud boolForKey:@"SOGoUIxDebugEnabled"];
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"];
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"];
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"];
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"];
122 if ((self = [super init]))
132 [queryParameters release];
133 [_selectedDate release];
137 /* query parameters */
139 - (void) _parseQueryString: (NSString *) _s
144 NSString *key, *value;
146 e = [[_s componentsSeparatedByString:@"&"] objectEnumerator];
147 part = [e nextObject];
150 r = [part rangeOfString:@"="];
153 /* missing value of query parameter */
154 key = [part stringByUnescapingURL];
159 key = [[part substringToIndex:r.location] stringByUnescapingURL];
160 value = [[part substringFromIndex:(r.location + r.length)]
161 stringByUnescapingURL];
163 [queryParameters setObject:value forKey:key];
164 part = [e nextObject];
168 - (void) addKeepAliveFormValuesToQueryParameters
172 - (NSString *) queryParameterForKey: (NSString *) _key
174 return [[self _queryParameters] objectForKey:_key];
177 - (void) setQueryParameter: (NSString *) _param
178 forKey: (NSString *) _key
183 [[self _queryParameters] setObject: _param forKey: _key];
185 [[self _queryParameters] removeObjectForKey: _key];
189 - (NSMutableDictionary *) _queryParameters
191 // TODO: this code is weird, should use WORequest methods for parsing
198 return queryParameters;
200 queryParameters = [[NSMutableDictionary alloc] initWithCapacity:8];
202 req = [context request];
204 r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
207 qs = [uri substringFromIndex:NSMaxRange(r)];
208 [self _parseQueryString:qs];
211 /* add form values */
212 [self addKeepAliveFormValuesToQueryParameters];
214 return queryParameters;
217 - (NSDictionary *) queryParameters
219 return [self _queryParameters];
222 - (NSDictionary *) queryParametersBySettingSelectedDate: (NSCalendarDate *) _date
224 NSMutableDictionary *qp;
226 qp = [[self queryParameters] mutableCopy];
227 [self setSelectedDateQueryParameter:_date inDictionary:qp];
228 return [qp autorelease];
231 - (void) setSelectedDateQueryParameter: (NSCalendarDate *) _newDate
232 inDictionary: (NSMutableDictionary *) _qp
235 [_qp setObject: [self dateStringForDate: _newDate] forKey: @"day"];
237 [_qp removeObjectForKey:@"day"];
240 - (NSString *) completeHrefForMethod: (NSString *) _method
244 NSString *qs, *qps, *href;
246 qp = [self queryParameters];
250 qps = [ctx queryPathSeparator];
251 [ctx setQueryPathSeparator: @"&"];
252 qs = [ctx queryStringFromDictionary: qp];
253 [ctx setQueryPathSeparator: qps];
254 href = [_method stringByAppendingFormat:@"?%@", qs];
262 - (NSString *) ownMethodName
267 uri = [[context request] uri];
269 /* first: cut off query parameters */
271 r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
273 uri = [uri substringToIndex:r.location];
275 /* next: strip trailing slash */
277 if ([uri hasSuffix: @"/"])
278 uri = [uri substringToIndex: ([uri length] - 1)];
279 r = [uri rangeOfString:@"/" options: NSBackwardsSearch];
281 /* then: cut of last path component */
283 if (r.length == 0) // no slash? are we at root?
286 return [uri substringFromIndex: (r.location + 1)];
289 - (NSString *) userFolderPath
292 NSEnumerator *objects;
293 SOGoObject *currentObject;
297 objects = [[ctx objectTraversalStack] objectEnumerator];
298 currentObject = [objects nextObject];
302 if ([currentObject isKindOfClass: [SOGoUserFolder class]])
305 currentObject = [objects nextObject];
307 return [[currentObject baseURLInContext:ctx] hostlessURL];
310 - (NSString *) applicationPath
312 SOGoObject *currentClient, *parent;
314 Class objectClass, groupFolderClass, userFolderClass;
316 currentClient = [self clientObject];
318 && [currentClient isKindOfClass: [SOGoObject class]])
320 groupFolderClass = [SOGoCustomGroupFolder class];
321 userFolderClass = [SOGoUserFolder class];
323 objectClass = [currentClient class];
324 found = (objectClass == groupFolderClass || objectClass == userFolderClass);
325 while (!found && currentClient)
327 parent = [currentClient container];
328 objectClass = [parent class];
329 if (objectClass == groupFolderClass
330 || objectClass == userFolderClass)
333 currentClient = parent;
337 currentClient = [WOApplication application];
339 return [[currentClient baseURLInContext: context] hostlessURL];
342 - (NSString *) resourcesPath
344 WOResourceManager *rm;
346 if ((rm = [self resourceManager]) == nil)
347 rm = [[WOApplication application] resourceManager];
349 return [rm webServerResourcesPath];
352 - (NSString *) ownPath
357 uri = [[context request] uri];
359 /* first: cut off query parameters */
361 r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
363 uri = [uri substringToIndex:r.location];
368 - (NSString *) relativePathToUserFolderSubPath: (NSString *) _sub
372 dst = [[self userFolderPath] stringByAppendingPathComponent: _sub];
373 rel = [dst urlPathRelativeToPath:[self ownPath]];
378 - (NSCalendarDate *) selectedDate
380 NSTimeZone *userTimeZone;
384 userTimeZone = [[context activeUser] timeZone];
387 dateFromShortDateString: [self queryParameterForKey: @"day"]
388 andShortTimeString: [self queryParameterForKey: @"hm"]
389 inTimeZone: userTimeZone];
390 [_selectedDate retain];
393 return _selectedDate;
396 - (NSString *) dateStringForDate: (NSCalendarDate *) _date
398 NSTimeZone *userTimeZone;
400 userTimeZone = [[context activeUser] timeZone];
401 [_date setTimeZone: userTimeZone];
403 return [_date descriptionWithCalendarFormat: @"%Y%m%d"];
408 return ([[self queryParameterForKey: @"noframe"] boolValue]);
411 - (UIxComponent *) jsCloseWithRefreshMethod: (NSString *) methodName
415 jsClose = [UIxJSClose new];
416 [jsClose autorelease];
417 [jsClose setRefreshMethod: methodName];
424 - (NSString *) shortUserNameForDisplay
426 if ([context activeUser] == nil)
427 return @"wrongusernamepassword";
429 return [[context activeUser] login];
434 - (NSString *) labelForKey: (NSString *) _str
436 WOResourceManager *rm;
438 NSString *lKey, *lTable, *lVal;
441 if ([_str length] == 0)
444 /* lookup languages */
446 languages = [context resourceLookupLanguages];
448 /* find resource manager */
450 if ((rm = [self pageResourceManager]) == nil)
451 rm = [[WOApplication application] resourceManager];
453 [self warnWithFormat:@"missing resource manager!"];
457 r = [_str rangeOfString:@"/"];
459 lTable = [_str substringToIndex:r.location];
460 lKey = [_str substringFromIndex:(r.location + r.length)];
468 if ([lKey hasPrefix:@"$"])
469 lKey = [self valueForKeyPath:[lKey substringFromIndex:1]];
471 if ([lTable hasPrefix:@"$"])
472 lTable = [self valueForKeyPath:[lTable substringFromIndex:1]];
475 if ([lVal hasPrefix:@"$"])
476 lVal = [self valueForKeyPath:[lVal substringFromIndex:1]];
481 return [rm stringForKey: lKey
483 withDefaultValue: lVal
484 languages: languages];
487 - (NSString *) localizedNameForDayOfWeek:(unsigned)_dayOfWeek {
488 NSString *key = [dayLabelKeys objectAtIndex:_dayOfWeek % 7];
489 return [self labelForKey:key];
492 - (NSString *)localizedAbbreviatedNameForDayOfWeek:(unsigned)_dayOfWeek {
493 NSString *key = [abbrDayLabelKeys objectAtIndex:_dayOfWeek % 7];
494 return [self labelForKey:key];
497 - (NSString *)localizedNameForMonthOfYear:(unsigned)_monthOfYear {
498 NSString *key = [monthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
499 return [self labelForKey:key];
502 - (NSString *)localizedAbbreviatedNameForMonthOfYear:(unsigned)_monthOfYear {
503 NSString *key = [abbrMonthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
504 return [self labelForKey:key];
507 /* HTTP method safety */
509 - (BOOL)isInvokedBySafeMethod {
510 // TODO: move to WORequest?
513 m = [[context request] method];
514 if ([m isEqualToString:@"GET"]) return YES;
515 if ([m isEqualToString:@"HEAD"]) return YES;
521 - (NSDictionary *)locale {
522 /* we need no fallback here, as locale is guaranteed to be set by sogod */
523 return [context valueForKey: @"locale"];
526 - (WOResourceManager *) pageResourceManager
528 WOResourceManager *rm;
530 if ((rm = [[context page] resourceManager]) == nil)
531 rm = [[WOApplication application] resourceManager];
536 - (NSString *) urlForResourceFilename: (NSString *) filename
538 static NSMutableDictionary *pageToURL = nil;
541 WOResourceManager *rm;
542 NSBundle *pageBundle;
547 pageToURL = [[NSMutableDictionary alloc] initWithCapacity: 32];
549 url = [pageToURL objectForKey: filename];
552 rm = [self pageResourceManager];
553 page = [context page];
554 pageBundle = [NSBundle bundleForClass: [page class]];
555 url = [rm urlForResourceNamed: filename
556 inFramework: [pageBundle bundlePath]
558 request: [context request]];
562 if ([url hasPrefix: @"http"])
563 url = [url hostlessURL];
564 [pageToURL setObject: url forKey: filename];
567 // NSLog (@"url for '%@': '%@'", filename, url);
575 - (WOResponse *) responseWith204
577 WOResponse *response;
579 response = [context response];
580 [response setStatus: 204];
587 - (BOOL)isUIxDebugEnabled {
588 return uixDebugEnabled;
591 @end /* UIxComponent */