/* Copyright (C) 2000-2005 SKYRIX Software AG This file is part of SOPE. SOPE is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. SOPE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with SOPE; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "WOForm.h" #include "WOElement+private.h" #include "WOInput.h" #include "WOContext+private.h" #include #include "decommon.h" @implementation WOForm static int debugTakeValues = -1; + (int)version { return 4; } - (id)initWithName:(NSString *)_name associations:(NSDictionary *)_config template:(WOElement *)_c { if (debugTakeValues == -1) { debugTakeValues = [[NSUserDefaults standardUserDefaults] boolForKey:@"WODebugTakeValues"] ? 1 : 0; if (debugTakeValues) NSLog(@"WOForm: WODebugTakeValues on."); } if ((self = [super initWithName:_name associations:_config template:_c])) { WOAssociation *sidInUrlAssoc; id tmp; self->containsForm = YES; sidInUrlAssoc = OWGetProperty(_config, @"?wosid"); self->action = OWGetProperty(_config, @"action"); self->href = OWGetProperty(_config, @"href"); self->pageName = OWGetProperty(_config, @"pageName"); self->queryDictionary = OWGetProperty(_config, @"queryDictionary"); self->queryParameters = OWExtractQueryParameters(_config); self->actionClass = OWGetProperty(_config, @"actionClass"); self->directActionName = OWGetProperty(_config, @"directActionName"); self->method = OWGetProperty(_config, @"method"); self->sidInUrl = (sidInUrlAssoc != nil) ? [sidInUrlAssoc boolValueInComponent:nil] : YES; if ((tmp = OWGetProperty(_config, @"multipleSubmit")) != nil) { /* not required with SOPE, for WO compatibility */ [tmp release]; } self->template = [_c retain]; } return self; } - (void)dealloc { [self->method release]; [self->template release]; [self->actionClass release]; [self->directActionName release]; [self->queryDictionary release]; [self->queryParameters release]; [self->action release]; [self->pageName release]; [self->href release]; [super dealloc]; } /* handle active form elements */ - (id)template { return self->template; } /* handling requests */ - (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx { static int alwaysPassIn = -1; if (alwaysPassIn == -1) { alwaysPassIn = [[[NSUserDefaults standardUserDefaults] objectForKey:@"WOFormAlwaysPassDown"] boolValue] ? 1 : 0; } if ([_ctx isInForm]) { [self errorWithFormat:@"(%s): another form is already active in context !", __PRETTY_FUNCTION__]; } [_ctx setInForm:YES]; { WOComponent *sComponent = [_ctx component]; BOOL doTakeValues = NO; if (self->queryParameters != nil) { /* apply values to ?style parameters */ NSEnumerator *keys; NSString *key; keys = [self->queryParameters keyEnumerator]; while ((key = [keys nextObject])) { WOAssociation *assoc; id value; assoc = [self->queryParameters objectForKey:key]; value = [_rq formValueForKey:key]; [assoc setValue:value inComponent:sComponent]; } } // TODO: explain this href comparison if ([[self->href stringValueInComponent:sComponent] isEqualToString:[_rq uri]]) { if (debugTakeValues) { NSArray *formValues = [_rq formValueKeys]; NSLog(@"%s: we are uri active (uri=%@): %@ ..", __PRETTY_FUNCTION__, [_rq uri], formValues); } doTakeValues = YES; } else if ([[_ctx elementID] isEqualToString:[_ctx senderID]]) { if (debugTakeValues) { NSArray *formValues = [_rq formValueKeys]; NSLog(@"%s: we are elem active (eid=%@): %@ ..", __PRETTY_FUNCTION__, [_ctx elementID], formValues); } doTakeValues = YES; } else if (alwaysPassIn) { // Note: this does not call the component! Bug? (see 'else' below) if (debugTakeValues) NSLog(@"%s: taking values from foreign request ",__PRETTY_FUNCTION__); doTakeValues = YES; } else { /* finally, let the component decide */ doTakeValues = [sComponent shouldTakeValuesFromRequest:_rq inContext:_ctx]; if (debugTakeValues) { NSLog(@"%s: component should take values: %s ", __PRETTY_FUNCTION__, doTakeValues ? "yes" : "no"); } } if (doTakeValues) { if (debugTakeValues) NSLog(@"%s: taking values ...", __PRETTY_FUNCTION__); [self->template takeValuesFromRequest:_rq inContext:_ctx]; if (debugTakeValues) NSLog(@"%s: did take values.", __PRETTY_FUNCTION__); } else if (debugTakeValues) { [sComponent debugWithFormat: @"WOForm: *not* taking values from foreign request " @"(id='%@' vs sid='%@') ...", [_ctx elementID], [_ctx senderID]]; } } if (![_ctx isInForm]) { [[_ctx component] errorWithFormat:@"(%s:%d): -isInForm is NO !!!", __PRETTY_FUNCTION__, __LINE__]; } else [_ctx setInForm:NO]; } - (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx { id result = nil; [_ctx setInForm:YES]; if ([_ctx currentElementID] == nil) { WOElement *element; if ((element = [_ctx activeFormElement])) { #if 1 result = [self->template invokeActionForRequest:_rq inContext:_ctx]; RETAIN(result); #else /* wrong - need to setup correct component stack */ result = [[element invokeActionForRequest:_rq inContext:_ctx] retain]; #endif } else if (self->action) { result = [self executeAction:self->action inContext:_ctx]; } else if (self->pageName) { NSString *pname = nil; WOComponent *page = nil; pname = [self->pageName stringValueInComponent:[_ctx component]]; page = [[_ctx application] pageWithName:pname inContext:_ctx]; if (page == nil) { [[_ctx session] logWithFormat: @"%@[0x%p]: did not find page with name %@ !", NSStringFromClass([self class]), self, pname]; } NSLog(@"showing page %@", page); result = page; } } else result = [self->template invokeActionForRequest:_rq inContext:_ctx]; [_ctx setInForm:NO]; return result; } /* generate response */ - (NSString *)_addHrefToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx { /* post to a fixed hyperlink */ WOComponent *sComponent = [_ctx component]; NSString *s; NSDictionary *d; s = [self->href stringValueInComponent:sComponent]; d = [self->queryDictionary valueInComponent:sComponent]; WOResponse_AddString(_r, s); return [self queryStringForQueryDictionary:d andQueryParameters:self->queryParameters inContext:_ctx]; } - (NSString *)_addActionToResponse:(WOResponse *)_r inContext:(WOContext *)_c { /* post to a component action */ NSDictionary *d; WOResponse_AddString(_r, [_c componentActionURL]); d = [self->queryDictionary valueInComponent:[_c component]]; return [self queryStringForQueryDictionary:d andQueryParameters:self->queryParameters inContext:_c]; } - (void)_addDirectActionToResponse:(WOResponse *)_r inContext:(WOContext *)_c { /* a direct action link */ WOComponent *sComponent; NSString *daClass = nil; NSString *daName = nil; NSMutableDictionary *qd; NSDictionary *tmp; NSString *uri; sComponent = [_c component]; daClass = [self->actionClass stringValueInComponent:sComponent]; daName = [self->directActionName stringValueInComponent:sComponent]; if (daClass != nil) { if (daName != nil) { if (![daClass isEqualToString:@"DirectAction"]) daName = [NSString stringWithFormat:@"%@/%@", daClass, daName]; } else daName = daClass; } qd = [NSMutableDictionary dictionaryWithCapacity:16]; /* add query dictionary */ if (self->queryDictionary) { if ((tmp = [self->queryDictionary valueInComponent:sComponent])) [qd addEntriesFromDictionary:tmp]; } /* add ?style parameters */ if (self->queryParameters) { NSEnumerator *keys; NSString *key; keys = [self->queryParameters keyEnumerator]; while ((key = [keys nextObject])) { id assoc, value; assoc = [self->queryParameters objectForKey:key]; value = [assoc stringValueInComponent:sComponent]; [qd setObject:(value != nil ? value : (id)@"") forKey:key]; } } /* add session ID */ if (self->sidInUrl && [_c hasSession]) { WOSession *sn; sn = [_c session]; [qd setObject:[sn sessionID] forKey:WORequestValueSessionID]; if (![sn isDistributionEnabled]) { [qd setObject:[[WOApplication application] number] forKey:WORequestValueInstance]; } } else if (self->sidInUrl) { /* Note: this is not a problem! Eg this occurs on the OGo Main component */ [self debugWithFormat: @"Note: session-id is requested, but no session is active?"]; } uri = [_c directActionURLForActionNamed:daName queryDictionary:qd]; WOResponse_AddString(_r, uri); } - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx { WOComponent *sComponent; NSString *queryString = nil; if ([[_ctx request] isFromClientComponent]) { [self->template appendToResponse:_response inContext:_ctx]; return; } [_ctx setInForm:YES]; sComponent = [_ctx component]; WOResponse_AddCString(_response, "
href != nil) queryString = [self _addHrefToResponse:_response inContext:_ctx]; else if (self->directActionName != nil || self->actionClass != nil) [self _addDirectActionToResponse:_response inContext:_ctx]; else queryString = [self _addActionToResponse:_response inContext:_ctx]; if (queryString) { [_response appendContentCharacter:'?']; WOResponse_AddString(_response, queryString); } if (self->method) { WOResponse_AddCString(_response, "\" method=\""); WOResponse_AddString(_response, [self->method stringValueInComponent:sComponent]); WOResponse_AddCString(_response, "\""); } else WOResponse_AddCString(_response, "\" method=\"post\""); [self appendExtraAttributesToResponse:_response inContext:_ctx]; if (self->otherTagString) { WOResponse_AddChar(_response, ' '); WOResponse_AddString(_response, [self->otherTagString stringValueInComponent: sComponent]); } WOResponse_AddChar(_response, '>'); [self->template appendToResponse:_response inContext:_ctx]; WOResponse_AddCString(_response, "
"); [_ctx setInForm:NO]; } /* description */ - (NSString *)associationDescription { NSMutableString *str = [NSMutableString stringWithCapacity:64]; //[str appendString:[super associationDescription]]; if (self->action) [str appendFormat:@" action=%@", self->action]; if (self->href) [str appendFormat:@" href=%@", self->href]; if (self->pageName) [str appendFormat:@" page=%@", self->pageName]; if (self->actionClass) [str appendFormat:@" actionClass=%@", self->actionClass]; if (self->directActionName) [str appendFormat:@" directAction=%@", self->directActionName]; if (self->template) [str appendFormat:@" template=%@", self->template]; return str; } @end /* WOForm */