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/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>
46 #import "UIxJSClose.h"
48 #import "UIxComponent.h"
50 @interface UIxComponent (PrivateAPI)
51 - (void)_parseQueryString:(NSString *)_s;
52 - (NSMutableDictionary *)_queryParameters;
55 @implementation UIxComponent
57 static NSMutableArray *dayLabelKeys = nil;
58 static NSMutableArray *abbrDayLabelKeys = nil;
59 static NSMutableArray *monthLabelKeys = nil;
60 static NSMutableArray *abbrMonthLabelKeys = nil;
62 static BOOL uixDebugEnabled = NO;
65 return [super version] + 0 /* v2 */;
69 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
71 NSAssert2([super version] == 2,
72 @"invalid superclass (%@) version %i !",
73 NSStringFromClass([self superclass]), [super version]);
75 uixDebugEnabled = [ud boolForKey:@"SOGoUIxDebugEnabled"];
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"];
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"];
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"];
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"];
128 if ((self = [super init]))
138 [queryParameters release];
139 [_selectedDate release];
143 /* query parameters */
145 - (void) _parseQueryString: (NSString *) _s
150 NSString *key, *value;
152 e = [[_s componentsSeparatedByString:@"&"] objectEnumerator];
153 part = [e nextObject];
156 r = [part rangeOfString:@"="];
159 /* missing value of query parameter */
160 key = [part stringByUnescapingURL];
165 key = [[part substringToIndex:r.location] stringByUnescapingURL];
166 value = [[part substringFromIndex:(r.location + r.length)]
167 stringByUnescapingURL];
169 [queryParameters setObject:value forKey:key];
170 part = [e nextObject];
174 - (void) addKeepAliveFormValuesToQueryParameters
178 - (NSString *) queryParameterForKey: (NSString *) _key
180 return [[self _queryParameters] objectForKey:_key];
183 - (void) setQueryParameter: (NSString *) _param
184 forKey: (NSString *) _key
189 [[self _queryParameters] setObject: _param forKey: _key];
191 [[self _queryParameters] removeObjectForKey: _key];
195 - (NSMutableDictionary *) _queryParameters
197 // TODO: this code is weird, should use WORequest methods for parsing
204 return queryParameters;
206 queryParameters = [[NSMutableDictionary alloc] initWithCapacity:8];
208 req = [context request];
210 r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
213 qs = [uri substringFromIndex:NSMaxRange(r)];
214 [self _parseQueryString:qs];
217 /* add form values */
218 [self addKeepAliveFormValuesToQueryParameters];
220 return queryParameters;
223 - (NSDictionary *) queryParameters
225 return [self _queryParameters];
228 - (NSDictionary *) queryParametersBySettingSelectedDate: (NSCalendarDate *) _date
230 NSMutableDictionary *qp;
232 qp = [[self queryParameters] mutableCopy];
233 [self setSelectedDateQueryParameter:_date inDictionary:qp];
234 return [qp autorelease];
237 - (void) setSelectedDateQueryParameter: (NSCalendarDate *) _newDate
238 inDictionary: (NSMutableDictionary *) _qp
241 [_qp setObject: [self dateStringForDate: _newDate] forKey: @"day"];
243 [_qp removeObjectForKey:@"day"];
246 - (NSString *) completeHrefForMethod: (NSString *) _method
250 NSString *qs, *qps, *href;
252 qp = [self queryParameters];
256 qps = [ctx queryPathSeparator];
257 [ctx setQueryPathSeparator: @"&"];
258 qs = [ctx queryStringFromDictionary: qp];
259 [ctx setQueryPathSeparator: qps];
260 href = [_method stringByAppendingFormat:@"?%@", qs];
268 - (NSString *) ownMethodName
273 uri = [[context request] uri];
275 /* first: cut off query parameters */
277 r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
279 uri = [uri substringToIndex:r.location];
281 /* next: strip trailing slash */
283 if ([uri hasSuffix: @"/"])
284 uri = [uri substringToIndex: ([uri length] - 1)];
285 r = [uri rangeOfString:@"/" options: NSBackwardsSearch];
287 /* then: cut of last path component */
289 if (r.length == 0) // no slash? are we at root?
292 return [uri substringFromIndex: (r.location + 1)];
295 - (NSString *) userFolderPath
298 NSEnumerator *objects;
299 SOGoObject *currentObject;
303 objects = [[ctx objectTraversalStack] objectEnumerator];
304 currentObject = [objects nextObject];
308 if ([currentObject isKindOfClass: [SOGoUserFolder class]])
311 currentObject = [objects nextObject];
313 return [[currentObject baseURLInContext:ctx] hostlessURL];
316 - (NSString *) applicationPath
318 SOGoObject *currentClient, *parent;
320 Class objectClass, groupFolderClass, userFolderClass;
322 currentClient = [self clientObject];
324 && [currentClient isKindOfClass: [SOGoObject class]])
326 groupFolderClass = [SOGoCustomGroupFolder class];
327 userFolderClass = [SOGoUserFolder class];
329 objectClass = [currentClient class];
330 found = (objectClass == groupFolderClass || objectClass == userFolderClass);
331 while (!found && currentClient)
333 parent = [currentClient container];
334 objectClass = [parent class];
335 if (objectClass == groupFolderClass
336 || objectClass == userFolderClass)
339 currentClient = parent;
343 currentClient = [WOApplication application];
345 return [[currentClient baseURLInContext: context] hostlessURL];
348 - (NSString *) resourcesPath
350 WOResourceManager *rm;
352 if ((rm = [self resourceManager]) == nil)
353 rm = [[WOApplication application] resourceManager];
355 return [rm webServerResourcesPath];
358 - (NSString *) ownPath
363 uri = [[context request] uri];
365 /* first: cut off query parameters */
367 r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
369 uri = [uri substringToIndex:r.location];
374 - (NSString *) relativePathToUserFolderSubPath: (NSString *) _sub
378 dst = [[self userFolderPath] stringByAppendingPathComponent: _sub];
379 rel = [dst urlPathRelativeToPath:[self ownPath]];
384 - (NSCalendarDate *) selectedDate
386 NSTimeZone *userTimeZone;
390 userTimeZone = [[context activeUser] timeZone];
393 dateFromShortDateString: [self queryParameterForKey: @"day"]
394 andShortTimeString: [self queryParameterForKey: @"hm"]
395 inTimeZone: userTimeZone];
396 [_selectedDate retain];
399 return _selectedDate;
402 - (NSString *) dateStringForDate: (NSCalendarDate *) _date
404 NSTimeZone *userTimeZone;
406 userTimeZone = [[context activeUser] timeZone];
407 [_date setTimeZone: userTimeZone];
409 return [_date descriptionWithCalendarFormat: @"%Y%m%d"];
414 return ([[self queryParameterForKey: @"noframe"] boolValue]);
417 - (UIxComponent *) jsCloseWithRefreshMethod: (NSString *) methodName
421 jsClose = [UIxJSClose new];
422 [jsClose autorelease];
423 [jsClose setRefreshMethod: methodName];
428 /* common conditions */
429 - (BOOL) canCreateOrModify
431 SoSecurityManager *sm;
433 sm = [SoSecurityManager sharedSecurityManager];
435 return (![sm validatePermission: SoPerm_ChangeImagesAndFiles
436 onObject: [self clientObject]
437 inContext: context]);
442 - (NSString *) shortUserNameForDisplay
444 if ([context activeUser] == nil)
445 return @"wrongusernamepassword";
447 return [[context activeUser] login];
452 - (NSString *) labelForKey: (NSString *) _str
454 WOResourceManager *rm;
456 NSString *lKey, *lTable, *lVal;
459 if ([_str length] == 0)
462 /* lookup languages */
464 languages = [context resourceLookupLanguages];
466 /* find resource manager */
468 if ((rm = [self pageResourceManager]) == nil)
469 rm = [[WOApplication application] resourceManager];
471 [self warnWithFormat:@"missing resource manager!"];
475 r = [_str rangeOfString:@"/"];
477 lTable = [_str substringToIndex:r.location];
478 lKey = [_str substringFromIndex:(r.location + r.length)];
486 if ([lKey hasPrefix:@"$"])
487 lKey = [self valueForKeyPath:[lKey substringFromIndex:1]];
489 if ([lTable hasPrefix:@"$"])
490 lTable = [self valueForKeyPath:[lTable substringFromIndex:1]];
493 if ([lVal hasPrefix:@"$"])
494 lVal = [self valueForKeyPath:[lVal substringFromIndex:1]];
499 return [rm stringForKey: lKey
501 withDefaultValue: lVal
502 languages: languages];
505 - (NSString *) localizedNameForDayOfWeek:(unsigned)_dayOfWeek {
506 NSString *key = [dayLabelKeys objectAtIndex:_dayOfWeek % 7];
507 return [self labelForKey:key];
510 - (NSString *)localizedAbbreviatedNameForDayOfWeek:(unsigned)_dayOfWeek {
511 NSString *key = [abbrDayLabelKeys objectAtIndex:_dayOfWeek % 7];
512 return [self labelForKey:key];
515 - (NSString *)localizedNameForMonthOfYear:(unsigned)_monthOfYear {
516 NSString *key = [monthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
517 return [self labelForKey:key];
520 - (NSString *)localizedAbbreviatedNameForMonthOfYear:(unsigned)_monthOfYear {
521 NSString *key = [abbrMonthLabelKeys objectAtIndex:(_monthOfYear - 1) % 12];
522 return [self labelForKey:key];
525 /* HTTP method safety */
527 - (BOOL)isInvokedBySafeMethod {
528 // TODO: move to WORequest?
531 m = [[context request] method];
532 if ([m isEqualToString:@"GET"]) return YES;
533 if ([m isEqualToString:@"HEAD"]) return YES;
539 - (NSDictionary *)locale {
540 /* we need no fallback here, as locale is guaranteed to be set by sogod */
541 return [context valueForKey: @"locale"];
544 - (WOResourceManager *) pageResourceManager
546 WOResourceManager *rm;
548 if ((rm = [[context page] resourceManager]) == nil)
549 rm = [[WOApplication application] resourceManager];
554 - (NSString *) urlForResourceFilename: (NSString *) filename
556 static NSMutableDictionary *pageToURL = nil;
559 WOResourceManager *rm;
560 NSBundle *pageBundle;
565 pageToURL = [[NSMutableDictionary alloc] initWithCapacity: 32];
567 url = [pageToURL objectForKey: filename];
570 rm = [self pageResourceManager];
571 page = [context page];
572 pageBundle = [NSBundle bundleForClass: [page class]];
573 url = [rm urlForResourceNamed: filename
574 inFramework: [pageBundle bundlePath]
576 request: [context request]];
580 if ([url hasPrefix: @"http"])
581 url = [url hostlessURL];
582 [pageToURL setObject: url forKey: filename];
585 // NSLog (@"url for '%@': '%@'", filename, url);
593 - (WOResponse *) responseWith204
595 WOResponse *response;
597 response = [context response];
598 [response setStatus: 204];
605 - (BOOL)isUIxDebugEnabled {
606 return uixDebugEnabled;
609 @end /* UIxComponent */