Index: openacs-4/packages/soap-gateway/soap-gateway.info
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/soap-gateway.info,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/soap-gateway.info	17 Oct 2004 05:51:39 -0000	1.1
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!-- Generated by the OpenACS Package Manager -->
+
+<package key="soap-gateway" url="http://openacs.org/repository/apm/packages/SOAP-Gateway" type="apm_application">
+    <package-name>SOAP Gateway</package-name>
+    <pretty-plural>SOAP Gateway</pretty-plural>
+    <initial-install-p>f</initial-install-p>
+    <singleton-p>t</singleton-p>
+    <auto-mount>soap</auto-mount>
+
+    <version name="0.12d" url="http://openacs.org/repository/download/apm/SOAP-Gateway-0.12d.apm">
+        <owner url="mailto:williamb@byrnelitho.com">William Byrne</owner>
+        <owner url="http://www.weg.ee.usyd.edu.au/people/ncarroll">Nick Carroll</owner>
+        <summary>SOAP Gateway marshalls SOAP/HTTP to user defined services</summary>
+        <release-date>2004-10-04</release-date>
+
+        <provides url="soap-gateway" version="0.12d"/>
+
+        <callbacks>
+        </callbacks>
+        <parameters>
+            <parameter datatype="string"  min_n_values="1"  max_n_values="1"  name="SOAP_ENC_1_1"  default="http://schemas.xmlsoap.org/soap/encoding/" description="Encoding for SOAP version 1.1."/>
+            <parameter datatype="string"  min_n_values="1"  max_n_values="1"  name="SOAP_ENC_1_2"  default="http://www.w3.org/2003/05/soap-encoding" description="Encoding for SOAP version 1.2."/>
+            <parameter datatype="string"  min_n_values="1"  max_n_values="1"  name="SOAP_NS_1_1"  default="http://schemas.xmlsoap.org/soap/envelope/" description="Namespace for SOAP version 1.1"/>
+            <parameter datatype="string"  min_n_values="1"  max_n_values="1"  name="SOAP_NS_1_2"  default="http://www.w3.org/2003/05/soap-envelope" description="Namespace for SOAP version 1.2."/>
+        </parameters>
+
+    </version>
+</package>
Index: openacs-4/packages/soap-gateway/lib/demo-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/lib/demo-procs.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/lib/demo-procs.tcl	17 Oct 2004 05:51:51 -0000	1.1
@@ -0,0 +1,83 @@
+ad_library {
+
+    soap-gateway demo routines
+
+    @author William Byrne (WilliamB@ByrneLitho.com)
+
+}
+
+# create namespace
+namespace eval sg::demo {
+
+	# remove old procs
+	foreach p [info commands ::sg::demo::*] {
+	
+		# remove
+		rename $p {}
+	}
+
+	# If there are any authentication requirements for a method in a service, add login
+	# and logout wrappers for soap::login and soap::logout methods. 
+	#
+	# This will prevent the SOAP client transport from having to maintain session cookies
+	# across multiple client SOAP stubs. For example, a SOAP client can log into OpenACS using
+	# the 'workspace' service. Typically, the SOAP client will fetch the WSDL for the service
+	# and expose methods to the developer for calling upon methods specified in the WSDL.
+	# In the case of the 'workspace' service, the user would call the 'login' method. If 
+	# successful, a session cookie is returned to the client and is maintained by the HTTP
+	# transport. If the user wishes to use the 'demo' service, another client SOAP stub 
+	# would be created referencing the WSDL for the 'demo' service. Since the 'demo' SOAP
+	# stub is new, it won't have the session data maintained by the 'workspace' stub. There
+	# are certainly ways to share the session data; however, the process of doing so often 
+	# turns into a science project.
+
+	# workspace login wrapper
+	ad_proc -public login { 
+		user
+		password
+	} {
+		@author William Byrnec
+		@idl void Login(string user, string password)
+	} {
+		
+		# call sg library
+		return [soap::login $user $password]
+	}
+
+
+	# workspace logout wrapper
+	ad_proc -public logout {
+	} {
+		@author William Byrne
+		@idl void Logout()
+	} {
+		# call sg logout 
+		return [soap::logout]
+	}
+
+
+	# define calculate method
+	ad_proc -public calculate {
+		expr
+	} {
+	
+		Performs an evaluation of the expression argument. The method attemps to provide some
+		safety by scanning for procedure notation. If detected, an exception is thrown.
+		
+		@author William Byrne
+		@idl string Calculate(string expr)
+	} {
+		
+		# detect proc bracket
+		if { [sting first \[ $expr] >= 0 } {
+			# throw
+			soap::fault::raise "procedure calls within expression are not allowed!"
+		}
+		
+		# calculate
+		return [expr $expr]
+	
+	}
+
+
+}
Index: openacs-4/packages/soap-gateway/lib/interop-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/lib/interop-procs.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/lib/interop-procs.tcl	17 Oct 2004 05:51:51 -0000	1.1
@@ -0,0 +1,116 @@
+ad_library {
+
+    soap-gateway interop routines
+
+    @author William Byrne (WilliamB@ByrneLitho.com)
+
+}
+
+# set up interop namespace
+namespace eval sg::interop {
+
+	# remove old procs
+	foreach p [info commands ::sg::interop::*] {
+	
+		# remove
+		rename $p {}
+	}
+
+	ad_proc -public login {
+		user 
+		password
+	} {
+		Logs the user into OpenACS. The <em>user</em> and <em>password</em> arguments
+		correspond to the user/password values specified during user registration. The
+		HTTP transport used for the SOAP Envelope must support cookies for session based
+		RPC; otherwise, the user will be limited  WSDL functions that expose 'invoke'
+		privileges to 'public'.
+		
+		@author William Byrne
+		@idl void Login(string user, string password)
+	} {
+	
+		# call sg library
+		return [soap::login $user $password]
+	}
+	
+	ad_proc -public logout {
+	} {
+		Logs the current user session out of OpenACS.
+		
+		@author William Byrne
+		@idl void Logout()
+	} {
+		# call sg library
+		return [soap::logout]
+	}
+	
+	ad_proc -public echo_string {
+		data
+	} {
+		@author William Byrne
+		@idl string EchoString(string data)
+	} {
+	
+		# return test data
+		return $data
+	
+	}
+	
+	ad_proc -public echo_integer {
+		data
+	} {
+		@author William Byrne
+		@idl int EchoInteger(int data)
+	} {
+	
+		# return test data
+		return $data
+	
+	}
+	
+	ad_proc -public echo_float {
+		data
+	} {
+		@author William Byrne
+		@idl float EchoFloat(float data)
+	} {
+	
+		# return test data
+		return $data
+	
+	}
+
+	ad_proc -public echo_long {
+		data
+	} {
+		@author William Byrne
+		@idl long EchoLong(long data)
+	} {
+		# return test data
+		return $data
+	
+	}
+	
+	ad_proc -public echo_int64 {
+		data
+	} {
+		@author William Byrne
+		@idl __int64 EchoInt64(__int64 data)
+	} {
+		# return test data
+		return $data
+	
+	}
+
+	ad_proc -public echo_void {
+	} {
+		@author William Byrne
+		@idl void EchoVoid()
+	} {
+	
+		# return nothing
+	
+	}
+
+}	
Index: openacs-4/packages/soap-gateway/lib/workspace-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/lib/workspace-procs.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/lib/workspace-procs.tcl	17 Oct 2004 05:51:51 -0000	1.1
@@ -0,0 +1,220 @@
+ad_library {
+
+	The <em>workspace</em> service provides a set of user workspace functions that
+	include the ability to log in and out of the OpenACS system. In order to take 
+	advantage of session based SOAP RPC, the HTTP transport used by the client must
+	support cookies; otherwise, the user will be limited to methods that have 
+	<em>invoke</em> privileges on the <em>Public</em> user.
+
+    @author William Byrne (WilliamB@ByrneLitho.com)
+
+}
+
+# set up workspace namespace and exports
+namespace eval sg::workspace {
+
+	# remove old procs
+	foreach p [info commands ::sg::workspace::*] {
+	
+		# remove
+		rename $p {}
+	}
+
+
+	ad_proc -public login {
+		user 
+		password
+	} {
+		Logs the user into OpenACS. The <em>user</em> and <em>password</em> arguments
+		correspond to the user/password values specified during user registration. The
+		HTTP transport used for the SOAP Envelope must support cookies for session based
+		RPC; otherwise, the user will be limited  WSDL functions that expose 'invoke'
+		privileges to 'public'.
+		
+		@author William Byrne
+		@idl void Login(string user, string password)
+	} {
+
+		# call soap::login procedure
+		return [soap::login $user $password]	
+	}
+	
+	ad_proc -public logout {
+	} {
+		Logs the current user session out of OpenACS.
+		
+		@author William Byrne
+		@idl void Logout()
+	} {
+		
+		# call sg logout
+		return [soap::logout]
+	}
+	
+	ad_proc -public set_name {
+		firstname
+		lastname
+	} {
+		Changes the <em>firstname</em> and <em>lastname</em> of the user specified during the 'login' operation.		
+		
+		@author William Byrne
+		@idl void SetName(string firstname, string lastname)
+	} {
+	
+		# get user
+		set user_id [ad_conn user_id]
+	
+		# require write permission on user
+		soap::server::require_permission $user_id write
+		
+		# verify args ???
+	
+		db_dml {} "update persons
+		  set first_names = :firstname,
+		  last_name = :lastname
+		  where person_id = :user_id"
+		
+	}
+	
+	ad_proc -public get_name {
+	} {
+		Returns the first and last name of the user currently logged in.
+		
+		@author William Byrne
+		@idl string GetName()
+	} {
+	
+		# get user
+		set user_id [ad_conn user_id]
+	
+		# require write permission on user
+		soap::server::require_permission $user_id read
+		
+		db_1row  {} {
+		  select first_names, last_name, email, 
+		  case when url is null then 'http://' else url end as url,
+		  screen_name
+		  from cc_users 
+		  where user_id=:user_id
+		}
+	
+		# return name
+		return [string trim "$first_names $last_name"]
+		
+	}
+	
+	ad_proc -private has_bio {
+		user_id
+		{data {}}
+	} {
+		Utility procedure that returns whether user has bio record
+		
+		@author William Byrne	
+	} {
+	
+		# grafted from subsite		
+		set retval [db_0or1row grab_bio "select attr_value as bio_old
+			from acs_attribute_values
+			where object_id = :user_id
+			and attribute_id =
+			  (select attribute_id
+			  from acs_attributes
+			  where object_type = 'person'
+			  and attribute_name = 'bio')"]
+			  
+		# test
+		if { $data != {} } {
+		
+			# go up one frame
+			upvar $data bio
+
+			if [soap::server::lib::true $retval] {
+		
+				# set it
+				set bio $grab_bio
+			
+			} else {
+				
+				# clear it
+				set bio {}
+				
+			}
+		
+		}			  
+		
+		# return status
+		return $retval
+	}
+	
+	ad_proc -public get_bio {
+	} {
+		Returns the users biography.
+		
+		@author William Byrne
+		@idl string GetBio()
+		
+	} {
+	
+		# get user
+		set user_id [ad_conn user_id]
+	
+		# require write permission on user
+		soap::server::require_permission $user_id read
+		
+		# has bio will fill optional data arg with biography
+		has_bio $user_id bio
+		
+		# return bio
+		return $bio
+		
+	}
+
+	ad_proc -public set_bio {
+		bio
+	} {
+		Updates the users biography.
+		
+		@author William Byrne
+		@idl void SetBio(string bio)
+		
+	} {
+	
+		# get user
+		set user_id [ad_conn user_id]
+	
+		# require write permission on user
+		soap::server::require_permission $user_id read
+		
+		# verify length
+		soap::check_str_len $bio 4000 "Your biography is too long. Please limit it to 4000 characters"
+		
+		# has bio ?
+		if [has_bio $user_id] {
+		
+			# grafted from subsite - update
+			db_dml update_bio "update acs_attribute_values
+			set attr_value = :bio
+			where object_id = :user_id
+			and attribute_id =
+				  (select attribute_id
+				  from acs_attributes
+				  where object_type = 'person'
+				  and attribute_name = 'bio')"
+		
+		
+		} else {
+		
+			# grafted from subsite - insert		
+			db_dml insert_bio "insert into acs_attribute_values
+			(object_id, attribute_id, attr_value)
+			values 
+			(:user_id, (select attribute_id
+				  from acs_attributes
+				  where object_type = 'person'
+				  and attribute_name = 'bio'), :bio)"
+
+		}
+				
+	}
+	
+}
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/sql/postgresql/soap-gateway-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/sql/postgresql/soap-gateway-create.sql,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/sql/postgresql/soap-gateway-create.sql	17 Oct 2004 05:51:52 -0000	1.1
@@ -0,0 +1,571 @@
+-- packages/soap-gateway/sql/postgresql/soap-gateway-create.sql
+--
+-- @author WilliamB@ByrneLitho.com
+-- @creation-date 2002-12-22
+-- @cvs-id $Id: soap-gateway-create.sql,v 1.1 2004/10/17 05:51:52 ncarroll Exp $
+--
+--
+
+-- clear existing
+--\i soap-gateway-drop.sql
+--\q
+create function inline_0 ()
+returns integer as '
+begin
+    PERFORM acs_object_type__create_type (
+	''wsdl_namespace'',			-- object_type
+	''WSDL Namespace'',			-- pretty_name
+	''WSDL Namespaces'',		-- pretty_plural
+	''acs_object'',				-- supertype
+	''sg_namespaces'',			-- table_name
+	''namespace_id'',			-- id_column
+	null,						-- package_name
+	''f'',						-- abstract_p
+	null,						-- type_extension_table
+	''sg_namespaces__name''		-- name_method
+	);
+
+    return 0;
+end;' language 'plpgsql';
+
+select inline_0 ();
+
+drop function inline_0 ();
+
+create function inline_1 ()
+returns integer as '
+begin
+    PERFORM acs_object_type__create_type (
+	''wsdl_method'',			-- object_type
+	''WSDL Method'',			-- pretty_name
+	''WSDL Methods'',			-- pretty_plural
+	''acs_object'',				-- supertype
+	''sg_methods'',				-- table_name
+	''method_id'',				-- id_column
+	null,						-- package_name
+	''f'',						-- abstract_p
+	null,						-- type_extension_table
+	''sg_methods__name''		-- name_method
+	);
+
+    return 0;
+end;' language 'plpgsql';
+
+select inline_1 ();
+
+drop function inline_1 ();
+
+-- define invoke moniker
+create view sg_invoke_moniker as
+	select 'invoke' as invoke from dual;
+
+create function inline_2 ()
+returns integer as '
+declare
+	v_invoke varchar;
+begin
+	select invoke into v_invoke from sg_invoke_moniker;
+
+	-- create privileges
+	perform acs_privilege__create_privilege(v_invoke);
+	
+	-- bind privileges to global names
+	perform acs_privilege__add_child(''admin'',v_invoke);
+	
+	return 0;
+end;' language 'plpgsql';
+select inline_2();
+drop function inline_2();
+
+
+
+create table sg_namespaces (
+    namespace_id    integer 
+			   constraint sg_namespaces_namespace_id_fk
+			   references acs_objects(object_id) 
+			   constraint sg_namespaces_namespace_id_pk
+			   primary key,
+    service	   varchar(255) 
+			   constraint sg_namespaces_service_nn
+			   not null unique check(trim(service) <> ''),
+    uri		   varchar(255) 
+			   constraint sg_namespaces_uri_nn
+			   not null,
+	dirty	   boolean
+			   default 't'
+			   constraint sg_namespaces_dirty_nn
+			   not null,
+    notes      varchar(1024)
+);
+
+create index sg_namespaces_idx1 on sg_namespaces(service);
+
+create table sg_methods (
+    method_id    integer 
+			   constraint sg_methods_method_id_fk
+			   references acs_objects(object_id) 
+			   constraint sg_methods_namespace_id_pk
+			   primary key,
+    namespace_id   integer 
+			   constraint sg_methods_namespace_id_fk
+			   references sg_namespaces(namespace_id),
+    method	   varchar(255) 
+			   constraint sg_methods_method_nn
+			   not null check(trim(method) <> ''),
+    idl		   varchar(255) 
+			   constraint sg_methods_idl_nn
+			   not null,
+    idl_style  varchar(32)
+			   constraint sg_methods_idl_style_nn
+			   not null,
+    proc       varchar(255) 
+			   constraint sg_methods_proc_nn
+			   not null,
+    notes      varchar(1024)
+);
+
+-- oddity fixup for lower case on index
+create function sg_unique(integer,varchar)
+returns text as '
+begin
+	return '''' || $1 || ''-'' || lower($2);
+end;' language 'plpgsql' with(iscachable);;
+
+
+create unique index sg_methods_idx1 on sg_methods(sg_unique(namespace_id, method));
+
+	
+create table sg_libraries (
+    library_id  integer not null primary key,
+	path	varchar(255) not null unique
+);
+
+--
+-- sequences
+--
+
+create sequence sg_library_id_seq start 1000;
+
+--
+-- functions
+--
+
+-- get namespace id
+create function sg_namespace__get_id(varchar)
+returns integer as '
+declare
+	p_service		alias for $1;
+
+	v_namespace_id		sg_namespaces.namespace_id%type;
+begin
+
+	-- nullify
+	v_namespace_id = null;
+
+	-- get namespace count for id
+	select into v_namespace_id namespace_id
+	from sg_namespaces
+	where service = p_service;
+	
+	-- fix up
+	if v_namespace_id is null then
+		v_namespace_id = -1;
+	end if;
+	
+	-- return object id
+	return v_namespace_id;
+
+end;' language 'plpgsql';	
+
+-- create new namespace
+create function sg_namespace__new(varchar, varchar, varchar, timestamptz, integer, varchar, integer)
+returns integer as '
+declare
+	p_service		alias for $1;
+	p_uri			alias for $2;
+	p_notes			alias for $3;
+
+	p_creation_date	alias for $4;	-- default now()
+	p_creation_user	alias for $5;
+	p_creation_ip	alias for $6;
+	p_context_id	alias for $7;
+
+	v_namespace_id		sg_namespaces.namespace_id%type;
+begin
+
+	-- create new base object
+	v_namespace_id := acs_object__new (
+		null,
+		''wsdl_namespace'',
+		p_creation_date,
+		p_creation_user,
+		p_creation_ip,
+		p_context_id
+	);
+
+	-- add to namespace table
+	insert into sg_namespaces
+	  (namespace_id, service, uri, dirty, notes)
+	values
+	  (v_namespace_id, p_service, p_uri, ''t'', p_notes);
+
+	-- create admin permission
+	PERFORM acs_permission__grant_permission(
+          v_namespace_id,
+          p_creation_user,
+          ''admin''
+    );
+
+	-- return new object id
+	return v_namespace_id;
+
+end;' language 'plpgsql';	
+
+create function sg_namespace__update(integer, varchar, varchar, varchar)
+returns integer as '
+declare
+	p_namespace_id	alias for $1;
+	p_service		alias for $2;
+	p_uri			alias for $3;
+	p_notes			alias for $4;
+
+begin
+
+	-- update row values
+	update sg_namespaces
+		set 
+			service = p_service,
+			uri = p_uri,
+			dirty = ''t'',
+			notes = p_notes
+		where
+			namespace_id = p_namespace_id;
+			
+	-- return something
+	return 0;
+
+end;' language 'plpgsql';	
+
+-- check namespace id
+create function sg_namespace__exists(integer)
+returns integer as '
+declare
+	p_namespace_id alias for $1;
+	v_record record;
+begin
+	
+	-- get namespace count for id
+	select into v_record count(*)
+	from sg_namespaces
+	where namespace_id = p_namespace_id;
+	
+	-- test
+	return v_record.count;
+
+end;' language 'plpgsql';	
+
+-- remove namespace and child methods
+create function sg_namespace__delete (integer)
+returns integer as '
+declare
+	p_namespace_id	alias for $1;
+	v_object_rec		record;
+begin
+
+	-- verify id
+	if sg_namespace__exists(p_namespace_id) = 0 then
+		raise EXCEPTION ''Invalid namespace id: %'', p_namespace_id;
+	end if;
+
+	-- clean up permissions for namespace methods
+	delete from acs_permissions
+		where object_id in (
+			select method_id from sg_methods
+				where namespace_id = p_namespace_id
+			);
+			
+	-- clean up permissions for namespace
+    delete from acs_permissions
+		where object_id = p_namespace_id;
+
+	-- remove method objects
+	for v_object_rec in select method_id from sg_methods where namespace_id = p_namespace_id
+	loop
+		perform acs_object__delete( v_object_rec.method_id );
+	end loop;
+
+	PERFORM acs_object__delete(p_namespace_id);
+
+	-- remove methods
+	delete from sg_methods
+		where namespace_id = p_namespace_id;
+	
+	-- remove namespace
+	delete from sg_namespaces
+		where namespace_id = p_namespace_id;
+
+	return 0;
+
+end;' language 'plpgsql';
+
+
+-- create new method
+create function sg_method__new(integer, varchar, varchar, varchar, varchar, varchar, timestamptz, integer, varchar, integer)
+returns integer as '
+declare
+	p_namespace_id	alias for $1;
+	p_method		alias for $2;
+	p_idl			alias for $3;
+	p_idl_style		alias for $4;
+	p_proc			alias for $5;
+	p_notes			alias for $6;
+
+	p_creation_date	alias for $7;	-- default now()
+	p_creation_user	alias for $8;
+	p_creation_ip	alias for $9;
+	p_context_id	alias for $10;
+
+	v_method_id		integer;
+begin
+
+	-- create new base object
+	v_method_id := acs_object__new (
+		null,
+		''wsdl_method'',
+		p_creation_date,
+		p_creation_user,
+		p_creation_ip,
+		p_context_id
+	);
+
+	-- add to method table
+	insert into sg_methods
+	  (method_id, namespace_id, method, idl, idl_style, proc, notes)
+	values
+	  (v_method_id, p_namespace_id, p_method, p_idl, p_idl_style, p_proc, p_notes);
+
+	-- create admin permission
+	PERFORM acs_permission__grant_permission(
+          v_method_id,
+          p_creation_user,
+          ''admin''
+    );
+
+	-- return new object id
+	return v_method_id;
+
+end;' language 'plpgsql';	
+
+-- update method
+create function sg_method__update(integer, varchar, varchar, varchar, varchar, varchar)
+returns integer as '
+declare
+	p_method_id		alias for $1;
+	p_method		alias for $2;
+	p_idl			alias for $3;
+	p_idl_style		alias for $4;
+	p_proc			alias for $5;
+	p_notes			alias for $6;
+
+begin
+
+	-- update row values
+	update sg_methods
+		set 
+			method = p_method,
+			idl = p_idl,
+			idl_style = p_idl_style,
+			proc = p_proc,
+			notes = p_notes
+		where
+			method_id = p_method_id;
+			
+	-- return something
+	return 0;
+
+end;' language 'plpgsql';	
+
+-- check method id
+create function sg_method__exists(integer)
+returns integer as '
+declare
+	p_method_id alias for $1;
+	v_record record;
+begin
+	
+	-- get method count for id
+	select into v_record count(*)
+	from sg_methods
+	where method_id = p_method_id;
+	
+	-- test
+	return v_record.count;
+
+end;' language 'plpgsql';	
+	
+-- remove method
+create function sg_method__delete (integer)
+returns integer as '
+declare
+	p_method_id	alias for $1;
+begin
+
+	-- verify id
+	if sg_method__exists(p_method_id) = 0 then
+		raise EXCEPTION ''Invalid method id: %'', p_method_id;
+	end if;
+
+
+	-- clean up permissions for method
+    delete from acs_permissions
+		where object_id = p_method_id;
+
+	-- remove method object
+	perform acs_object__delete(p_method_id);
+	
+	-- remove methods
+	delete from sg_methods
+		where method_id = p_method_id;
+	
+	return 0;
+
+end;' language 'plpgsql';
+
+-- create new library
+create function sg_library__new(varchar)
+returns integer as '
+declare
+	p_path			alias for $1;
+
+	v_library_id		sg_libraries.library_id%type;
+begin
+
+	-- create next val
+	v_library_id = nextval(''sg_library_id_seq'');
+	
+	-- add to library table
+	insert into sg_libraries
+	  (library_id, path)
+	values
+	  (v_library_id, p_path);
+
+	-- return id
+	return v_library_id;
+
+end;' language 'plpgsql';	
+
+-- update library
+create function sg_library__update(integer, varchar)
+returns integer as '
+declare
+	p_library_id	alias for $1;
+	p_path		alias for $2;
+begin
+
+	-- update row values
+	update sg_libraries
+		set 
+			path = p_service
+		where
+			library_id = p_library_id;
+			
+	-- return something
+	return 0;
+
+end;' language 'plpgsql';	
+
+-- remove library
+create function sg_library__delete (integer)
+returns integer as '
+declare
+	p_library_id	alias for $1;
+begin
+
+	-- remove 
+	delete from sg_libraries
+		where library_id = p_library_id;
+
+	return 0;
+
+end;' language 'plpgsql';
+
+-- returns namespace name
+create function sg_namespaces__name (integer)
+returns varchar as '
+declare
+    id      alias for $1;
+    v_name  sg_namespaces.service%TYPE;
+begin
+	select service into v_name
+		from sg_namespaces
+		where namespace_id = id;
+
+    return v_name;
+end;' language 'plpgsql';
+
+-- returns method name
+create function sg_methods__name (integer)
+returns varchar as '
+declare
+    id      alias for $1;
+    v_name  sg_methods.method%TYPE;
+begin
+	select method into v_name
+		from sg_methods
+		where method_id = id;
+
+    return v_name;
+end;' language 'plpgsql';
+
+-- forces namespace to dirty state for WSDL regen
+create function sg_namespaces__dirty(integer)
+returns integer as '
+declare
+	id alias for $1;
+begin
+	update sg_namespaces
+	set dirty = ''t''
+	where namespace_id = id;
+    return 0;
+end;' language 'plpgsql';
+	
+-- trigger functions
+create function sg_methods__itrg ()
+returns opaque as '
+begin
+    perform sg_namespaces__dirty(new.namespace_id);
+    return new;
+end;' language 'plpgsql';
+
+create function sg_methods__dtrg ()
+returns opaque as '
+begin
+    perform sg_namespaces__dirty(old.namespace_id);
+    return old;
+end;' language 'plpgsql';
+
+create function sg_methods__utrg ()
+returns opaque as '
+begin
+    perform sg_namespaces__dirty(new.namespace_id);
+	if new.namespace_id <> old.namespace_id then
+	    perform sg_namespacs__dirty(old.namespace_id);
+	end if;
+    return old;
+end;' language 'plpgsql';
+
+-- create triggers
+create trigger sg_methods__itrg after insert on sg_methods
+for each row execute procedure sg_methods__itrg (); 
+
+create trigger sg_methods__dtrg after delete on sg_methods
+for each row execute procedure sg_methods__dtrg (); 
+
+create trigger sg_methods__utrg after update on sg_methods
+for each row execute procedure sg_methods__utrg (); 
+
+-- post intallation configuration
+select sg_library__new('packages/soap-gateway/lib/workspace-procs.tcl') from dual;
+select sg_library__new('packages/soap-gateway/lib/interop-procs.tcl') from dual;
+
+
Index: openacs-4/packages/soap-gateway/sql/postgresql/soap-gateway-drop.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/sql/postgresql/soap-gateway-drop.sql,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/sql/postgresql/soap-gateway-drop.sql	17 Oct 2004 05:51:52 -0000	1.1
@@ -0,0 +1,100 @@
+-- packages/soap-gateway/sql/postgresql/soap-gateway-drop.sql
+--
+-- @author WilliamB@ByrneLitho.com
+-- @creation-date 2002-12-22
+-- @cvs-id $Id: soap-gateway-drop.sql,v 1.1 2004/10/17 05:51:52 ncarroll Exp $
+--
+--
+
+--drop permissions
+delete from acs_permissions where object_id in (select method_id from sg_methods);
+delete from acs_permissions where object_id in (select namespace_id from sg_namespaces);
+delete from acs_permissions where object_id in (select object_id from acs_objects where object_type in ('wsdl_namespace','wsdl_method'));
+delete from acs_permissions where object_id in (select package_id from apm_packages where package_key in ('soap-gateway'));
+
+-- clear objects
+create function inline_0 ()
+returns integer as '
+declare
+	object_rec		record;
+begin
+	for object_rec in select object_id from acs_objects where object_type in (''wsdl_namespace'',''wsdl_method'')
+	loop
+		perform acs_object__delete( object_rec.object_id );
+	end loop;
+
+	return 0;
+end;' language 'plpgsql';
+
+select inline_0 ();
+drop function inline_0 ();
+
+create function inline_2 ()
+returns integer as '
+declare
+	v_invoke varchar;
+begin
+	select invoke into v_invoke from sg_invoke_moniker;
+
+	-- unbind privileges to global names
+	perform acs_privilege__remove_child(''admin'', v_invoke);
+
+	-- drop privileges
+	perform acs_privilege__drop_privilege(v_invoke);
+
+	
+	return 0;
+end;' language 'plpgsql';
+select inline_2();
+drop function inline_2();
+
+
+-- drop triggers
+drop trigger sg_methods__itrg on sg_methods;
+drop trigger sg_methods__dtrg on sg_methods; 
+drop trigger sg_methods__utrg on sg_methods; 
+
+-- drop functions
+drop function sg_namespace__get_id(varchar);
+drop function sg_namespace__new(varchar, varchar, varchar, timestamptz, integer, varchar, integer);
+drop function sg_namespace__update(integer, varchar, varchar, varchar);
+drop function sg_namespace__exists(integer);
+drop function sg_namespace__delete (integer);
+drop function sg_method__new(integer, varchar, varchar, varchar, varchar, varchar, timestamptz, integer, varchar, integer);
+drop function sg_method__update(integer, varchar, varchar, varchar, varchar, varchar);
+drop function sg_method__exists(integer);
+drop function sg_method__delete (integer);
+drop function sg_namespaces__name (integer);
+drop function sg_methods__name (integer);
+drop function sg_namespaces__dirty(integer);
+drop function sg_methods__itrg();
+drop function sg_methods__dtrg();
+drop function sg_methods__utrg();
+drop function sg_library__new(varchar);
+drop function sg_library__update(integer, varchar);
+drop function sg_library__delete(integer);
+drop function sg_unique(integer,varchar);
+
+-- drop tables
+drop table sg_methods;
+drop table sg_namespaces;
+drop table sg_libraries;
+
+-- drop sequences
+drop sequence sg_library_id_seq;
+
+-- drop views
+drop view sg_invoke_moniker;
+
+-- drop attributes
+
+-- drop type
+select acs_object_type__drop_type(
+	   'wsdl_namespace',
+	   't'
+	);
+select acs_object_type__drop_type(
+	   'wsdl_method',
+	   't'
+	);
+
Index: openacs-4/packages/soap-gateway/tcl/soap-fault-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/tcl/soap-fault-procs.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/tcl/soap-fault-procs.tcl	17 Oct 2004 05:51:52 -0000	1.1
@@ -0,0 +1,239 @@
+ad_library {
+    Tcl API for SOAP Faults.
+
+    @author William Byrne (WilliamB@ByrneLitho.com)
+    @author Nick Carroll (ncarroll@ee.usyd.edu.au)
+    @creation-date 2004-09-24
+    @cvs-id $Id: soap-fault-procs.tcl,v 1.1 2004/10/17 05:51:52 ncarroll Exp $
+}
+
+
+namespace eval soap::fault {}
+
+
+ad_proc -public soap::fault::assert {
+    test
+    msg
+} {
+    @param test
+    @param msg
+} {
+    # calculate
+    if [catch {set test [uplevel expr $test] } ] {
+	# throw
+	soap::fault::raise "Assertion\ntest: $test\n$msg"
+    }
+
+    # test
+    if { [string is integer -strict $test] == 0 || $test == 0 } {
+	# throw
+	soap::fault::raise "Assertion\ntest: $test\n$msg"
+    }
+}
+
+
+ad_proc -public soap::fault::raise {
+    msg
+    {code 500}
+} {
+    @param msg
+    @param code Default code set to 500.
+} {
+
+    # throw
+    error "SOAP Gateway Error\n$msg" {} $code
+}
+
+
+ad_proc -public soap::fault::unauthorized {
+    {msg "Access Denied"}
+} {
+    @param msg
+} {
+
+    # throw
+    soap::fault::raise "$msg" 401
+}
+
+
+ad_proc -public soap::fault::unsupported {
+    msg
+} {
+    @param msg
+} {
+
+    # throw
+    soap::fault::raise "$msg" 501
+}
+
+
+ad_proc -private soap::fault::generate_fault {
+    msg
+    {ver 1.1}
+} {
+    Generates a fault response based on the specified message.
+
+    @param msg The message to be sent back to the client.
+    @param ver The version of SOAP that the message should be based on.
+    @return Returns a fault response SOAP message.
+} {
+    # get version namespace
+    set version [soap::server::get_version_namespace $ver]
+
+    # construct xml doc object
+    set doc [dom createDocument env:Envelope]
+
+    # create root node: "env:Envelope"
+    set env [$doc documentElement] 
+
+    # define namespace atts into node
+    $env setAttribute xmlns:env $version
+
+    # create Body node - "env:Envelope/env:Body"
+    set body [$env appendChild [$doc createElement env:Body]]
+
+    # create Fault node - "env:Envelope/env:Body/env:Fault"
+    set fault [$body appendChild [$doc createElement env:Fault]]
+	
+    # test version
+    if { $ver == "1.1" } {
+
+	# create faultcode node
+        # env:Envelope/env:Body/env:Fault/env:faultcode
+	$fault appendXML "<env:faultcode>env:Client</env:faultcode>"
+	
+	# create faultstring node
+	# env:Envelope/env:Body/env:Fault/env:faultstring
+	$fault appendXML "<env:faultstring>$msg</env:faultstring>"
+	
+    } else { 
+		
+	# do v1.2
+
+	# create Code node and Value as a sub node of Code
+        # env:Envelope/env:Body/env:Fault/env:Code
+	# env:Envelope/env:Body/env:Fault/env:Code/env:Value
+	$fault appendXML "
+            <env:Code>
+                <env:Value>env:Sender</env:Value>
+            </env:Code>"
+	
+	# create Reason node
+	# env:Envelope/env:Body/env:Fault/env:Reason
+	# define lang attr into Reason node
+	$fault appendFromList [list env:Reason {xml:lang en-US} {}]
+    }
+	
+    # render xml into result string
+    return [$env asXML]
+}
+
+ad_proc -private soap::fault::generate_misunderstood {
+    namespaces
+    {ver 1.1}
+} {
+    Generates a misunderstood fault response based on the 
+    specified namespaces.
+
+    @param namespaces The message to be sent back to the client.
+    @param ver The version of SOAP that the message should be based on.
+    @return Returns a misunderstood fault response SOAP message.
+} {
+    # set envelope version
+    set version [soap::server::get_version_namespace $ver]
+
+    # construct xml doc object
+    set doc [dom createDocument env:Envelope]
+
+    # create root node: "env:Envelope"
+    set env [$doc documentElement]
+
+    # define namespace atts into node
+    $env setAttribute xmlns:env $version
+    $env setAttribute xmlns:flt http://www.w3.org/2003/05/soap-faults
+
+    # create Header node - "env:Envelope/env:Header"
+    set header [$env appendChild [$doc createElement env:Header]]
+
+    # loop through namespaces and add
+    foreach ns $namespaces {
+        # safety
+        if { [llength $ns] > 1 } {
+	    # add child
+            set mu [$header appendChild [$doc createElement flt:Misunderstood]]
+
+	    # get qname
+	    set qname [lindex $ns 0]
+
+	    # split off namespace prefix
+	    set parts [split $qname :]
+
+	    # test
+	    if { [llength $parts] > 1 } {
+		# get prefix
+		set prefix [lindex $parts 0]
+		
+		# get name
+		set name [lindex $parts 1]
+	    } else {
+		# generate prefix
+		append auto x
+
+		# set prefix to auto
+		set prefix $auto
+
+		# set name to qname
+		set name $qname
+	    }
+
+	    # add name attr
+	    $mu setAttribute qname "$prefix:$name"
+
+	    # add namespace
+	    $mu setAttribute "xmlns:$prefix" [lindex $ns 1]
+	}
+    }
+
+    # create Body node - "env:Envelope/env:Body"
+    set body [$env appendChild [$doc createElement env:Body]]
+
+    # create Fault node - "env:Envelope/env:Body/env:Fault"
+    set fault [$body appendChild [$doc createElement env:Fault]]
+
+    # test version
+    if { $ver == "1.1" } {
+	
+	# create faaultcode node
+        #env:Envelope/env:Body/env:Fault/env:faultcode
+	$fault appendXML "<env:faultcode>env:MustUnderstand</env:faultcode>"
+
+	# create faultstring node
+	# env:Envelope/env:Body/env:Fault/env:faultstring
+	$fault appendXML "<env:faultstring>One or more mandatory headers not understood</env:faultstring>"
+	
+    } else { 
+	
+	# do v1.2
+	
+	# create Code node
+	# env:Envelope/env:Body/env:Fault/env:Code
+	# env:Envelope/env:Body/env:Fault/env:Code/env:Value
+        $fault appendXML "
+            <env:Code>
+                <env:Value>env:MustUnderstand</env:Value>
+            </env:Code>"
+
+	# create Reason node
+	# env:Envelope/env:Body/env:Fault/env:Reason
+	set reason [$fault appendChild [$doc createElement env:Reason]]
+
+	# define lang attr into Reason node
+	$reason setAttribute xml:lang "en-US"
+
+	# set message for env:Reason.
+	$reason appendChild [$doc createTextNode "One or more mandatory headers not understood"]
+    }
+    
+    # render xml into result string
+    return [$env asXML]
+}
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/tcl/soap-init.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/tcl/soap-init.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/tcl/soap-init.tcl	17 Oct 2004 05:51:53 -0000	1.1
@@ -0,0 +1,10 @@
+ad_library {
+
+    soap-gateway init library routines
+
+    @author William Byrne (WilliamB@ByrneLitho.com)
+
+}
+
+# schedule a one time directory scan for service source files
+ad_schedule_proc -thread t -once t 5 soap::server::lib::boot_libraries
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/tcl/soap-procs-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/tcl/soap-procs-postgresql.xql,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/tcl/soap-procs-postgresql.xql	17 Oct 2004 05:51:53 -0000	1.1
@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+
+<queryset>
+  <rdbms><type>postgresql</type><version>7.1</version></rdbms>
+
+  <fullquery name="soap::method_get_procs.select_procs">
+    <querytext>
+      select proc
+        from sg_methods
+        where namespace_id = :namespace_id
+        order by method_id
+    </querytext>
+  </fullquery>
+
+  <fullquery name="soap::namespace_get_names.select_services">
+    <querytext>
+      select service from sg_namespaces;
+    </querytext>
+  </fullquery>
+
+  <fullquery name="soap::package_id.select_pid">
+    <querytext>
+      select package_id from apm_packages where package_key = 'soap-gateway'
+    </querytext>
+  </fullquery>
+
+  <fullquery name="soap::namespace_check.namespace_exists">
+    <querytext>
+      select sg_namespace__exists(:namespace_id);
+    </querytext>
+  </fullquery>
+
+  <fullquery name="soap::method_check.method_exists">
+    <querytext>
+        select sg_method__exists(:method_id)
+    </querytext>
+  </fullquery>
+
+  <fullquery name="soap::namespace_delete.namespace_delete">      
+    <querytext>
+      select 0 + sg_namespace__delete(:namespace_id);
+    </querytext>
+  </fullquery>
+
+  <fullquery name="soap::method_delete.delete_method">      
+    <querytext>
+      select 0 + sg_method__delete(:method_id);
+    </querytext>
+  </fullquery>
+
+</queryset>
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/tcl/soap-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/tcl/soap-procs.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/tcl/soap-procs.tcl	17 Oct 2004 05:51:53 -0000	1.1
@@ -0,0 +1,852 @@
+ad_library {
+    SOAP utils API.
+
+    Based on William Byrne's soap-gateway implementation.
+
+    @author William Byrne (WilliamB@ByrneLitho.com)
+    @author Nick Carroll (ncarroll@ee.usyd.edu.au)
+    @creation-date 2004-09-24
+    @cvs-id $Id: soap-procs.tcl,v 1.1 2004/10/17 05:51:53 ncarroll Exp $
+}
+
+
+namespace eval soap {}
+
+# Libraries in the lib directory must run in the sg namespace.
+namespace eval sg {}
+
+
+ad_proc -public soap::check_str_len {
+    string
+    length
+    {warning {string is too long}}
+} {
+    Verifies the string does not exceed length
+    
+    @param string
+    @param length
+    @param warning
+} {
+    if { [string length $string] > $length } {
+	# throw
+	soap::fault::raise $warning
+    }   
+}
+
+
+# create login wrapper for sg services
+ad_proc -public soap::login {
+    user
+    password
+} {
+    @param user
+    @param password
+} {
+    # normalize id
+    set email [string tolower $user]
+    
+    # search for
+    set result [db_0or1row user_login_user_id_from_email {
+	select user_id, member_state, email_verified_p
+	from cc_users
+	where email = :email}]
+    
+    # good house keeping		
+    db_release_unused_handles
+        
+    # verify
+    if { $result == 0 } {
+	# rejected	
+	soap::fault::unauthorized "Access Denied\n$email not registered"
+    }
+    
+    # again
+    if { $member_state != "approved" || $email_verified_p == "f" } {
+	# rejected	
+	soap::fault::unauthorized "Access Denied\nMember: $member_state\ne-mail: $email_verified_p"
+    }
+    
+    # and again
+    if { ![ad_check_password $user_id $password] } {
+	# rejected	
+	soap::fault::unauthorized "Access Denied\nInvalid user or password"
+    }
+    
+    # is this necessary ???
+    ad_user_logout
+    
+    # log user
+    ad_user_login -forever=1 $user_id
+    
+    # return 0
+    return 0	
+}
+
+
+# create logout wrapper for sg services
+ad_proc -public soap::logout {
+} {
+    @author William Byrne
+} {
+    # clear cookies
+    ad_user_logout
+}
+
+
+ad_proc -private soap::method_check {
+    method_id
+} {
+    @param method_id
+} {
+    # exec db
+    set exists [db_string method_exists {} -default 0]
+    
+    # test result
+    if { $exists == 0 || [string is integer $exists] != 1 } {
+	# failed, throw
+	soap::fault::raise "invalid method id: $namespace_id"
+    }
+    # valid
+}
+
+
+ad_proc -public soap::namespace_delete {
+    namespace_id 
+} {
+    @param namespace_id
+} {
+    db_exec_plsql namespace_delete {}		
+}
+
+
+ad_proc -public soap::method_delete {
+    method_id 
+} {
+    @param method_id
+} {
+    # db update
+    db_exec_plsql delete_method {}		
+}
+
+
+ad_proc -public soap::package_id {
+    {-throw 1}
+} {
+    @author William Byrne
+} {
+    # try and get id
+    set pid [apm_package_id_from_key soap-gateway]
+
+    # test 
+    if { $pid != 0 } {
+	# done
+	return $pid
+    }
+
+    # memoize got fed bad stuff - clear it
+    util_memoize_flush_regexp "apm_package_id_from_key_mem soap-gateway"
+
+    # try again
+    set pid [apm_package_id_from_key soap-gateway]
+
+    # test
+    if { $pid != 0 } {
+	# done
+	return $pid
+    }
+
+    # crap - get connection
+    set pid [ad_conn package_id]
+
+    # verify
+    if [string equal [apm_package_key_from_id $pid] soap-gateway] {
+	#done
+	return $pid
+    }	
+
+    # how 'bout the db
+    set pid [db_string select_pid {} -default 0]
+
+    # test
+    if { $pid != 0 } {
+	# done
+	return $pid
+    }
+
+    # throw
+    if [soap::server::lib::true $throw] {
+	soap::fault::raise "Cannot get package id for soap-gateway"	
+    }
+
+    # return error
+    return 0
+}
+
+
+ad_proc -private soap::get {
+    {-set sg_properties}
+    property
+} {
+    @param property
+} {
+    # check set
+    if ![nsv_exists $set $property] {
+	# return empty
+	return {}
+    }
+    
+    # get em
+    return [nsv_get $set $property]
+}
+
+
+ad_proc -private soap::namespace_get_names {
+} {
+    @author William Byrne
+} {
+    # init
+    set names [list]
+
+    # loop through namespaces
+    db_foreach select_services {} { 
+	# append name
+	lappend names $service
+    }
+
+    # return names
+    return $names
+}
+
+
+ad_proc -private soap::query_services {
+    {-unpublished 0}
+    {-published 1}
+    
+} {
+    @author William Byrne
+} {
+    
+    # get active services
+    set services [soap::namespace_get_names]
+    
+    # test for request
+    if $unpublished {
+	# decl unpublished list
+	set unpub [list]
+	
+	# create lower case services
+	set lowercase_services [string tolower $services]
+	
+	# get all namespaces under ::sg
+	foreach service [namespace children ::sg] {
+	    # get child portion of namespace only - skip 
+	    # '::sg::' portion of string
+	    set child [namespace tail $service]
+	    
+	    # search for existing
+	    if { [lsearch $lowercase_services [string tolower $child]] < 0 } {
+		# add to unpublished list
+		lappend unpub $child
+	    }
+	}
+	
+	# want all
+	if $published {
+	    # add to services
+	    return [concat $services $unpub]
+	} else {
+	    # return list
+	    return $unpub
+	}
+    }
+    
+    # return services list
+    return $services
+}
+
+
+ad_proc -private soap::get_idl_help  {
+} {
+    @author William Byrne
+} {
+
+    # return simple instructions
+    set help {
+	<p style="margin-top:4px">
+	Use "C" style function syntax. Data type map:
+	<table width="100%">
+	<tr style="line-height:90%"><td><u><b>Data Type</b></u></td><td><u><b>XML Schema</b></u></td></tr>
+	<tr style="line-height:90%"><td>char, char[], string</td><td>xsd:string</td></tr>
+	<tr style="line-height:90%"><td>int, long</td><td>xsd:int</td></tr>
+	<tr style="line-height:90%"><td>float, double</td><td>xsd:double</td></tr>
+	<tr style="line-height:90%"><td>__int64</td><td>xsd:long</td></tr>
+	<tr style="line-height:90%"><td>void</td><td>-</td></tr>
+	</table>
+	</p>
+    }   
+}
+
+
+ad_proc -private soap::check_symbol {
+    symbol
+} {
+    @param symbol
+} {
+    
+    # setup reg expr
+    set r {(^[^a-zA-Z]*)([a-zA-Z][a-zA-Z0-9_]*)([^a-zA-Z0-9_]*$)}
+    
+    # call
+    set e [regexp $r $symbol {} a b c]
+    
+    # test - requiring symbol not to exceed 64 characters ???
+    if {
+	$e == 0 || 
+	[string length $a] > 0 || 
+	[string length $b] > 64 ||
+	[string length $c] > 0
+    } {
+	# no good
+	soap::fault::raise "Invalid symbol: '$symbol'"
+    }
+}
+
+
+ad_proc -private soap::service_from_uri {
+    uri
+} {
+    @author William Byrne
+} {
+	
+    # expects format similar to that returned 
+    # from soap::wsdl::build_namespace_uri
+	
+    # skip protocol scheme
+    set offset [string first {://} $uri]
+	
+    # found ?
+    if { $offset >= 0 } {
+	# strip scheme
+	set uri [string range $uri [expr $offset + 3] end]
+    }
+    
+    # split sub domains and return first
+    return [llindex [split $uri .] 0]
+}
+
+
+ad_proc -private soap::get_base_url {
+} {
+    @author William Byrne
+} {
+
+    # calc href base
+    set base [ad_conn package_url]
+
+    # verify we're in a soap-gateway site
+    if { ![string equal [ad_conn package_key] "soap-gateway"] } {
+	# force to apm registration
+	set base [apm_package_url_from_key soap-gateway]
+    }
+	
+    # test for problems
+    if { $base == {} } {
+	# force to install mode
+	set base {/soap/}
+    }
+
+    # return it
+    return $base
+}
+
+
+ad_proc -private soap::get_doc_elements {
+    {-service {}}
+    proc
+} {
+    @param proc
+} {
+    # test for service arg
+    if { $service != {} } {
+	# build full path
+	set proc [format "::sg::%s::%s" $service $proc]
+    }
+    
+    # try and get elements
+    if [catch {
+	# try
+	set elements [nsv_get api_proc_doc $proc]
+    }] {
+	# failed - strip off leading namespace qualifier
+	set elements [nsv_get api_proc_doc [string range $proc 2 end]]
+    }
+
+    # return elements
+    return $elements
+}
+
+
+ad_proc -private soap::get_source_procs {
+    {-private 0}
+    {-local 0}
+    service
+} {
+    Returns a list of procedures within the tcl namespace
+    formulated by sg::<service>::*
+
+    @param service
+} {
+    # decl unpublished list
+    set procs [list]
+
+    # safe fetch
+    catch {
+	# get methods
+	set procs [info commands [format "::sg::%s::*" $service]]
+    }
+
+    # decl result
+    set result [list]
+
+    # loop through source procs
+    foreach proc $procs {
+
+        # test for public
+        set public 0
+
+	# safe
+	catch {
+
+	    # get proc doc elements
+	    array set doc_elements [nsv_get api_proc_doc \
+                [string range $proc 2 end]]
+
+	    # assign
+	    set public $doc_elements(public_p)
+	}
+
+	# test
+	if { $public || $private } {
+	    # test for local (no namespace)
+	    if [soap::server::lib::true $local] {
+		# get last element after ::	
+		regexp {([^:]+$)} $proc {} proc
+	    }
+	    # add to list
+	    lappend result $proc
+	}
+    }
+
+    # return procs
+    return $result
+}
+
+
+ad_proc -private soap::get_source_idl {
+    proc
+} {
+    Returns the idl of a procedure. If the procedure exists,
+    an attempt is made to return @idl description. If @idl doesn't
+    exists, the idl is formulated from the procedures args. If 
+    the procedure doesn't exists, an empty value is returned.
+    
+    @param proc
+} {
+    # build formal name
+    set formal $proc; #[format "::sg::%s::%s" $service $proc]
+    
+    # verify
+    if { [info commands $formal] == {} } {
+	# let's return empty string to signal error
+	soap::fault::raise "Cannot get idl for invalid procedur: $proc"
+    }
+    
+    # decl idl 
+    set idl {}
+    
+    # safe 
+    catch {
+	# get the documentenation array	for the method
+	array set doc_elements [soap::get_doc_elements $formal]
+		
+	# get the @idl value and remove curlies via 'join'
+	set idl [join $doc_elements(idl)]
+    }
+    
+    # test idl
+    if { $idl == {} } {
+	
+	# build from tcl info
+		
+	# decl temp
+	set args2 {}
+	
+	# the default idl will always return a string
+	# and each arg will be type string
+	foreach arg [info args $formal] {
+	    
+	    # first time
+	    if { $args2 == {} } {
+		# assign
+		set args2 "string $arg"
+	    } else {
+		# add to 
+		append args2 ", string $arg"
+	    }
+	}
+	
+	# remove namespace from proc
+	set proc [namespace tail $proc]
+
+	# finish
+	set idl [format "string %s(%s)" $proc $args2]
+    }
+
+    # return whatever we got
+    return $idl
+}
+
+
+ad_proc -private soap::get_source_idls {
+    service
+} {
+    Returns a list of idls for public procedures defined
+    within the sg::<service>:: namespace.
+    
+    @see soap::get_source_idl
+    @param service
+} {
+    # get source procs for service
+    set procs [soap::get_source_procs $service]
+    
+    # decl result list
+    set result [list]
+    
+    # loop though procs
+    foreach proc $procs {
+        # get idl for proc
+	lappend result [soap::get_source_idl $proc]
+    }
+
+    # return list
+    return $result
+}
+
+
+ad_proc -private soap::method_get_procs {
+    namespace_id
+} {
+    @param namespace_id
+} {
+    # init
+    set procs [list]
+
+    db_foreach select_procs {} { 
+	# append method proc
+	lappend procs $proc
+    }
+
+    # return methods
+    return $procs
+}
+
+
+ad_proc -private soap::diff_methods {
+    {-same 0}
+    service
+} {
+    Compares the published service methods to those in the source file
+    @param service
+} {
+    # decl unpublished list
+    set procs [soap::get_source_procs $service]
+    
+    # decl published list
+    set methods [list]
+    set idls [list]
+    
+    # get namespace id
+    set nid [soap::server::namespace_get_id $service]
+    
+    # verify
+    if { $nid >= 0 } {
+	
+	# get published method Tcl proc bindings (proc symbol in db);
+	set bindings [soap::method_get_procs $nid]	
+	
+	# and their idls
+	set idls [soap::wsdl::method_get_idls $nid]
+    }
+    
+    # decl history list
+    set history [list]
+    
+    # decl diff array
+    array set diffs [list]
+    
+    # decl short names list for procs
+    set shorts [list]
+    
+    # get idl parser expression for method - "C" syntax
+    set method_expr [soap::wsdl::get_style_parser_expr C]
+    set arg_expr [soap::wsdl::get_style_parser_expr -argpart 1 C]
+    
+    # decl published list
+    set published [list]
+    
+    # duplicate procs as they're duplicated in the WSDL 
+    # database - this will ensure
+    # every entry in the database is tested. ??? weak
+    
+    # decl dups
+    set dups [list]
+    
+    # scan
+    foreach proc $procs {
+			 
+        # trim proc name
+	set short [namespace tail $proc]
+			 
+	# decl counter
+	set count 0
+
+	# get hits in db
+	foreach binding $bindings {
+	    
+	    # compare
+	    if [string equal $binding $short] {
+		
+		# incr counter
+		incr count
+		
+		# test for more than 1
+		if { $count > 1 } {
+		    
+		    # add dup
+		    lappend dups $proc
+		}
+	    }
+	}
+    }
+    
+    # update proc list with duplicated db method entries
+    foreach dup $dups {
+	# add to proc list
+	lappend procs $dup
+    }
+    
+    # loop through source procs
+    foreach proc $procs {
+			 
+        # trim proc name
+	set short [namespace tail $proc]
+	
+	# decl found 
+	set found {}
+	
+	# decl diff var
+	set diff {}
+	
+	# get args for source proc (unpublished?)
+	set src_idl [soap::get_source_idl $proc]; #[info args $proc]
+	
+	# decl uargs (unpublished)
+	set uargs {}
+	
+	# invoke regexp to get args
+	if [regexp $method_expr $src_idl {} type src_meth argz] {
+	    
+	    # loop through args
+	    foreach arg [split $argz ,] {
+		
+		# split
+		if [regexp $arg_expr $arg {} type name] {
+		    
+		    # add to list
+		    lappend uargs $name
+		}
+	    }
+	} else {
+	    # store for check below
+	    set src_meth $short
+	}
+	
+	# search published
+	foreach binding $bindings idl $idls {
+	    
+	    # try
+	    if [catch {
+		
+		# test for case sensitive match
+		if [string equal $short $binding] {
+		    
+		    # decl pargs
+		    set pargs [list]
+		    
+		    # invoke regexp to get args
+		    if [regexp $method_expr $idl {} type method argz] {
+			
+			# loop through args
+			foreach arg [split $argz ,] {
+			    
+			    # split
+			    if [regexp $arg_expr $arg {} type name] {
+
+				# add to list
+				lappend pargs $name
+			    }
+			}
+			
+			# park idl method name into found - used below
+			#set found $meth
+		    } else {
+			# egats
+			continue
+		    }
+		    
+		    # set found indicator
+		    set found $method
+		    
+		    # compare unpublished args against published args
+		    
+		    # compare
+		    if { [llength $uargs] != [llength $pargs] } {
+			
+			# note difference
+			set diff [list $uargs $pargs]
+			
+		    } else {
+			
+			# compare arg names
+			foreach u $uargs p $pargs {
+			    
+			    # compare
+			    if ![string equal -nocase $u $p] {
+				
+				# note difference
+				set diff [list $uargs $pargs]
+				
+				# enough to note diff
+				break
+			    }
+			}
+		    }
+
+		    # add to published list
+		    lappend published $binding
+
+		    # get idx of binding
+		    set idx [lsearch $bindings $binding]
+
+		    # remove from db lists
+		    set bindings [lreplace $bindings $idx $idx]
+		    set idls [lreplace $idls $idx $idx]
+		    set methods [lreplace $methods $idx $idx]
+		}
+	    } msg] {
+		
+		# show error for diff
+		set diff "err $msg"
+	    }
+
+	    # test found
+	    if { $found != {} } {
+		# stop scanning bindings for match - we found it
+		break
+	    }
+	}	
+
+	# found ?
+	if { $found != {} } {
+
+	    # upper case found
+	    set ufound [string toupper $found]
+
+	    # check for duplicate
+	    if { [lsearch $history $ufound] >= 0 } {
+		# mark as duplicate
+		set diffs($found) [list DUPL $uargs $pargs]
+	    } else {
+		# differences ?
+		if { $diff != {} } { 
+		    # append to results list
+		    set diffs($found) [list ARGS $uargs $pargs]
+		} elseif [soap::server::lib::true $same] {
+		    # append procs that are identical - 'same' flag set
+		    set diffs($found) [list SAME $uargs $pargs]
+		}
+
+		# add to history
+		lappend history $ufound
+	    }
+	} else {
+
+	    # upper case 
+	    set found [string toupper $src_meth]
+
+	    # use full proc name to avoid potential clash
+	    # with any db methods of same name
+
+	    # check for duplicate
+	    if { [lsearch $history $found] >= 0 } {
+		# mark as duplicate
+		set diffs($proc) [list DUPL $uargs {}]
+	    } else {
+		# append missing - modify array key to avoid
+		# clash with db method of same name
+		set diffs($proc) [list UPUB $uargs {}]
+
+		# add to history
+		lappend history $found
+	    }
+	}
+    }
+
+    # add remaining bindings
+    foreach binding $bindings idl $idls {
+	
+	# invoke regexp to get args
+	if [regexp $method_expr $idl {} type method argz] {
+
+	    # decl pargs
+	    set pargs [list]
+
+	    # loop through args
+	    foreach arg [split $argz ,] {
+		# split
+		if [regexp $arg_expr $arg {} type name] {
+		    # add to list
+		    lappend pargs $name
+		}				
+	    }
+	    
+	    # append missing
+	    set diffs($method) [list ORPH {} $pargs]
+	    
+	} else {
+	    
+	    # append error
+	    set diffs($binding) [list ERR {} {}]
+	}
+    }
+    
+    #return differences
+    return [array get diffs]
+}
+
+
+ad_proc -private soap::namespace_check {
+    namespace_id
+} {
+    @param namespace_id
+} {
+    # exec db
+    set exists [db_string namespace_exists {} -default 0]
+    
+    # test result
+    if { $exists == 0 || [string is integer $exists] != 1 } {
+	# failed, throw
+	soap::fault::raise "invalid namespace id: $namespace_id"
+    }
+    # valid
+}
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/tcl/soap-server-lib-procs-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/tcl/soap-server-lib-procs-postgresql.xql,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/tcl/soap-server-lib-procs-postgresql.xql	17 Oct 2004 05:51:53 -0000	1.1
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+
+<queryset>
+  <rdbms><type>postgresql</type><version>7.1</version></rdbms>
+
+  <fullquery name="soap::server::lib::library_get_paths.select_lib_paths">
+    <querytext>
+      select path from sg_libraries;
+    </querytext>
+  </fullquery>
+
+  <fullquery name="soap::server::lib::method_new.method_new">
+    <querytext>
+      select sg_method__new(
+        :namespace_id,
+	:method,
+	:idl,
+	:idl_style,
+	:proc,
+	:notes,
+	now(),
+	:user_id,
+	:peeraddr,
+	:package_id
+      );
+      </querytext>
+</fullquery>
+
+  <fullquery name="soap::server::lib::namespace_new.namespace_new">
+    <querytext>
+      select sg_namespace__new (
+        :service,
+        :uri,
+	:notes,
+	now(),
+	:user_id,
+	:peeraddr,
+	:package_id
+	) from dual;
+    </querytext>
+  </fullquery>
+
+  <fullquery name="namespace_update">      
+    <querytext>
+      select sg_namespace__update(
+        :namespace_id,
+	:service,
+	:uri,
+	:notes,
+      ) from dual;
+    </querytext>
+  </fullquery>
+
+  <fullquery name="soap::server::lib::import_service.namespace_select">      
+    <querytext>
+      select service, uri, notes 
+        from sg_namespaces
+	where namespace_id = :nid
+    </querytext>
+  </fullquery>
+
+  <fullquery name="soap::server::lib::method_update.method_update">      
+    <querytext>
+
+    </querytext>
+  </fullquery>
+
+  <fullquery name="soap::server::lib::library_new.library_new">      
+    <querytext>
+        select sg_library__new(:path) from dual
+    </querytext>
+  </fullquery>
+
+  <fullquery name="soap::server::lib::library_get_path.select_path">      
+    <querytext>
+      select path
+        from sg_libraries
+        where library_id = :library_id
+    </querytext>
+  </fullquery>
+
+  <fullquery name="soap::server::lib::library_delete.delete_library">
+    <querytext>
+        select 0 + sg_library__delete(:library_id)
+    </querytext>
+  </fullquery>
+
+  <fullquery name="soap::server::lib::library_update.update_library">      
+    <querytext>
+        select 0 + sg_library__update(:library_id,:path)
+    </querytext>
+  </fullquery>
+
+</queryset>
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/tcl/soap-server-lib-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/tcl/soap-server-lib-procs.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/tcl/soap-server-lib-procs.tcl	17 Oct 2004 05:51:53 -0000	1.1
@@ -0,0 +1,624 @@
+ad_library {
+
+    SOAP API for registering and handling TCL services located in the
+    library directory.
+    
+    @author William Byrne (WilliamB@ByrneLitho.com)
+    @author Nick Carroll (ncarroll@ee.usyd.edu.au)
+}
+
+
+namespace eval soap::server::lib {}
+
+
+ad_proc -public soap::server::lib::library_new {
+    path
+} {
+    @param path
+} {
+    db_exec_plsql library_new {}
+}
+
+
+ad_proc -public soap::server::lib::library_update {
+    library_id 
+    path 
+} {
+    @param library_id
+    @param path
+} {
+    db_exec_plsql update_library {}
+}
+
+ad_proc -public soap::server::lib::library_delete {
+    library_id 
+} {
+    @param library_id
+} {
+    db_exec_plsql delete_library {}		
+}
+
+
+ad_proc -public soap::server::lib::library_get_path {
+    library_id 
+} {
+    @param library_id
+} {
+    set path [db_string select_path {} -default {} ]	
+    
+    # return
+    return $path
+}
+
+
+ad_proc -private soap::server::lib::is_library_valid {
+    library
+} {
+    @param library
+} {
+
+    # get root without tail /
+    set root [file join [acs_root_dir]]
+
+    # test for directory
+    if [file isdirectory [file join $root $library]] {
+	# append wildcard
+	set library [file join $library *.tcl]
+    }
+
+    # scan  glob list
+    foreach f [glob -nocomplain -directory $root $library] {
+	# verify extension
+	if ![string equal -nocase [file extension $f] {.tcl}] {
+	    # skip it
+	    continue
+	}
+	# yup
+	return 1	
+    }
+    # clean
+    return 0
+}
+
+ad_proc -private soap::server::lib::is_library_dirty {
+    library
+} {
+    @author William Byrne
+} {
+    # get root without trailing /
+    set root [file join [acs_root_dir]]
+
+    # get len + 1 for eventual /
+    set len [expr [string length $root] + 1]
+
+    # test for directory
+    if [file isdirectory [file join $root $library]] {
+	# append wildcard
+	set library [file join $library *.tcl]
+    }
+
+    # scan  glob list
+    foreach f [glob -nocomplain -directory $root $library] {
+	# verify extension
+	if ![string equal -nocase [file extension $f] {.tcl}] {
+	    # skip it
+	    continue
+	}
+
+	# get mtime
+	set mtime [file mtime $f]
+
+	# get short
+	set short [string range $f $len end]
+
+	# check to see if registered in loader
+	if ![nsv_exists apm_reload_watch $short] {
+	    # remove from mtime
+	    catch { nsv_unset apm_library_mtime $short }
+	}
+
+	# get property without root
+	set cached [soap::get -set apm_library_mtime $short]
+
+	# test
+	if { $cached == {} || $mtime != $cached } {
+	    # dirty
+	    return 1
+	}
+    }
+    # clean
+    return 0
+}
+
+
+ad_proc -private soap::server::lib::library_get_paths {
+} {
+    @author William Byrne
+} {
+    # init
+    set paths [list]
+
+    # loop through libraries
+    db_foreach select_lib_paths {} { 
+	# append name
+	lappend paths $path
+    }
+    
+    # return names
+    return $paths
+}
+
+
+ad_proc -public soap::server::lib::update_libraries {
+    {-stop 0}
+    {libraries [list]}
+} {
+    @author William Byrne
+} {
+    # get root without trailing /
+    set root [file join [acs_root_dir]]
+
+    # get len + 1 for eventual /
+    set len [expr [string length $root] + 1]
+    
+    # loop through libraries
+    foreach lib $libraries {
+
+	# test for directory
+	if [file isdirectory [file join $root $lib]] {
+	    # append wildcard
+	    set lib [file join $lib *.tcl]
+	} elseif ![string equal -nocase [file extension $lib] {.tcl}] {
+	    # skip it
+	    continue
+	}
+
+	# scan  glob list
+	foreach f [glob -nocomplain -directory $root $lib] {
+	    # add to watch without root
+	    soap::server::lib::watch -stop $stop [string range $f $len end]
+	}
+    }
+    # return something
+    return 1
+}
+
+
+ad_proc -private soap::server::lib::true {
+    value
+} {
+    @author William Byrne
+} {
+    # handle ints > 1 || < 0
+    if [string is integer $value] {
+	# eval
+	return [expr $value != 0 ? 1 : 0]
+    }
+
+    # empty value is false
+    return [expr [string length $value] > 0 && [string is true $value] ? 1 : 0]
+}
+
+
+ad_proc -public soap::server::lib::watch {
+    {-stop 0}
+    file
+} {
+    @author William Byrne
+} {
+    # setup result
+    set result 1
+
+    # test for stop
+    if [soap::server::lib::true $stop] {
+	# safe
+	if [catch {
+	    # stop watch
+	    nsv_unset apm_reload_watch $file
+	}] {
+	    # egats
+	    set result 0
+	}
+	# safe
+	catch {
+	    # remove cache
+	    nsv_unset apm_library_mtime $file
+	}
+
+    } else {
+	# add
+	apm_file_watch $file	
+    }
+
+    # return status
+    return $result
+}
+
+
+ad_proc -public soap::server::lib::boot_libraries {
+} {
+    @author William Byrne
+} {
+    # get paths
+    set paths [soap::server::lib::library_get_paths]
+
+    # send to update
+    foreach lib $paths {
+        soap::server::lib::update_libraries $lib
+    }
+
+    # return something
+    return 1
+}
+
+
+ad_proc -private soap::server::lib::get_library_doc {
+    service
+} {
+    @param service
+} {
+    # get a command from namespace
+    set procs [info commands [format "::sg::%s" $service]]
+    
+    # decl source path
+    set path {}
+    
+    # any ?
+    if [llength $procs] {
+	# get first one
+	set proc [lindex $procs 0]
+
+	# safe 
+	catch {
+	    # get the documentenation array	for the method
+	    array set doc_elements [nsv_get api_proc_doc \
+                [format "::sg::%s::%s" $service $proc]]
+	    
+	    # get script path
+	    set path $doc_elements(script)
+	}
+    }
+    
+    # check path
+    if { $path == {} } {
+	
+	# try lib directory
+	set path "packages/soap-gateway/lib/[string tolower $service]-procs.tcl"	
+    }
+
+    # decl result
+    set result {}
+    
+    # try to get doc info from file
+    catch {
+	# get source file docs - force lower case convention
+	array set doc_elements [nsv_get api_library_doc $path]
+	
+	# update and remove curlies
+	set result [join $doc_elements(main)]
+    }			
+
+    # return whatever we got
+    return $result
+}
+
+
+ad_proc -public soap::server::lib::method_new {
+    namespace_id 
+    method 
+    idl 
+    idl_style 
+    proc
+    notes 
+    user_id 
+    peeraddr 
+    package_id
+} {
+    @param namespace_id 
+    @param method 
+    @param idl 
+    @param idl_style 
+    @param proc
+    @param notes 
+    @param user_id 
+    @param peeraddr 
+    @param package_id
+} {
+    # create new  - 
+    db_exec_plsql method_new {}
+}
+
+
+ad_proc -public soap::server::lib::namespace_new {
+	service 
+	uri 
+	notes 
+	user_id 
+	peeraddr 
+	package_id
+} {
+    @param service
+    @param uri
+    @param notes
+    @param user_id
+    @param peeraddr
+    @param package_id
+} {
+    # db new 
+    db_exec_plsql namespace_new {}
+}
+
+
+ad_proc -public soap::server::lib::namespace_update {
+    namespace_id 
+    service 
+    uri 
+    notes
+} {
+    @param namespace_id 
+    @param service 
+    @param uri 
+    @param notes
+} {
+    db_exec_plsql namespace_update {}
+}
+
+
+ad_proc -private soap::server::lib::get_proc_doc {
+    proc
+} {
+    @param proc
+} {
+    # decl result
+    set result {}
+    
+    # safe
+    catch {
+	
+	# remove sg namespace
+	if { [string equal -length 6 ::sg:: $proc] } {
+	    # trim ::
+	    set proc [string range $proc 2 end]
+	}
+	
+	# get doc set for procedure
+	array set doc_elements [nsv_get api_proc_doc $proc]
+	
+	# get main documentation and remove curlies
+	set result [join $doc_elements(main)]
+    }
+    
+    # return procedure doc
+    return $result
+}
+
+
+ad_proc -private soap::server::lib::idl_to_xsd { 
+    style
+    idl
+} {
+    @param style
+    @param idl
+} {
+    # verify style
+    if { [string compare -nocase $style "C"] != 0 } {
+
+	# not yet supported
+	soap::fault::unsupported "Unsupported IDL style: $style\n Use 'C'"
+	
+    }
+
+    # set up regexp expression for "C" style function 
+    set expr [soap::wsdl::get_style_parser_expr C]
+	
+    # invoke regexp
+    regexp $expr $idl {} type method argz
+
+    # map type
+    set xtype [soap::wsdl::map_ctype_to_xtype $type]
+
+    # verify
+    if { [llength $xtype] > 1 } {
+
+	# not yet supported
+	soap::fault::unsupported "cannot spec non simple types: $type"
+	
+    }
+
+    # setup arg list
+    set xargs [list]
+
+    # get arg parser expr
+    set expr [soap::wsdl::get_style_parser_expr -argpart 1 C]
+	
+    # loop through args
+    foreach a [split $argz ,] {
+		
+	# split arg type from its name
+	if ![regexp $expr $a {} typ nam] {
+	    
+	    # format problem
+	    error "unexpected argument format: $a"
+	    
+	}
+		
+	# add arg to param order var
+	lappend order $nam
+		
+	# map type
+	set xtype2 [soap::wsdl::map_ctype_to_xtype $typ]
+	
+	# get component count
+	set cnt [llength $xtype2]
+	
+	# test for simple
+	if { $cnt == 1 } {
+	    
+	    # append to arg list
+	    lappend xargs [list [lindex $xtype2 0] $nam]
+	    
+	} else {
+	    
+	    # not yet supported
+	    soap::fault::unsupported "cannot spec non simple types: $a, $xtype2"
+	}
+    }
+
+    # build return
+    return [list $xtype $method $xargs]
+}
+
+
+ad_proc -public soap::server::lib::method_update {
+    method_id 
+    method 
+    idl 
+    idl_style 
+    proc
+    notes
+} {
+    @param method_id 
+    @param method 
+    @param idl 
+    @param idl_style 
+    @param proc
+    @param notes
+} {
+    # update existing
+    db_exec_plsql method_update {}
+}
+
+
+ad_proc -private soap::server::lib::import_service {
+    {-force 0}
+    {-proc {}}
+    service
+} {
+    @param service
+} {
+    # set connection vars
+    set user_id [ad_conn user_id]
+    set peeraddr {}
+    set package_id [ad_conn package_id]
+    
+    # verify workspace namespace
+    set nid [soap::server::namespace_get_id $service]
+    
+    # test
+    if { $nid == -1 } {
+	
+	# get doc
+	set notes [soap::server::lib::get_library_doc $service]
+	
+	# create
+	soap::server::lib::namespace_new \
+            $service "http://$service.openacs.org/methods" \
+            $notes $user_id $peeraddr $package_id
+	
+	# clear
+	unset notes
+	
+	# get id
+	set nid [soap::server::namespace_get_id $service]
+	
+    } elseif { $force } {
+	
+	# query for namespace attributes
+	db_1row namespace_select {}
+	
+	# get doc
+	set notes [soap::server::lib::get_library_doc $service]
+	
+	# update with new notes
+	soap::server::lib::namespace_update $nid $service $uri $notes	
+    }
+    
+    # get public procs for namespace
+    
+    # set method parameters - idl style
+    set idl_style {C}
+    
+    # build procs list
+    set procs [soap::get_source_procs $service]
+    
+    # test for optional proc arg
+    if { $proc != {} } {
+	
+	# test for ns qualifier ??? (weak)
+	if ![string equal -length 6 $proc {::sg::}] {
+	    # fix up
+	    set proc [format "::sg::%s::%s" $service $proc]
+	}
+	
+	# contained in list
+	if { [lsearch -exact $procs $proc] >= 0 } {
+	    # use
+	    set procs [list $proc]
+	} else {
+	    # clear, not found
+	    set procs [list]
+	}
+    }
+
+    # loop
+    foreach proc $procs {
+        # get idl
+	set idl [soap::get_source_idl $proc]
+
+	# get notes
+	set note [soap::server::lib::get_proc_doc $proc]
+	
+	# try
+	if [catch {
+	    # decompose IDL
+	    set xsd [soap::server::lib::idl_to_xsd $idl_style $idl]
+	} msg] {
+	    # report
+	    soap::fault::raise "Error importing: $proc, idl: $idl\n$msg"
+	}
+	
+	# get method name from idl
+	set method [lindex $xsd 1]
+	
+	# remove namespace
+	set proc [namespace tail $proc]
+	
+	# verify workspace method
+	set mid [soap::wsdl::method_get_id $nid $method]
+	
+	# test
+	if { $mid == -1 } {
+	    # create
+	    soap::server::lib::method_new $nid $method $idl $idl_style \
+                          $proc $note $user_id $peeraddr $nid
+	    
+	    # test for 'login'
+	    if [string equal -nocase $method "LOGIN"] {
+		# get method id		
+		set mid [soap::wsdl::method_get_id $nid $method]
+		
+		# verify
+		soap::fault::assert {$mid != -1} "Error retrieving 'login' method id: $method => $mid"
+		
+		# get public
+		set public_id [acs_magic_object the_public]
+		
+		# get invoke symbol
+		set invoke [soap::server::get_invoke_permission_moniker]
+		
+		# grant invoke permission to public
+		permission::grant -party_id $public_id -object_id $mid -privilege $invoke
+
+		# verify
+		set ok [permission::permission_p -party_id $public_id -object_id $mid -privilege $invoke]
+		soap::fault::assert $ok "Error granting '$invoke' permission to public"
+	    }
+	} elseif { $force } {
+	    # update
+	    error "soap::server::lib::method_update $mid $method $idl $idl_style $proc $note"
+	}
+    }
+
+    # return namespace id
+    return $nid   
+}
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/tcl/soap-server-procs-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/tcl/soap-server-procs-postgresql.xql,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/tcl/soap-server-procs-postgresql.xql	17 Oct 2004 05:51:53 -0000	1.1
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+
+<queryset>
+  <rdbms><type>postgresql</type><version>7.1</version></rdbms>
+
+  <fullquery name="soap::server::namespace_get_id.namespace_id">
+    <querytext>
+      select sg_namespace__get_id(:service) from dual
+    </querytext>
+  </fullquery>
+
+  <fullquery name="soap::server::service_name_exists_p.service_name">
+    <querytext>
+      select sg_namespace__get_id(:service) from dual
+    </querytext>
+  </fullquery>
+
+  <fullquery name="soap::server::method_get_id_and_proc.method_id_proc">
+    <querytext>
+      select method_id || ' ' || proc
+        from sg_methods
+	where namespace_id = :namespace_id and
+	lower(method) = lower(:method)
+    </querytext>
+  </fullquery>
+
+  <fullquery name="soap::server::get_invoke_permission_moniker.select_moniker">
+    <querytext>
+      select * from sg_invoke_moniker
+    </querytext>
+  </fullquery>
+</queryset>
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/tcl/soap-server-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/tcl/soap-server-procs.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/tcl/soap-server-procs.tcl	17 Oct 2004 05:51:54 -0000	1.1
@@ -0,0 +1,425 @@
+ad_library {
+    Tcl API for a SOAP Server.
+
+    Based on William Byrne's soap-gateway implementation.
+
+    @author William Byrne (WilliamB@ByrneLitho.com)
+    @author Nick Carroll (ncarroll@ee.usyd.edu.au)
+    @creation-date 2004-09-24
+    @cvs-id $Id: soap-server-procs.tcl,v 1.1 2004/10/17 05:51:54 ncarroll Exp $
+}
+
+namespace eval soap::server {}
+
+ad_proc -public soap::server::get_version_namespace {
+    ver
+} {
+    Returns the namespace for the specified SOAP version.
+
+    @param ver A SOAP version, eg 1.1 or 1.2.
+    @return Returns the namespace associated with the specified
+    version of SOAP.
+} {
+
+    switch $ver {
+	1.1 {
+	    # Namespace for SOAP 1.1
+	    return [parameter::get -parameter "SOAP_NS_1_1"]
+	}
+	1.2 {
+	    # Namespace for SOAP 1.2
+	    return [parameter::get -parameter "SOAP_NS_1_2"]
+	}
+    }
+
+    # return 1.1 as safety
+    return [parameter::get -parameter "SOAP_NS_1_1"]
+}
+
+ad_proc -public soap::server::get_version_encoding {
+    ver
+} {
+    Returns the encoding for the specified SOAP version.
+
+    @param ver A SOAP version, eg 1.1 or 1.2.
+    @return Returns the encoding associated with the specified
+    version of SOAP.
+} {
+    switch $ver {
+	1.1 {
+	    return [parameter::get -parameter "SOAP_ENC_1_1"]
+	}
+	1.2 {
+	    return [parameter::get -parameter "SOAP_ENC_1_2"]
+	}
+    }
+
+    # return 1.1 as safety
+    return [parameter::get -parameter "SOAP_ENC_1_1"]
+}
+
+ad_proc -public soap::server::get_url_params {
+} {
+    @author William Byrne
+} {
+    # try to get from target url
+    set request [ns_conn request]
+
+    # search for ?
+    set offset [string first "?" $request]
+	
+    # test
+    if { $offset >= 0 } {
+
+	# fixup offset
+	incr offset
+	
+	# find first space after query
+	set last [string first " " $request $offset]
+	
+	# fixup
+	if { $last < 0 } { 
+	    set last end 
+	} else { 
+	    incr last -1
+	}
+	
+	# get query
+	set query [string range $request $offset $last]
+		
+    } else {
+	# clear
+	set query {}		
+    }
+    # return params as ns_set
+    return [ns_parsequery $query]
+}
+
+ad_proc -public soap::server::get_url_param {
+    param
+} {
+    @author William Byrne
+} {
+    # get params
+    set params [soap::server::get_url_params]
+
+    # return requested
+    return [ns_set get $params $param]
+}
+
+ad_proc -public soap::server::has_permission {
+    {-user_id {}}
+    object_id
+    privilege
+} {
+    @param object_id
+    @param privilege
+} {
+    # test user 
+    if { $user_id == {} } {
+	# set to current user
+	set user_id [ad_conn user_id]
+    }
+
+    # return permission cache
+    return [permission::permission_p -party_id $user_id \
+            -object_id $object_id -privilege $privilege]
+}
+
+ad_proc -public soap::server::require_permission {
+    object_id
+    privilege
+} {
+    @param object_id
+    @param privilege
+} {
+    # check permission cache
+    if { ![soap::server::has_permission $object_id $privilege] } {
+        # deny
+	return [soap::fault::generate_error "Unauthorized: Access Denied"]
+    }
+}
+
+ad_proc -public soap::server::invoke {
+    env
+} {
+    Take the SOAP request and invoke the method on the server.
+
+    @param env The SOAP envelope sent from the client.
+    @return result wrapped in a SOAP response envelope and returned
+    to the client.
+} {
+
+    # Invoke in safe block
+    if {[catch {set result [soap::server::do_invoke $env]} err_msg]} {
+	# build fault
+	set result [soap::fault::generate_fault $err_msg]
+    }
+
+    # return envelope
+    return $result
+}
+
+
+ad_proc -private soap::server::do_invoke {
+    env
+} {
+    Parses the specified SOAP envelope for methods, and invokes these
+    methods with the supplied arguments.  The results (if any) are
+    returned to the invoking client as a SOAP response.
+
+    @param env The SOAP envelope to parse for methods to invoke.
+    @return Returns a SOAP response for the invoking client.
+} {
+    # force to v1.1
+    set ver 1.1
+        
+    # set encoding style  
+    set encoding [soap::server::get_version_encoding $ver]
+
+    # set envelope version
+    set version [soap::server::get_version_namespace $ver]
+
+    # parse incoming soap envelope
+    set doc [dom parse $env] 
+
+    # LOG SOAP Request
+    ns_log Notice "\nSOAP Request:\n[$doc asXML]"
+
+    # get doc root
+    set root [$doc documentElement]
+
+    # get child nodes of Envelope
+    set children [$root childNodes]
+
+    # decl method for response
+    set method {}
+    set result {}
+
+    # Brute force envelope search is performed in place of 
+    # preferred XPath search. I ran into issues that were complicated 
+    # by the fact that XPath was not available on a
+    # baseline installation. The goal is to demonstrate SOAP interop 
+    # and not necessarily write the ideal implementation. Furthermore, 
+    # if the envelope exists within XML, it
+    # should be found quickly.
+    
+    # decl mustUnderstand list
+    set misunderstood {}
+	
+    set header [$root selectNodes /SOAP-ENV:Envelope/SOAP-ENV:Header]
+
+    # test for header
+    if ![empty_string_p $header] {
+
+	# get requisites
+	set reqs [$header childNodes]
+	    
+	# loop
+	foreach r $reqs {
+	    
+	    # look for must understand
+	    set mu [$r getAttribute mustUnderstand]
+	    
+	    # test 
+	    if { $mu == "1" || [string equal -nocase $mu true] } {
+		
+		# don't understand anything other than 
+		# basics right now
+		# add to list - should be qnames with namespaces??
+		lappend misunderstood [list $r {}]
+	    }
+	}
+    }
+
+    set body [$root selectNodes /SOAP-ENV:Envelope/SOAP-ENV:Body]
+
+    # test for body
+    if ![empty_string_p $body] {
+	    
+	# before proceeding, make sure "misunderstood" var is clear
+	if { $misunderstood != {} } {
+	    
+	    # return misunderstood fault
+	    return [soap::fault::generate_misunderstood $misunderstood]
+	    
+	}
+	
+	# get methods
+	set methods [$body childNodes]
+	
+	# loop
+	foreach m $methods {
+	    
+	    # get node type
+	    set type [$m nodeType]
+	    
+	    # test for element - skip cdata (axis)
+	    if { [string equal -nocase $type "cdata_section"] } {
+		# skip 
+		continue
+	    }
+	    
+	    # get method namespace
+	    set service {};
+	    
+	    # verify
+	    if { $service == {} } {
+		# parse connection url and see if it's there
+		set service [soap::server::get_url_param service]
+	    }
+	    
+	    # get service/namespace id
+	    set nid [soap::server::namespace_get_id $service]
+	    
+	    # verify
+	    if { $nid < 0 } {
+		# not found
+		return [soap::fault::generate_error "Error: $namespace not found"]
+	    }
+	    
+	    # get method
+	    set method [$m nodeName]
+	    
+	    # authenticate
+	    
+	    # get method id and proc
+	    set id_proc [soap::server::method_get_id_and_proc $nid $method]
+	    
+	    # get id
+	    set mid [lindex $id_proc 0]
+	    
+	    # get proc
+	    set proc [lindex $id_proc 1]
+	    
+	    # verify
+	    if { $mid < 0 } {
+		# throw
+		set error_msg [format "Invalid service method: '%s:%s'" \
+                               $service $method]
+		return [soap::fault::generate_error "Error: $error_msg"]
+	    }
+
+### Get this working!	    
+	    # try authenticating to method
+####	    soap::server::require_permission $mid [soap::server::get_invoke_permission_moniker]
+	    
+	    # build namespace into expr
+	    set expr "sg::"
+	    
+	    # append namespace and proc
+	    append expr $service :: $proc
+	    
+	    # get args
+	    set args [$m childNodes]
+	    
+	    # loop
+	    foreach a $args {
+		# get node type
+		set text_node [$a firstChild]
+		lappend expr [$text_node nodeValue]
+	    }
+
+	    # invoke - error will be caught by 
+	    # caller and returned as fault
+	    set result [eval $expr]
+
+	    # done
+	    break
+	}
+    }
+    
+    return [soap::server::response $version $encoding $method $result]
+}
+
+ad_proc -private soap::server::response {
+    version
+    encoding
+    method
+    result
+} {
+    Constructs a SOAP response based on the specified result and method.
+
+    @param version The version of SOAP.
+    @param encoding The encoding used for the version of SOAP specified.
+    @param method Method name.
+    @param result Result to return to the SOAP client.
+    @return Returns a SOAP response envelope.
+} {
+    # construct xml doc object
+    set doc [dom createDocument env:Envelope]
+    
+    # create root node: "env:Envelope"
+    set env [$doc documentElement]
+    
+    # define namespace atts into node
+    $env setAttribute xmlns:env $version
+
+    # define encoding style atts into node
+    $env setAttribute env:encodingStyle $encoding
+
+    # create SOAP header - "env:Envelope/env:Header"
+    set header [$env appendChild [$doc createElement env:Header]]
+    
+    # create SOAP body - "env:Envelope/env:Body"
+    set body [$env appendChild [$doc createElement env:Body]]
+        
+    # create method node - "env:Envelope/env:Body/?method?"
+    set method_node [$body appendChild [$doc createElement [format "m:%s%s" $method Response]]]
+    
+    # define namespace atts into node
+    $method_node setAttribute xmlns:m {http://namespace}; # need real namespace
+    
+    # create args node - "env:Envelope/env:Body/?method?/?arg?"
+    set result_node [$method_node appendChild [$doc createElement Result]]
+    set args [$result_node appendChild [$doc createTextNode $result]]
+
+    # LOG SOAP Response
+    ns_log Notice "\nSOAP Response:\n[$doc asXML]"
+
+    # render xml into result string
+    return [$doc asXML]
+}
+
+ad_proc -public soap::server::namespace_get_id {
+    service
+} {
+    @param service The service used to query the namespace id for.
+    @return Returns the namespace id for the given service.
+} {
+    return [db_string namespace_id {} -default -1 ]
+}
+
+ad_proc -public soap::server::method_get_id_and_proc {
+    namespace_id 
+    method
+} {
+    @param namespace_id
+    @param method
+    @return Returns the method ID and proc name for the given namespace ID.
+} {
+    return [db_string method_id_proc {} -default {-1 {}}]
+}
+
+ad_proc -private soap::server::get_invoke_permission_moniker {
+} {
+    @author William Byrne
+} {
+    # short cut
+    return "invoke"
+
+    # eval global within sg namespace
+    namespace eval sg {
+	# decl moniker
+	variable invoke_moniker
+
+	# test for moniker
+	if { ![info exists invoke_moniker] } {
+	    # get it
+	    set invoke_moniker [db_string select_moniker {}]
+	}
+	
+	# return it
+	return $invoke_moniker
+    }			
+}
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/tcl/soap-wsdl-procs-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/tcl/soap-wsdl-procs-postgresql.xql,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/tcl/soap-wsdl-procs-postgresql.xql	17 Oct 2004 05:51:54 -0000	1.1
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+
+<queryset>
+  <rdbms><type>postgresql</type><version>7.1</version></rdbms>
+
+  <fullquery name="soap::wsdl::method_get_idls.select_idls">
+    <querytext>
+      select idl
+        from sg_methods
+        where namespace_id = :namespace_id
+        order by method_id
+    </querytext>
+  </fullquery>
+
+  <fullquery name="soap::wsdl::method_get_notes.select_notes">
+    <querytext>
+      select notes
+        from sg_methods
+        where method_id = :method_id
+    </querytext>
+  </fullquery>
+
+<fullquery name="soap::wsdl::method_get_id.method_get_id">      
+      <querytext>
+	select method_id
+	  from sg_methods
+	  where namespace_id = :namespace_id and
+	  lower(method) = lower(:method)
+      </querytext>
+</fullquery>
+
+<fullquery name="soap::wsdl::method_get_id.method_get_id_with_proc">      
+  <querytext>
+    select method_id
+      from sg_methods
+      where namespace_id = :namespace_id and proc = :method
+  </querytext>
+</fullquery>
+
+<fullquery name="soap::wsdl::namespace_get_notes.select_notes">      
+  <querytext>
+    select notes
+      from sg_namespaces
+      where namespace_id = :namespace_id
+  </querytext>
+</fullquery>
+
+</queryset>
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/tcl/soap-wsdl-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/tcl/soap-wsdl-procs.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/tcl/soap-wsdl-procs.tcl	17 Oct 2004 05:51:54 -0000	1.1
@@ -0,0 +1,639 @@
+ad_library {
+    Tcl API for generating WSDLs.
+
+    Based on William Byrne's soap-gateway implementation.
+
+    @author William Byrne (WilliamB@ByrneLitho.com)
+    @author Nick Carroll (ncarroll@ee.usyd.edu.au)
+    @creation-date 2004-09-24
+    @cvs-id $Id: soap-wsdl-procs.tcl,v 1.1 2004/10/17 05:51:54 ncarroll Exp $
+}
+
+
+namespace eval soap::wsdl {}
+
+
+ad_proc -private soap::wsdl::build_wsdl_url {
+    service
+} {
+    @param service
+} {
+		
+    # normal	
+    set location [ns_conn location]
+		
+    # build wsdl url 
+    set wsdl [file join [ad_conn object_url] wsdl]
+	
+    # return format
+    return [format "%s%s?service=%s" $location $wsdl $service]
+}
+
+
+ad_proc -private soap::wsdl::method_get_idls {
+	namespace_id
+} {
+    @author William Byrne
+} {
+    # init
+    set methods [list]
+
+    # loop through methods belonging to namespace ??? XQL
+    db_foreach select_idls {} { 
+	# append method idl
+	lappend methods $idl
+    }
+
+    # return methods
+    return $methods
+}
+
+
+ad_proc -private soap::wsdl::get_style_parser_expr {
+    {-argpart 0}
+    {style "C"}
+} {
+    @author William Byrne
+} {
+    # switch
+    switch $style {
+	C {
+	    # test for arg expression
+	    if $argpart {
+
+		#return {(.+)(\w+) *$}
+		return {(\w+\W+)(\w+)}
+
+	    } else {
+		
+		return {^ *([^ ]+) +([a-zA-Z][a-zA-Z0-9_]*) *\(([^)]*)}	
+	    }
+        }
+        default {
+	    # throw
+	    soap::fault::raise "Unsupported IDL parse style: $style"
+        }
+    }
+}
+
+
+ad_proc -public soap::wsdl::method_get_notes {
+	method_id 
+} {
+    @author William Byrne
+} {
+    return [db_string select_notes {} -default -1 ]	
+}
+
+
+ad_proc -public soap::wsdl::method_get_id {
+	{-proc 0}
+	namespace_id 
+	method
+} {
+    @author William Byrne
+} {
+    # test for 'proc' clause
+    if [soap::server::lib::true $proc] {
+	set id [db_string method_get_id_with_proc {} -default -1 ]
+    } else {
+	set id [db_string method_get_id {} -default -1 ]	
+    }
+
+    # return
+    return $id
+}
+
+
+ad_proc -private soap::wsdl::build_namespace_uri {
+    service
+} {
+    @author William Byrne
+} {
+    # basic uri
+    return "http://$service.openacs.org/message/"
+}
+
+
+ad_proc -public soap::wsdl::namespace_get_notes {
+	namespace_id 
+} {
+    @param namespace_id
+} {
+    return [db_string select_notes {} -default -1 ]	
+}
+
+
+ad_proc -private soap::wsdl::map_ctype_to_xtype {
+    type
+} {
+    @param type
+} {
+    
+    # strip whitespace
+    regsub -all { } $type {} typ
+    
+    # map type 
+    switch $typ {
+	
+	char -
+	wchar_t {
+	    # simple character type
+	    return [list xsd:string]
+	}
+
+	int -
+	long {
+	    # simpl int
+	    return [list xsd:int]
+	}
+	
+	float -
+	double {
+	    # simple floating point
+	    return [list xsd:double]
+	}
+	
+	__int64 {
+	    # simple long long
+	    return [list xsd:long]
+	}
+	
+	char[] -
+	wchar_t[] -
+	string - 
+	wstring {
+	    # string (keep simple)
+	    return [list xsd:string]
+	}
+	
+	int[] -
+	long[] {
+	    # array of ints
+	    return [list xsd:int *]
+	} 
+	
+	float[] -
+	double[] {
+	    # array of floating point
+	    return [list xsd:double *]
+	}
+	
+	__int64[] {
+	    # array long long
+	    return [list xsd:long *]
+	}
+
+	void { 
+	    # void type
+	    return [list]
+	}		
+    }
+    
+    # not supported
+    soap::fault::unsupported "unable to map $type to xml type - '$type' refined to '$typ'"    
+}
+
+
+ad_proc -private soap::wsdl::build_endpoint {
+    service
+    {trace {}}
+} {
+    @param service
+    @param trace
+} {
+    # test for trace
+    if { $trace != {} } {
+	# use trace info specified in call
+	set location $trace
+    } else {
+	# normal	
+	set location [ns_conn location]
+    }
+
+    # build action url 
+    set action [file join [ad_conn object_url] action]
+
+    # return format
+    return [format "%s%s?service=%s" $location $action $service]
+}
+
+
+ad_proc -private soap::wsdl::do_generate_wsdl {
+    namespace
+    documentation
+    oneway
+    trace
+} {
+    @author William Byrne
+} {
+
+    # get namespace id
+    set nid [soap::server::namespace_get_id $namespace]
+	
+    # verify
+    if { $nid < 0 } {
+	
+	# not found
+	soap::fault::raise "service '$namespace' not found" 404
+	
+    }
+	
+    # fixup documentation boolean
+    set documentation [soap::server::lib::true $documentation]
+
+    # authenticate
+    # ??? soap::server::require_permission $nid read
+
+    # force to v1.1
+    set ver 1.1
+
+    # set encoding style
+    set encoding [soap::server::get_version_encoding $ver]
+
+    # get methods for namespace
+    set funcs [soap::wsdl::method_get_idls $nid]
+	
+    # decl methods
+    set methods [list]
+	
+    # set up regexp expression for "C" style function 
+    set expr [soap::wsdl::get_style_parser_expr C]
+    #set expr {^ *([^ ]+) +([a-zA-Z0-9_]+) *\(([^)]*)}
+	
+    # loop through functions
+    foreach func $funcs {
+	
+	# invoke regexp
+	regexp $expr $func {} type method argz
+	
+	# add func to methods list0
+	lappend methods $method
+	
+	# store funcs
+	set method_funcs($method) $argz
+	
+	# store func type
+	set method_types($method) $type
+	
+	# store args
+	set method_args($method) [split $argz ,]
+	
+	# get notes
+	if $documentation {
+	    set method_notes($method) [soap::wsdl::method_get_notes \
+                [soap::wsdl::method_get_id $nid $method]]
+	}	
+    }
+
+    # construct wsdl doc object
+    set doc [dom createDocument definitions]
+
+    # create root WSDL node: "definitions"
+    set defs [$doc documentElement] 
+
+    # build namespace uri for methods
+    set nsuri [soap::wsdl::build_namespace_uri $namespace]
+
+    # define namespace atts into "definitions" node
+    $defs setAttribute name $namespace
+    $defs setAttribute targetNamespace "http://$namespace.openacs.org/wsdl/" 
+    $defs setAttribute xmlns:wsdlns "http://$namespace.openacs.org/wsdl/" 
+    $defs setAttribute xmlns:typens "http://$namespace.openacs.org/type" 
+    $defs setAttribute xmlns:soap "http://schemas.xmlsoap.org/wsdl/soap/" 
+    $defs setAttribute xmlns:xsd "http://www.w3.org/2001/XMLSchema" 
+    $defs setAttribute xmlns "http://schemas.xmlsoap.org/wsdl/"
+    
+    # add documentation
+    if $documentation {
+	# get notes for namespace
+	set notes [soap::wsdl::namespace_get_notes $nid]
+	
+	# create child "definitions/documentation" node (allow empty notes)
+	set doc_node [$defs appendChild [$doc createElement documentation]]
+	set docu [$doc_node appendChild [$doc createTextNode $notes]]
+    }
+    
+    # create child "definitions/types" node
+    set types [$defs appendChild [$doc createElement types]]
+
+    # create child "definitions/types/schema" node
+    set schema [$types appendChild [$doc createElement schema]]
+    
+    # define namespace atts into "definitions/types/schema" node
+    $schema setAttribute targetNamespace "http://$namespace.openacs.org/type" 
+    $schema setAttribute xmlns "http://www.w3.org/2001/XMLSchema" 
+    $schema setAttribute xmlns:enc $encoding 
+    $schema setAttribute xmlns:wsdl "http://schemas.xmlsoap.org/wsdl/" 
+    $schema setAttribute elementFormDefault "qualified"
+    
+    # loop through decomposed methods
+    foreach m $methods {
+	
+	# get args
+	set argz $method_args($m)
+	
+	# create "definitions/message" node
+	set message [$defs appendChild [$doc createElement message]]
+	
+	# add name attr
+	$message setAttribute name "$namespace.$m"
+	
+	# add documentation
+	if $documentation {
+
+	    # create child "definitions/message/documentation" node
+	    # (allow empty notes)
+	    set doc_node [$message appendChild [$doc createElement documentation]]
+	    set docu [$doc_node appendChild [$doc createTextNode $method_notes($m)]]
+	}
+	
+	# decl param order arg
+	set order ""
+	
+	# get arg part parser expr		
+	set expr [soap::wsdl::get_style_parser_expr -argpart 1 C]
+	
+	# loop through args
+	foreach a $argz {
+	    
+	    # split arg type from its name
+	    if ![regexp $expr $a {} typ nam] {
+		
+		# format problem
+		error "unexpected argument format: '$a' in '$argz', '$m', '$method_args($m)'"
+		
+	    }
+	    
+	    # add arg to param order var
+	    lappend order $nam
+	    
+	    # map type
+	    set xtype [soap::wsdl::map_ctype_to_xtype $typ]
+	    
+	    # get component count
+	    set cnt [llength $xtype]
+	    
+	    # test for simple
+	    if { $cnt == 1 } {
+		
+		# create arg parts
+		set part [$message appendChild [$doc createElement part]]
+		
+		# add name attr
+		$part setAttribute name $nam
+
+		# add type attr
+		$part setAttribute type [lindex $xtype 0]
+		
+	    } else {
+		
+		# not yet supported
+		soap::fault::unsupported "cannot spec non simple types: $a, $xtype"
+	    }
+	}
+	
+	# reset method_args to hold param order
+	set method_args($m) $order
+	
+	# build return message
+	set typ $method_types($m)
+	
+	# map type
+	set xtype [soap::wsdl::map_ctype_to_xtype $typ]
+	
+	# get component count
+	set cnt [llength $xtype]
+	
+	# test for void
+	if { $cnt != 0} {
+	    
+	    # set boolean into method type for Respond in portType wsdl node
+	    set method_types($m) 1
+	    
+	    # create response message
+	    set message [$defs appendChild [$doc createElement message]]
+	    
+	    # add name attr
+	    $message setAttribute name [format "$namespace.$m%s" Response]
+	    
+	    # test for simple
+	    if { $cnt == 1 } {
+		
+		# create arg parts
+		set part [$message appendChild [$doc createElement part]]
+
+		# add name attr
+		$part setAttribute name Result
+		
+		# add type attr
+		$part setAttribute type [lindex $xtype 0]
+		
+	    } else {
+		# not yet supported
+		soap::fault::unsupported "cannot spec non simple types: $typ"
+	    }			
+	    
+	} elseif { $oneway } {
+	    # set false boolean into method type eliminating
+	    # Respond in portType wsdl node
+	    set method_types($m) 0
+	} else {
+	    # set true boolean into method type forcing
+	    # void Respond in portType wsdl node
+	    set method_types($m) 1
+	    
+	    # create response message
+	    set message [$defs appendChild [$doc createElement message]]
+
+	    # add name attr
+	    $message setAttribute name [format "$namespace.$m%s" Response]
+	    
+	    # force string result type
+	    if { 1 } {
+		
+		# create arg parts
+		set part [$message appendChild [$doc createElement part]]
+
+		# add name attr
+		$part setAttribute name Result
+		
+		# add type attr
+		$part setAttribute type {xsd:string}
+	    }
+	}
+    }
+    
+    # create portType "definitions/portType" node
+    set portType [$defs appendChild [$doc createElement portType]]
+    
+    # set its name 
+    $portType setAttribute name [format "%s%s" $namespace SoapPort]
+
+    # create operations for each function
+    foreach m $methods {
+
+	# create new operation
+	set operation [$portType appendChild [$doc createElement operation]]
+	
+	# set its name 
+	$operation setAttribute name $m
+	
+	# set parameter order
+	$operation setAttribute parameterOrder $method_args($m)
+	
+	# create input op
+	set input [$operation appendChild [$doc createElement input]]
+	
+	# bind to message node
+	$input setAttribute message [format "wsdlns:%s.%s" $namespace $m]
+	
+	# test for non void function (false if void)
+	if $method_types($m) {
+	    
+	    # create output op
+	    set output [$operation appendChild [$doc createElement output]]
+	    
+	    # bind to message node
+	    $output setAttribute message [format "wsdlns:%s.%s%s" $namespace $m Response]
+	}
+    }
+    
+    # setup RPC bindings, encodings, and namespaces
+    
+    # create binding node - "definitions/binding"
+    set binding [$defs appendChild [$doc createElement binding]]
+    
+    # set its name
+    $binding setAttribute name [format "%s%s" $namespace SoapBinding]
+    
+    # set its type
+    $binding setAttribute type [format "wsdlns:%s%s" $namespace SoapPort]
+    
+    # create child soap binding node 
+    set soap_binding [$binding appendChild [$doc createElement soap:binding]]
+    
+    # set rpc style
+    $soap_binding setAttribute style rpc
+    
+    # set transport
+    $soap_binding setAttribute transport {http://schemas.xmlsoap.org/soap/http}
+    
+    # loop through methods
+    foreach m $methods {
+	
+	# create input child - "definitions/binding/operation"
+	set operation [$binding appendChild [$doc createElement operation]]
+	
+	# set its name
+	$operation setAttribute name $m
+	
+	# create child soap operation node
+	# definitions/binding/operation/soap:operation
+	set soap_operation [$operation appendChild [$doc createElement soap:operation]]
+	
+	# set soap action
+	$soap_operation setAttribute soapAction [format "http://%s.openacs.org/action/%s.%s" $namespace $namespace $m]
+	
+	# create child input - "definitions/binding/operation/input"
+	set input [$operation appendChild [$doc createElement input]]
+	
+	# create child soap_body node
+	# definitions/binding/operation/input/soap:body
+	set soap_body [$input appendChild [$doc createElement soap:body]]
+	
+	# set 'use' attr
+	$soap_body setAttribute use encoded
+	
+	# set namespace
+	$soap_body setAttribute namespace $nsuri
+	
+	# set encoding
+	$soap_body setAttribute encodingStyle $encoding
+	
+	# test for output
+	if $method_types($m) {
+	    
+	    # create child output - "definitions/binding/operation/output"
+	    set output [$operation appendChild [$doc createElement output]]
+	    
+	    # create child soap_body node
+	    # definitions/binding/operation/output/soap:body
+	    set soap_body [$output appendChild [$doc createElement soap:body]]
+	    
+	    # set 'use' attr
+	    $soap_body setAttribute use encoded
+	    
+	    # set namespace
+	    $soap_body setAttribute namespace "http://$namespace.openacs.org/message/"
+	    
+	    # set encoding
+	    $soap_body setAttribute encodingStyle $encoding
+	}	
+    }
+    
+    # create service 
+    
+    # create service node - "definitions/service"
+    set service [$defs appendChild [$doc createElement service]]
+    
+    # set its name
+    $service setAttribute name $namespace
+    
+    # create child port - "definitions/service/port"
+    set port [$service appendChild [$doc createElement port]]
+    
+    # set its name
+    $port setAttribute name [format "%s%s" $namespace SoapPort]
+    
+    # set its binding
+    $port setAttribute binding [format "wsdlns:%s%s" $namespace SoapBinding]
+    
+    # create child address - "definitions/service/port/soap:address"
+    set soap_address [$port appendChild [$doc createElement soap:address]]
+    
+    # set its location
+    $soap_address setAttribute location [soap::wsdl::build_endpoint $namespace $trace]
+
+    # render xml into string
+    return [$doc asXML]
+    
+}
+
+
+ad_proc -public soap::wsdl::generate_wsdl {
+    {-documentation 1}
+    namespace
+    {oneway 1}
+    {trace {}}
+} {
+    @author William Byrne
+} {
+    # fixup and set missing to true
+    if { $oneway == {} } { set oneway 1 }
+
+    # try
+    if { [catch {
+
+	# delegate to do_generate
+	set wsdl [soap::wsdl::do_generate_wsdl $namespace $documentation $oneway $trace]
+
+    } msg] } {
+	
+	# get error code
+	global errorCode
+	set code $errorCode
+
+	# normalize error code
+	if { ![string is integer $code] } { set code 500 }
+
+	# error
+	global errorInfo
+	ns_returnerror $code "<pre>$msg\n$errorInfo</pre>"
+
+    } else {
+
+	# return wsdl
+	return $wsdl
+    }
+}
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/www/action.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/action.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/action.tcl	17 Oct 2004 05:51:55 -0000	1.1
@@ -0,0 +1,78 @@
+# /packages/soap-gateway/www/action.tcl
+
+# page contract not included due to cost of parsing payload - (not necessary)
+
+# generate temp file name
+set tmp [ns_tmpnam]
+
+# open it
+set f [open $tmp w+]
+
+# perform file ops in safe block to ensure tmp file unlink
+# (yes, this is a back asswards approach)
+set err [catch {
+	
+	# dump payload to file - there's gotta be a better way to get the content
+	ns_conncptofp $f
+	
+	# get file size
+	set size [tell $f]
+	
+	# limit incoming envelope size to 1/4 meg
+	if { $size > 262144 || $size < 0 } {
+			
+		# throw it
+		error "payload too large"			
+	
+	}
+	
+	# seek to beginning
+	seek $f 0
+	
+	# read file contents into SOAP envelope var
+	set env [read $f $size]
+	
+} msg] 
+
+# test for error
+if { $err != 0 } {
+
+	# make em' wait
+	ns_sleep 5
+
+	# prep
+	set savedInfo {}
+	
+	# advise
+	global errorInfo
+	
+	# test
+	if { [info exists errorInfo] != 0 } {
+	
+		# preserve error info
+		set savedInfo $errorInfo
+		
+	} 
+
+	# release file
+	catch { close $f }
+	
+	# unlink file
+	ns_unlink $tmp
+
+	# throw
+	error "$msg\nfile: $tmp" $savedInfo
+
+} else {
+	
+	# release file
+	catch { close $f }
+
+	# unlink file
+	ns_unlink $tmp
+
+
+}
+
+# invoke envelope using lib functions and return
+ns_return 200 text/xml [soap::server::invoke $env]
Index: openacs-4/packages/soap-gateway/www/debug.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/debug.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/debug.adp	17 Oct 2004 05:51:55 -0000	1.1
@@ -0,0 +1,4 @@
+<master src="./master">
+<include src="toolbar">
+<formtemplate id="debug_form"></formtemplate>
+@result@
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/www/debug.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/debug.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/debug.tcl	17 Oct 2004 05:51:55 -0000	1.1
@@ -0,0 +1,37 @@
+ad_page_contract {
+
+  @author WilliamB@ByrneLitho.com
+  @creation-date 2002-12-23
+  @cvs-id $Id: debug.tcl,v 1.1 2004/10/17 05:51:55 ncarroll Exp $
+} {
+	{expr {}}
+}
+
+template::form create debug_form
+
+# build service input field
+template::element create debug_form expr \
+	-widget textarea \
+    -datatype text \
+    -label "expr" \
+    -html { rows 8 cols 80 wrap off } \
+    -value $expr
+
+# test for valid form 
+if [template::form is_valid debug_form]  {
+
+	if [catch {
+		set result [uplevel $expr]
+	} msg] { 
+		set result $msg 
+	}
+	
+} else {
+
+	set result {}
+	
+}
+
+ad_return_template
+
+
Index: openacs-4/packages/soap-gateway/www/index-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/index-postgresql.xql,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/index-postgresql.xql	17 Oct 2004 05:51:55 -0000	1.1
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+
+<queryset>
+  <rdbms><type>postgresql</type><version>7.1</version></rdbms>
+
+  <fullquery name="namespace_list">
+    <querytext>
+      select namespace_id, service, uri, notes from sg_namespaces
+    </querytext>
+  </fullquery>
+</queryset>
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/www/index.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/index.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/index.adp	17 Oct 2004 05:51:55 -0000	1.1
@@ -0,0 +1,98 @@
+<master src="./master">
+<include src="toolbar" caption="@caption@">
+<!-- link href="basic.css" rel="stylesheet" type="text/css" -->
+
+<if @namespaces:rowcount@ gt 0>
+<a name="top"></a>
+<table width="800" border=1 cellpadding=2 cellspacing=2>
+  <tr> 
+	<td width="118" bgcolor=#cccccc><strong>Service</strong></td>
+	<td width="488" bgcolor=#cccccc><strong>Notes</strong></td>
+	<td width="54" bgcolor=#cccccc><strong>WSDL</strong></td>
+  </tr>
+  <multiple name="namespaces" rowcount=1> 
+  <tr> 
+	<td>
+	  <a href="#@namespaces.service@">@namespaces.service@</a>
+	</td>
+	<td>
+	  @namespaces.notes;noquote@&nbsp;
+	</td>
+	<td><a href="@namespaces.wsdl@">wsdl</a></td>
+  </tr>
+  </multiple> 
+</table>
+
+</if><else>
+<p><em>There are no namespaces</em></p>
+</else> 
+<if @namespaces:rowcount@ gt 0>
+<multiple name="namespaces">
+<hr size="1" width="800" align="left">
+<table width="800" border="0">
+  <tr>
+	<td width="129"><b><a name="@namespaces.service@"></a>Service:</b></td>
+	<td width="636"><b>
+	  @namespaces.service@
+	  </b>&nbsp;</td>
+	<td width="21"><a href="#"><img src="top.gif" width="12" height="12" border="0"></a></td>
+  </tr>
+  <tr>
+	<td><b>Endpoint:</td>
+	<td></b><a href="@namespaces.endpoint@">
+	  @namespaces.endpoint@
+	  </a></td>
+	<td>&nbsp;</td>
+  </tr>
+  <tr>
+	<td><b>WSDL:</td>
+	<td></b><a href="@namespaces.wsdl@">
+	  @namespaces.wsdl@
+	  </a></td>
+	<td>&nbsp;</td>
+  </tr>
+  <tr>
+	<td>&nbsp;<em>force response:</em></td>
+	<td><a href="@namespaces.wsdl@&amp;oneway=0">
+	  @namespaces.wsdl@
+	  &amp;oneway=0</a></td>
+	<td>&nbsp;</td>
+  </tr>
+  <tr>
+	<td>&nbsp;<em>no documentation:</em></td>
+	<td><a href="@namespaces.wsdl@&amp;documentation=0">
+	  @namespaces.wsdl@
+	  &amp;documentation=0</a></td>
+	<td>&nbsp;</td>
+  </tr>
+  <tr>
+	<td>&nbsp;<em>trace:</em></td>
+	<td><a href="@namespaces.wsdl@&amp;trace=http://localhost:8080">
+	  @namespaces.wsdl@
+	  &amp;trace=http://localhost:8080</a></td>
+	<td>&nbsp;</td>
+  </tr>
+  <tr>
+	<td><b>URI</b></td>
+	<td>
+	  @namespaces.uri@
+	</td>
+	<td>&nbsp;</td>
+  </tr>
+  <tr>
+	<td><b>SOAPAction</b></td>
+	<td>N/A</td>
+	<td>&nbsp;</td>
+  </tr>
+  <tr>
+	<td valign="top"><b>Notes:</td>
+	<td></b>
+	  @namespaces.notes;noquote@&nbsp;<a href="doc/service?service=@namespaces.service@">(more)</a>
+	</td>
+	<td>&nbsp;</td>
+  </tr>
+</table>
+</multiple>
+</if>
+
+
Index: openacs-4/packages/soap-gateway/www/index.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/index.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/index.tcl	17 Oct 2004 05:51:56 -0000	1.1
@@ -0,0 +1,61 @@
+# packages/soap-gateway/www/index.tcl
+
+ad_page_contract {
+
+    @author WilliamB@ByrneLitho.com
+    @creation-date 2002-12-23
+    @cvs-id $Id: index.tcl,v 1.1 2004/10/17 05:51:56 ncarroll Exp $
+} {
+}
+
+# clear title
+set title {}
+
+# installed correctly
+if [catch {
+    
+    soap::server::lib::true 1
+    
+}] {
+
+    # report as installation error
+    error "Failure while calling soap-gateway function!\nDid you restart the server after installing soap-gateway package?\n\n"
+
+}
+
+# get package id
+set package_id [ad_conn package_id]
+
+# require read permission 
+ad_require_permission $package_id read
+
+# query namespaces
+db_multirow -extend {endpoint edit delete wsdl} namespaces namespace_list {} {
+    set endpoint [soap::wsdl::build_endpoint $service]
+    set edit "edit-namespace?namespace_id=$namespace_id"
+    set delete "delete-namespace?namespace_id=$namespace_id"
+    set wsdl [soap::wsdl::build_wsdl_url $service]
+}
+
+# create form
+template::form create new_namespace_form
+
+# change action attribute for form - not documented
+set new_namespace_form:properties(action) edit-namespace
+
+# create form
+template::form create init_workspace_form
+
+# change action attribute for form - not documented
+set init_workspace_form:properties(action) init-workspace
+
+# create form
+template::form create init_interop_form
+
+# change action attribute for form - not documented
+set init_interop_form:properties(action) init-interop
+
+# update caption
+set caption "services"
+
+ad_return_template
Index: openacs-4/packages/soap-gateway/www/master.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/master.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/master.adp	17 Oct 2004 05:51:56 -0000	1.1
@@ -0,0 +1,91 @@
+<master>
+<property name="title">@title@</property>
+<if @context@ not nil>
+	<property name="context">@context@</property>
+</if>
+<property name="context_bar">@context_bar@</property>
+<property name="header_stuff">
+@header_stuff@
+<style>
+.sg_toolbar { 
+	font-family: tahoma,verdana,arial,helvetica; 
+	font-size: 70%; 
+	font-weight: bold; color: #ccccff; 
+	text-decoration: none; 
+}
+
+.sg_toolbar:hover { 
+	color: white; 
+	text-decoration: underline;  
+}
+
+A.sg_toolbar { 
+	color: white; 
+}
+
+INPUT.toolbar { 
+	font-family: tahoma,verdana,arial,helvetica; 
+	font-weight: bold; 
+	font-size: 70%; color: black; 
+}
+  
+.summary { 
+	font-size: 70%; 
+	font-family: verdana,arial,helvetica; 
+}
+
+.summary_bold { 
+	font-size: 70%; 
+	font-family: verdana,arial,helvetica; 
+	font-weight: bold; 
+}
+
+pre { 
+	font-family: Courier; 
+	font-size: 10pt; 
+}
+  
+  
+
+.section  {
+	font: bold medium Arial;
+}
+
+.text {
+  font-family: "Times New Roman", Times, serif;
+}
+
+.toc {
+	list-style-type : inherit;
+	list-style : decimal-leading-zero;
+}
+
+.tcl-files {
+	list-style-image: url(tcl.gif);
+}
+
+.adp-file {
+	list-style-image: url(www.gif);
+}
+
+.html-file {
+	list-style-image: url(www.gif);
+}
+
+.text-files {
+	list-style-image: url(text.gif);
+}
+
+.folder-files {
+	list-style-image: url(folder.gif);
+}
+
+.file-desc {
+	width : 320;
+}
+
+</style>
+</property>
+<slave>
+
+
Index: openacs-4/packages/soap-gateway/www/master.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/master.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/master.tcl	17 Oct 2004 05:51:56 -0000	1.1
@@ -0,0 +1,18 @@
+# Expects "title" and "header" and "context_bar"
+
+if { ![info exists context_bar] } {
+    set context_bar {}
+}
+
+if ![info exists header_stuff] {
+	set header_stuff {}
+}
+
+if ![info exists title] {
+	
+	# clear
+	set title {}
+	
+}
+
+ad_return_template
Index: openacs-4/packages/soap-gateway/www/toolbar.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/toolbar.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/toolbar.adp	17 Oct 2004 05:51:56 -0000	1.1
@@ -0,0 +1,22 @@
+<table width="100%" bgcolor="#000000" border="0">
+<tr><td>
+<table border="0">
+<tr><td>
+<a href="@base@" class="sg_toolbar" style="color: yellow">soap-gateway</a>
+<if @caption@ not nil><span class="sg_toolbar" style="color: yellow">&nbsp;&#8212;&nbsp;
+</span><a href="." class="sg_toolbar" style="color: yellow">@caption@</a></if>
+</td></tr>
+</table>
+</td><td align="right">
+<table border="0">
+  <tr> <multiple name="toolbar"> 
+	<td><span class="sg_toolbar">&nbsp;|&nbsp;</span><a href="@toolbar.url@" class="sg_toolbar">
+	  @toolbar.symbol@
+	  </a></td>
+	</multiple> </tr>
+</table>	
+</td></tr>	
+</table>
+<p>
+
+	
Index: openacs-4/packages/soap-gateway/www/toolbar.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/toolbar.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/toolbar.tcl	17 Oct 2004 05:51:56 -0000	1.1
@@ -0,0 +1,85 @@
+# /packages/soap-gateway/www/toolbar.tcl
+
+# layout inspired by bug-tracker
+
+# safety
+if ![info exists caption] {
+
+    # clear
+    set caption {}
+}
+
+# clear for tools
+set tools []
+
+# add standard tools
+set defaults [list help services tests]
+
+# package id
+set pid [soap::package_id -throw f]
+
+# verify
+if { $pid == 0 } {
+	
+    # must be just starting out - clear everything
+    set defaults [list]
+	
+# test for admin user
+} elseif { [soap::server::has_permission $pid admin] != 0 } { 
+
+    # add em'
+    lappend defaults admin permissions
+    
+}
+
+# update tools list
+foreach default $defaults {
+
+    # test current list and skip if caption
+    # ??? if $default equal to caption, then assume $default tool page is current
+    if { [lsearch $tools $default] < 0 && ![string equal -nocase $default $caption] } {
+	
+	# add
+	lappend tools $default
+    }
+}
+
+# get href base
+set base [soap::get_base_url]
+
+# create multirow
+multirow create toolbar symbol url
+
+# loop through list
+foreach tool $tools {
+
+    # switch
+    case $tool {
+	help {
+	    # add
+	    multirow append toolbar help [file join $base doc]
+	}
+	services {
+	    # add
+	    multirow append toolbar services [file join $base ]
+	}
+	admin {
+	    # add
+	    multirow append toolbar admin [file join $base admin ]
+	}
+	tests {
+	    # add
+	    multirow append toolbar tests [file join $base tests ]
+	}
+	permissions {
+	    # set href
+	    set url "/permissions/one?object_id=$pid"
+
+	    # add
+	    multirow append toolbar permissions $url
+
+	}
+    }
+}
+
+ad_template_return
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/www/top.gif
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/top.gif,v
diff -u
Binary files differ
Index: openacs-4/packages/soap-gateway/www/wsdl.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/wsdl.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/wsdl.tcl	17 Oct 2004 05:51:56 -0000	1.1
@@ -0,0 +1,19 @@
+# packages/soap-gateway/www/wsdl.tcl
+
+# clear title
+set title {}
+
+# get params from url
+set params [soap::server::get_url_params]
+
+# get interested params
+set service [ns_set get $params service]
+set oneway [ns_set get $params oneway]
+set trace [ns_set get $params trace]
+set docs [ns_set get $params documentation]
+if ![string length $docs] { set docs 1 }
+
+# render xml and return
+ns_return 200 text/xml [soap::wsdl::generate_wsdl -documentation $docs $service $oneway $trace] 
+ 
+ 
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/www/admin/delete-method-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/admin/delete-method-postgresql.xql,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/admin/delete-method-postgresql.xql	17 Oct 2004 05:51:56 -0000	1.1
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+
+<queryset>
+  <rdbms><type>postgresql</type><version>7.1</version></rdbms>
+
+  <fullquery name="select_method">
+    <querytext>
+      select method, idl, idl_style, notes 
+	from sg_methods
+	where method_id = :method_id
+    </querytext>
+  </fullquery>
+</queryset>
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/www/admin/delete-method.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/admin/delete-method.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/admin/delete-method.adp	17 Oct 2004 05:51:56 -0000	1.1
@@ -0,0 +1,6 @@
+<master src="../master">
+<!-- link href="basic.css" rel="stylesheet" type="text/css" -->
+<!-- property name="context">@context@</property -->
+<include src="../toolbar">
+Delete the following method: <b>@method@</b>
+<formtemplate id="method_form" style="plain"></formtemplate>
Index: openacs-4/packages/soap-gateway/www/admin/delete-method.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/admin/delete-method.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/admin/delete-method.tcl	17 Oct 2004 05:51:56 -0000	1.1
@@ -0,0 +1,55 @@
+# packages/soap-gateway/www/admin/method-namespace.tcl
+
+ad_page_contract {
+
+  @author WilliamB@ByrneLitho.com
+  @creation-date 2002-12-23
+  @cvs-id $Id: delete-method.tcl,v 1.1 2004/10/17 05:51:56 ncarroll Exp $
+} {
+	namespace_id:integer,notnull
+	method_id:integer,notnull
+}
+
+# clear title
+set title {}
+
+# get package
+set package_id [ad_conn package_id]
+
+# verify namespace id
+soap::method_check $method_id
+
+# require write permission
+ad_require_permission $method_id admin; #write
+	
+# set session context
+set context [list "Administration"]
+
+# create form
+template::form create method_form
+
+# store namespace_id into hidden form element
+template::element create method_form namespace_id \
+	-widget hidden \
+	-datatype text \
+	-value $namespace_id
+
+# store method_id into hidden form element
+template::element create method_form method_id \
+	-widget hidden \
+	-datatype text \
+	-value $method_id
+
+# query for method attributes
+db_1row select_method {}
+
+# test for valid form 
+if [template::form is_valid method_form] {
+
+	# update existing
+	soap::method_delete $method_id
+
+	ad_returnredirect "./edit-namespace?namespace_id=$namespace_id"
+}
+
+ad_return_template
Index: openacs-4/packages/soap-gateway/www/admin/delete-namespace-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/admin/delete-namespace-postgresql.xql,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/admin/delete-namespace-postgresql.xql	17 Oct 2004 05:51:57 -0000	1.1
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+
+<queryset>
+  <rdbms><type>postgresql</type><version>7.1</version></rdbms>
+
+  <fullquery name="namespace_select">
+    <querytext>
+      select service, uri, notes
+        from sg_namespaces
+	where namespace_id = :namespace_id
+    </querytext>
+  </fullquery>
+</queryset>
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/www/admin/delete-namespace.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/admin/delete-namespace.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/admin/delete-namespace.adp	17 Oct 2004 05:51:57 -0000	1.1
@@ -0,0 +1,5 @@
+<master src="../master">
+<!-- property name="context">@context@</property -->
+<include src="../toolbar">
+Delete the following service: <b>@service@</b>
+<formtemplate id="namespace_form" style="plain"></formtemplate>
Index: openacs-4/packages/soap-gateway/www/admin/delete-namespace.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/admin/delete-namespace.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/admin/delete-namespace.tcl	17 Oct 2004 05:51:57 -0000	1.1
@@ -0,0 +1,48 @@
+# packages/soap-gateway/www/admin/delete-namespace.tcl
+
+ad_page_contract {
+
+  @author WilliamB@ByrneLitho.com
+  @creation-date 2002-12-23
+  @cvs-id $Id: delete-namespace.tcl,v 1.1 2004/10/17 05:51:57 ncarroll Exp $
+} {
+	namespace_id:integer,notnull
+}
+
+# clear title
+set title {}
+
+# get package
+set package_id [ad_conn package_id]
+
+# verify namespace id
+soap::namespace_check $namespace_id
+
+# require admin permission
+ad_require_permission $namespace_id admin; #write
+	
+# set session context to delete mode
+set context [list "Administration"]
+
+# create form
+template::form create namespace_form
+
+# store namespace_id into hidden form element
+template::element create namespace_form namespace_id \
+	-widget hidden \
+	-datatype text \
+	-value $namespace_id
+
+# query for namespace attributes
+db_1row namespace_select {}
+
+# test for valid form 
+if [template::form is_valid namespace_form] {
+
+	# update existing
+	soap::namespace_delete $namespace_id
+
+	ad_returnredirect "./"
+}
+
+ad_return_template
Index: openacs-4/packages/soap-gateway/www/admin/edit-namespace-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/admin/edit-namespace-postgresql.xql,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/admin/edit-namespace-postgresql.xql	17 Oct 2004 05:51:57 -0000	1.1
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+
+<queryset>
+  <rdbms><type>postgresql</type><version>7.1</version></rdbms>
+
+  <fullquery name="namespace_select">
+    <querytext>
+      select service, uri, notes
+        from sg_namespaces
+	where namespace_id = :namespace_id
+    </querytext>
+  </fullquery>
+
+  <fullquery name="namespace_select_all">
+    <querytext>
+      select method_id, namespace_id, method, idl, idl_style, proc, notes 
+	from sg_methods
+	where namespace_id = :namespace_id
+    </querytext>
+  </fullquery>
+
+  <fullquery name="method_select">
+    <querytext>
+      select method, idl, idl_style, proc, notes 
+        from sg_methods
+        where method_id = :method_id
+    </querytext>
+  </fullquery>
+</queryset>
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/www/admin/edit-namespace.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/admin/edit-namespace.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/admin/edit-namespace.adp	17 Oct 2004 05:51:57 -0000	1.1
@@ -0,0 +1,143 @@
+<master src="../master">
+<!-- property name="context">@context@</property -->
+<property name="focus">@focus@</property>
+<include src="../toolbar" caption="@caption@">
+<formtemplate id="namespace_form" style="plain"></formtemplate> 
+<hr size="1" width="800" align="left">
+<if @editing_namespace@ not eq 0> 
+<h3>Methods</h3>
+<formtemplate id="method_form">
+<table width="980" border=1 cellpadding=2 cellspacing=2>
+  <tr> 
+	<td width="120" bgcolor=#cccccc><strong>proc</strong></td>
+	<td width="240" bgcolor=#cccccc><strong>IDL</strong></td>
+	<td width="400" bgcolor=#cccccc><strong>Notes</strong></td>
+	<td width="68" bgcolor=#cccccc>&nbsp;</td>
+	<td width="55" bgcolor=#cccccc>&nbsp;</td>
+  </tr>
+  <multiple name="methods"> 
+  <if @editing_method@ eq @methods.method_id@>
+  <tr> 
+	<td valign="top"><formwidget id="proc"></td>
+	<td valign="top"> 
+	<formwidget id="idl">
+	  @idl_help@
+    </td>
+	<td> 
+	  <formwidget id="method_notes">
+	</td>
+	<td><input type="submit" value="update"><!-- a href="javascript:document.method_form.submit();">update</a --></td>
+	<td><a href="@methods.cancel@">cancel</a></td>
+  </tr>
+  </if><else>
+  <if @methods.method_id@ lt 0>
+  <tr> 
+	<td>
+	<font color="#FF0000">
+		@methods.proc@
+	</font>
+	</td>
+	<td>
+	<font color="#FF0000">
+		<a href="#@methods.diff@">@methods.idl@</a>
+	</font>
+	</td>
+	<td> 
+	  @methods.notes@&nbsp;
+	</td>
+	<td><a href="@methods.edit@">import</a></td>
+	<td>&nbsp;</td>
+  </tr>
+  </if><else>
+  <tr> 
+	<td>
+	<if @methods.diff@ not eq "SAME"> 
+		<font color="#FF0000">
+		<a href="#@methods.diff@">@methods.proc@</a>
+		</font>
+	</if><else>
+		<font color="#000000">
+		@methods.proc;noquote@
+		</font>
+	</else>
+	</td>
+	<td>
+	<if @methods.diff@ not eq "SAME"> 
+		<font color="#FF0000">
+	</if><else>
+		<font color="#000000">
+	</else>
+		@methods.idl;noquote@
+	</font>
+	</td>
+	<td> 
+		@methods.notes;noquote@&nbsp;
+	</td>
+	<td><a href="@methods.edit@">edit</a></td>
+	<td><a href="@methods.delete@">delete</a></td>
+  </tr>
+  </else>
+  </else>
+  </multiple> 
+  <if @editing_method@ eq 0>
+  <tr> 
+  	<td valign="top"><formwidget id="proc"></td>
+	<td valign="top"> 
+	  <formwidget id="idl">@idl_help;noquote@
+	</td>
+	<td> 
+	  <formwidget id="method_notes">
+	</td>
+	<td><input type="submit" value="create" ><!-- a href="javascript:document.method_form.submit();">create</a --></td>
+	<td>&nbsp;</td>
+  </tr>
+  </if>
+</table>
+</formtemplate></if> 
+<p><if @editing_namespace@ not eq 0>
+<h3>Error Descriptions</h3>
+<table width="840" border="0">
+  <tr>
+	<td width="120" valign="top"><a name="UPUB"><strong>Not Published</strong></a></td>
+	<td>A public Tcl proc within the <em><strong> 
+	  @namespace@
+	  </strong></em> namespace exists that is not published . Selecting <em>import </em>will 
+	  add the procedure to the WSDL database. The proc will then be available 
+	  for public access using the name specified within <strong>ad_proc's </strong> 
+	  <em>@idl</em> 
+	  parameter. If the <em>@idl</em> parameter is missing, the proc's symbolic name will be used instead.<br>
+	</td>
+  </tr>
+  <tr>
+	<td valign="top"><a name="DUPL" id="DUPL"></a><strong>Duplicate IDL</strong></td>
+	<td>The soap-gateway's <em>diff</em> algorithm detected a potential duplicate 
+	  method name. The calculated IDL name already exists within the WSDL 
+	  database for the <em><strong>@namespace@</strong></em> namespace. Or, the IDL name for the Tcl proc was 
+	  detected within the list of sibling procs not yet published to the WSDL database.
+	   In either case, the Tcl proc cannot be published 
+	  until it's IDL name is made unique within the <em><strong>
+	  @namespace@
+	  </strong></em> namespace.<br>
+	</td>
+  </tr>
+  <tr>
+	<td valign="top"><a name="ORPH"><strong>Orphan</strong></a></td>
+	<td>A published method exists within the WSDL database that has no corresponding 
+	  <em>public</em> Tcl proc in the <em><strong>
+	  @namespace@
+	  </strong></em> namespace. Either delete the entry or supply a <em>public</em> Tcl proc. 
+	  <br>
+	</td>
+  </tr>
+  <tr>
+	<td valign="top"><a name="ARGS"><strong>Arguments</strong></a></td>
+	<td>A discrepency exists between the arguments of the Tcl proc and the published method in the
+	WSDL database. Comparisons are made to the argument names only. No type checking is performed.
+	  <br>
+	</td>
+  </tr>
+</table>
+</if><else> 
+<p><em>There are no methods!</em></p>
+</else> 
+@diffdata@
Index: openacs-4/packages/soap-gateway/www/admin/edit-namespace.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/admin/edit-namespace.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/admin/edit-namespace.tcl	17 Oct 2004 05:51:57 -0000	1.1
@@ -0,0 +1,492 @@
+# packages/soap-gateway/www/admin/edit-namespace.tcl
+
+ad_page_contract {
+
+    @author WilliamB@ByrneLitho.com
+    @creation-date 2002-12-23
+    @cvs-id $Id: edit-namespace.tcl,v 1.1 2004/10/17 05:51:57 ncarroll Exp $
+} {
+    namespace_id:integer,notnull,optional
+    {service ""}
+    {notes:html ""}
+    method_id:integer,notnull,optional
+    {idl ""}
+    {proc ""}
+    {method_notes:html ""}
+    {import 0}
+} -properties {
+    focus
+}
+
+# test for import
+if [soap::server::lib::true $import] {
+
+    # test for single method import
+    if { $proc != {} } {
+	
+	# perform single import
+	set nid [soap::server::lib::import_service \
+		     -proc $proc $service]
+	
+    } else {
+	
+	# perform full import
+	set nid [soap::server::lib::import_service $service]
+		
+	# return to admin page
+	ad_returnredirect .
+		
+    }
+
+    # verify args
+    if { [info exists namespace_id] != 0 && $nid != $namespace_id } {
+	
+	# egats
+	soap::fault::raise "Namespace id mismatch during import"
+	
+    } else {
+	
+	# set id
+	set namespace_id $nid
+	
+    }	
+    
+}
+
+# clear error
+set error {}
+
+# clear focus
+set focus {}
+
+# init debug var
+set diffdata {}
+
+# get idl help
+set idl_help [soap::get_idl_help]
+
+# get package
+set package_id [ad_conn package_id]
+
+# check to see if namespace_id is assigned
+if {[info exists namespace_id]} {
+
+    # verify namespace id
+    soap::namespace_check $namespace_id
+
+    # require write permission
+    ad_require_permission $namespace_id admin; #write
+	
+    # set session context to edit mode
+    set context [list "Edit Namespace"]
+	
+} else {
+
+    # require write permission for new namespace
+    ad_require_permission $package_id admin; #create
+
+    # set session context to creation mode
+    set context [list "New Namespace"]
+
+}
+
+# create form
+template::form create namespace_form
+
+# test for namespace_id assigment
+if {[info exists namespace_id]} {
+
+    # set editing 
+    set editing_namespace 1
+
+} else {
+
+    # creating 
+    set editing_namespace 0
+
+}
+
+# build service input field
+template::element create namespace_form service \
+    -datatype text \
+    -label "Service" \
+    -html { size 32 } \
+    -value {}; #$service
+
+# build notes input field
+template::element create namespace_form notes \
+    -widget textarea \
+    -datatype text \
+    -label "Notes" \
+    -html { rows 8 cols 80 wrap off } \
+    -value {}; #$notes
+
+# test for valid form 
+if [template::form is_valid namespace_form] {
+
+    # clear method_id to disable method logic below
+    if [info exists method_id] { unset method_id }
+    
+    # clean up service
+    set service [string trim $service]
+	
+    # try
+    set err [catch {
+	    
+	# verify
+	soap::check_symbol $service
+
+    } error]
+	
+    # verify
+    if { $err } {
+	    
+	# do nothing
+	
+    } else {
+	
+	# get session values	
+	set user_id [ad_conn user_id]
+	set peeraddr [ad_conn peeraddr]
+	
+	# force uri to xxxx.openacs.org
+	set uri "http://$service.openacs.org/methods"
+		
+	# look for id of named method
+	set nid [soap::server::namespace_get_id $service]
+	
+	# verify
+	if { $nid > 0 && (![info exists namespace_id] || $nid != $namespace_id) } {
+		
+	    # egats
+	    soap::fault::raise "Duplicate service: $service"
+	}
+
+	# test for assigned namespace id
+	if [info exists namespace_id] {
+		
+	    # update existing
+	    soap::server::lib::namespace_update $namespace_id \
+		$service $uri $notes
+	    
+	} else {
+	    
+	    # create new
+	    soap::server::lib::namespace_new $service $uri $notes $user_id $peeraddr $package_id
+
+	    # return to admin page
+	    ad_returnredirect .
+			
+	}
+
+	# ok return to main list
+	#ad_returnredirect "./"
+		
+    }
+    
+}
+
+# test for editing
+if { $editing_namespace != 0 } {
+
+    # store namespace_id into hidden form element
+    template::element create namespace_form namespace_id \
+	-widget hidden \
+	-datatype text \
+	-value $namespace_id
+
+    # query for namespace attributes
+    db_1row namespace_select {}
+
+    # update form elements
+    template::element set_value namespace_form service $service
+    template::element set_value namespace_form notes $notes
+    
+    # create method form
+    template::form create method_form
+    
+    set method_form:properties(action) edit-namespace
+    
+    # test for method_id assigment
+    if [info exists method_id] {
+	
+	# set editing 
+	set editing_method $method_id
+	
+    } else {
+	
+	# creating 
+	set editing_method 0
+	
+    }
+	
+    # store namespace_id into hidden form element
+    template::element create method_form namespace_id \
+	-widget hidden \
+	-datatype text \
+	-value $namespace_id
+    
+    # build idl input field
+    template::element create method_form idl \
+	-datatype text \
+	-label "IDL" \
+	-html { size 48 } \
+	-value {}; #$idl
+	
+    # decl procs
+    set procs2 [list]
+	
+    # get source procs and double entries for HTML options
+    foreach p [soap::get_source_procs $service] {
+		
+	# get local
+	set local [namespace tail $p]
+	
+	# append
+	lappend procs2 [list "$local {[info args $p]}" $local]
+	
+    }
+    
+    # build proc select
+    template::element create method_form proc \
+	-datatype text \
+	-label "Procedure" \
+	-widget select \
+	-options $procs2 \
+	-value $proc
+    
+    # build notes input field
+    template::element create method_form method_notes \
+	-widget textarea \
+	-datatype text \
+	-label "Notes" \
+	-html { rows 10 cols 40 wrap off } \
+	-value {}; #$notes
+    
+    # test for valid form 
+    if { [template::form is_valid method_form] } {
+	
+	# try
+	set err [catch {
+	    
+	    # decompose IDL
+	    set xsd [soap::server::lib::idl_to_xsd "C" $idl]
+	    
+	    # get method
+	    set method [lindex $xsd 1]
+	    
+	    # verify
+	    soap::check_symbol $method
+	    
+	} error]
+	
+	# verify
+	if { $err } {
+	    
+	    # do nothing
+	    
+	} else {
+	    
+	    # show
+	    set error $xsd
+	    
+	    # set fixed
+	    set idl_style "C"
+	    
+	    # get session values	
+	    set user_id [ad_conn user_id]
+	    set peeraddr [ad_conn peeraddr]
+	    
+	    # look for id of named method
+	    set mid [soap::wsdl::method_get_id $namespace_id $method]
+	    
+	    # verify
+	    if { $mid > 0 && $mid != $editing_method } {
+		
+		# egats
+		soap::fault::raise "Duplicate method: $method"
+		
+	    }
+	    
+	    # test for assigned method id
+	    if { $editing_method != 0 } {
+		
+		# update existing
+		soap::server::lib::method_update $method_id $method $idl $idl_style $proc $method_notes
+		
+	    } else {
+		
+		# create new
+		soap::server::lib::method_new $namespace_id $method $idl $idl_style $proc $method_notes $user_id $peeraddr $namespace_id
+	    }
+	    
+	    # clear editing mode
+	    set editing_method 0
+	    
+	    #ad_returnredirect "./edit-namespace"
+	}
+    }
+
+    # get diffs
+    array set diffs [soap::diff_methods -same t $service]
+	
+    if { $editing_method } {
+	
+	# query for method attributes
+	db_1row method_select {}
+	
+	# store method_id into hidden form element
+	template::element create method_form method_id \
+	    -widget hidden \
+	    -datatype text \
+	    -value $method_id
+	
+	# set db method values into field elements
+	template::element set_value method_form idl $idl
+	template::element set_value method_form proc $proc
+	template::element set_value method_form method_notes $notes
+	
+    } else {
+	
+	# clear
+	template::element set_value method_form proc {}
+	template::element set_value method_form idl {}
+	template::element set_value method_form method_notes {}
+	
+    }
+    
+    # record history list of db entries
+    set history [list]
+    
+    # query methods
+    db_multirow -extend {edit delete cancel diff} methods \
+	namespace_select_all {} {
+	
+	# build hot links for edit/delete/...
+	set edit "edit-namespace?method_id=$method_id&namespace_id=$namespace_id"
+	set delete "delete-method?method_id=$method_id&namespace_id=$namespace_id"
+	set cancel "edit-namespace?namespace_id=$namespace_id"
+	
+	# init diff code
+	set diff ERR
+	
+	# try
+	if [catch {
+	    
+	    # get the diff details for $method
+	    set details $diffs($method)
+	    
+	    # get the diff description code
+	    set diff [lindex $details 0]
+	    
+	    # add entry to history list
+	    lappend history $method
+	    
+	    # get the args
+	    set proc [format "$proc {%s}" [lindex $details 1]]
+	    
+	    # check for orphan
+	    if [string equal -nocase -length 4 $diff ORPH] {
+		
+		# modify proc to reflect orphan
+		set proc "#ORPHAN#"
+		
+	    }
+	    
+	    
+	} msg] {
+	    
+	    # display error using proc
+	    set proc $msg
+	    
+	}
+	
+	# use hard spaces
+	regsub -all { } $proc {\&nbsp;} proc
+	regsub -all { } $idl {\&nbsp;} idl
+    }
+    
+    # debug
+    #set diffdata [array get diffs]
+    
+    # scan history list
+    foreach remove $history {
+	
+	# remove entry from diffs array
+	array unset diffs $remove
+	
+    }
+    
+    # loop through remaining elements in diffs
+    foreach proc [array names diffs] {
+				      
+        # local 
+	set local [namespace tail $proc]
+	
+	# build import expression
+	set import "edit-namespace?namespace_id=$namespace_id&service=$service&import=1&proc=$local"
+	
+	# get diff code
+	set diff [lindex $diffs($proc) 0]
+	
+	# describe code
+	switch $diff {
+	    
+	    UPUB {
+	        set desc {*NOT PUBLISHED*}
+	    }
+		
+	    DUPL {
+		set desc {*DUPLICATE IDL*}
+	    }
+		
+	    default {
+		set desc {*UNKNOWN ERROR*}
+	    }
+	    
+	}
+	
+	# get proc
+	set local [format "$local {%s}" [lindex $diffs($proc) 1]]
+	
+	# change to hard spaces
+	regsub -all { } $local {\&nbsp;} local
+	
+	# add to table
+	multirow append methods -1 $namespace_id {} $desc {} $local {} $import {} {} $diff
+	
+    }
+    
+    # create goto anchor
+    set focus "method_form.idl"
+    
+} else {
+    
+    # clear
+    set editing_method 0
+    
+    # clear diffs
+    array set diffs [list empty {}]
+}
+
+
+
+# set context
+set context "Administration"
+
+# update caption for toolbar
+if $editing_namespace {
+
+    # set to edit
+    set caption "edit '$service'"
+	
+    # create namespace var for help
+    set namespace [format "::sg::%s" $service]
+	
+} else {
+
+    # set to create
+    set caption "create service"
+}
+
+ad_return_template
Index: openacs-4/packages/soap-gateway/www/admin/index-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/admin/index-postgresql.xql,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/admin/index-postgresql.xql	17 Oct 2004 05:51:57 -0000	1.1
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+
+<queryset>
+  <rdbms><type>postgresql</type><version>7.1</version></rdbms>
+
+  <fullquery name="namespace_list">
+    <querytext>
+    select namespace_id, service, uri, notes from sg_namespaces
+    </querytext>
+  </fullquery>
+</queryset>
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/www/admin/index.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/admin/index.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/admin/index.adp	17 Oct 2004 05:51:57 -0000	1.1
@@ -0,0 +1,126 @@
+<master src="../master">
+<!-- property name="context">@context@</property -->
+<include src="../toolbar" caption="@caption@">
+<!-- link href="basic.css" rel="stylesheet" type="text/css" -->
+<if @namespaces:rowcount@ gt 0>
+<a name="top"></a>
+<table width="800" border=1 cellpadding=2 cellspacing=2>
+  <tr> 
+	<td width="91" bgcolor=#cccccc><strong>Service</strong></td>
+	<td width="472" bgcolor=#cccccc><strong>Notes</strong></td>
+	<td width="50" bgcolor=#cccccc><strong>Status</strong></td>
+	<td width="37" bgcolor=#cccccc><strong>Edit</strong></td>
+	<td width="47" bgcolor=#cccccc><strong>Delete</strong></td>
+	<td width="51" bgcolor=#cccccc><strong>WSDL</strong></td>
+  </tr>
+  <multiple name="namespaces" rowcount=1> 
+  <tr> 
+	<td> <a href="#@namespaces.service@">
+	  @namespaces.service@
+	  </a> </td>
+	<td> 
+	  @namespaces.notes;noquote@&nbsp;
+	</td>
+	<td>@namespaces.status;noquote@</td>
+	<td><a href="@namespaces.edit@">edit</a></td>
+	<td><a href="@namespaces.delete@">delete</a></td>
+	<td><a href="@namespaces.wsdl@">wsdl</a></td>
+  </tr>
+  </multiple> 
+</table>
+
+</if><else>
+<p><em>There are no namespaces</em></p>
+</else> 
+<hr>
+<p><strong><u>Maintenance</u></strong></p>
+<ul>
+  <li><a href="libraries">Manage source libraries</a>.</li>
+  <!-- li><a href="edit-namespace">Create new namespace</a></li -->
+<if @unpublished:rowcount@ gt 0>
+  <multiple name="unpublished" rowcount=0> 
+  <li>Import the following unpublished service: <a href="edit-namespace?service=@unpublished.service@&import=1">@unpublished.service@</a></li>
+  </multiple>
+</if>
+<if @ru_invoke@ eq 0>
+<b><em><font color="#FF0000"><li>
+Registered Users do not have 'invoke' privileges on the soap-gateway package! Go to Permissions.
+</li></font></em></b>
+</if> 
+<if @pu_read@ eq 0>
+<b><em><font color="#FF0000"><li>
+The Public do not have 'read' privileges on the soap-gateway package! This may restrict clients from downloading WSDL service specifications. Go to Permissions.
+</if> 
+</li></font></em></b>
+</ul>
+<p>Note: Only public procedures within the sg::&lt;my-namespace&gt;::* will be 
+  imported. Comments are extracted<br>
+  from the source files and can modified once imported.</p>
+
+<if @namespaces:rowcount@ gt 0> <multiple name="namespaces"> 
+<hr size="1" width="800" align="left">
+<table width="800" border="0">
+  <tr>
+	<td width="129"><b><a name="@namespaces.service@"></a>Service:</b></td>
+	<td width="636"><b>
+	  @namespaces.service@
+	  </b>&nbsp;</td>
+	<td width="21"><a href="#"><img src="../top.gif" width="12" height="12" border="0"></a></td>
+  </tr>
+  <tr>
+	<td><b>Endpoint:</td>
+	<td></b><a href="@namespaces.endpoint@">
+	  @namespaces.endpoint@
+	  </a></td>
+	<td>&nbsp;</td>
+  </tr>
+  <tr>
+	<td><b>WSDL:</td>
+	<td></b><a href="@namespaces.wsdl@">
+	  @namespaces.wsdl@
+	  </a></td>
+	<td>&nbsp;</td>
+  </tr>
+  <tr>
+	<td>&nbsp;<em>force response:</em></td>
+	<td><a href="@namespaces.wsdl@&amp;oneway=0">
+	  @namespaces.wsdl@
+	  &amp;oneway=0</a></td>
+	<td>&nbsp;</td>
+  </tr>
+  <tr>
+	<td>&nbsp;<em>no documentation:</em></td>
+	<td><a href="@namespaces.wsdl@&amp;documentation=0">
+	  @namespaces.wsdl@
+	  &amp;documentation=0</a></td>
+	<td>&nbsp;</td>
+  </tr>
+  <tr>
+	<td>&nbsp;<em>trace:</em></td>
+	<td><a href="@namespaces.wsdl@&amp;trace=http://localhost:8080">
+	  @namespaces.wsdl@
+	  &amp;trace=http://localhost:8080</a></td>
+	<td>&nbsp;</td>
+  </tr>
+  <tr>
+	<td><b>URI</b></td>
+	<td>
+	  @namespaces.uri@
+	</td>
+	<td>&nbsp;</td>
+  </tr>
+  <tr>
+	<td><b>SOAPAction</b></td>
+	<td>N/A</td>
+	<td>&nbsp;</td>
+  </tr>
+  <tr>
+	<td valign="top"><b>Notes:</td>
+	<td></b>
+	  @namespaces.notes;noquote@&nbsp;<a href="../doc/service?service=@namespaces.service@">(more)</a>
+	</td>
+	<td>&nbsp;</td>
+  </tr>
+</table>
+</multiple>
+</if>
Index: openacs-4/packages/soap-gateway/www/admin/index.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/admin/index.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/admin/index.tcl	17 Oct 2004 05:51:57 -0000	1.1
@@ -0,0 +1,97 @@
+# packages/soap-gateway/www/admin/index.tcl
+
+ad_page_contract {
+
+    @author WilliamB@ByrneLitho.com
+    @creation-date 2002-12-23
+    @cvs-id $Id: index.tcl,v 1.1 2004/10/17 05:51:57 ncarroll Exp $
+} {
+}
+
+# clear title
+set title {}
+
+# installed correctly
+if [catch {
+
+    soap::server::lib::true 1
+	
+}] {
+
+    # report as installation error
+    error "Failure while calling soap-gateway function!\nDid you restart the server after installing soap-gateway package?\n\n"
+
+}
+
+# get package id
+set package_id [ad_conn package_id]
+
+# require read permission 
+ad_require_permission $package_id admin
+
+# query namespaces
+db_multirow -extend {endpoint edit delete wsdl status} namespaces namespace_list {} {
+    set endpoint [soap::wsdl::build_endpoint $service]
+    set edit "edit-namespace?namespace_id=$namespace_id"
+    set delete "delete-namespace?namespace_id=$namespace_id"
+    set wsdl [soap::wsdl::build_wsdl_url $service]
+	
+    # check for problems
+    set diffs [soap::diff_methods $service]
+    if { [llength $diffs] > 0 } {
+	set status "<font color=\"#CC0000\">errors</font>"
+    } else {
+	set status "<font color=\"#00CC00\">ok</font>"
+    }
+}
+
+# get permission for object
+
+# get registered users
+set users [acs_magic_object registered_users]
+
+# test for invoke privileges on package for Registered_users
+set ru_invoke [soap::server::has_permission -user_id $users $package_id [soap::server::get_invoke_permission_moniker]]
+
+# get public 
+set public [acs_magic_object the_public]
+
+# test for public read access on WSDL
+set pu_read 1;#[soap::server::has_permission -user_id $public  $package_id read]
+
+# create form
+template::form create new_namespace_form
+
+# change action attribute for form - not documented
+set new_namespace_form:properties(action) edit-namespace
+
+# create form
+template::form create init_workspace_form
+
+# change action attribute for form - not documented
+set init_workspace_form:properties(action) init-workspace
+
+# create form
+template::form create init_interop_form
+
+# change action attribute for form - not documented
+set init_interop_form:properties(action) init-interop
+
+# create unpublished rowset
+multirow create unpublished service
+
+# get unpublished
+foreach s [soap::query_services -unpublished 1 -published 0] {
+
+    # add to multirow
+    multirow append unpublished $s
+
+}
+
+# set context
+set context "Administation"
+
+# update caption
+set caption "admin"
+
+ad_return_template
Index: openacs-4/packages/soap-gateway/www/admin/libraries-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/admin/libraries-postgresql.xql,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/admin/libraries-postgresql.xql	17 Oct 2004 05:51:57 -0000	1.1
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+
+<queryset>
+  <rdbms><type>postgresql</type><version>7.1</version></rdbms>
+
+  <fullquery name="library_list">
+    <querytext>
+      select library_id, path from sg_libraries
+    </querytext>
+  </fullquery>
+</queryset>
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/www/admin/libraries.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/admin/libraries.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/admin/libraries.adp	17 Oct 2004 05:51:57 -0000	1.1
@@ -0,0 +1,64 @@
+<master src="../master"> 
+<!-- property name="context">@context@</property -->
+<include src="../toolbar" caption="@caption@">
+<a name="top"></a> 
+<p> Enter the locations of the source files that will be available for importing 
+  into the soap-gateway.<br>
+  Relative locations will be appended to the <em>acs_root </em>directory. Directory 
+  watches will be converted<br>
+  to wildcard notation and will not recurse; e.g., soap-gateway/lib/*.tcl. The 
+  files are <em>watched</em> by the<br>
+  Request Processor. <a href="libraries">Refresh</a> to update status.</p>
+<p>Once the source files are loaded, go back to the <a href=".">admin</a> and 
+  import the services into the soap-gateway.<br>
+</p>
+<formtemplate id="library_form"> 
+<table width="800" border=1 cellpadding=2 cellspacing=2>
+  <tr> 
+	<td width="760" bgcolor=#cccccc><strong>Path</strong></td>
+	<td width="20" bgcolor=#cccccc><strong>Status</strong></td>
+	<td width="20" bgcolor=#cccccc><strong>Watch</strong></td>
+  </tr>
+  <multiple name="libraries"> 
+  <tr> 
+	<td> 
+	  @libraries.path@</a>
+	  </td>
+	<td> 
+	  @libraries.status;noquote@
+	</td>
+	<td><a href="@libraries.remove@">remove</a></td>
+  </tr>
+  </multiple> 
+  <tr> 
+	<td><formwidget id="path"></a></td>
+	<td>&nbsp;</td>
+	<td><a href="javascript:document.library_form.submit();">add</a></td>
+  </tr>
+</table>
+</formtemplate><br>
+<table width="99%" border="0">
+  <tr> 
+	<td width="4%">&nbsp;</td>
+	<td width="10%"><u><strong>Status</strong></u></td>
+	<td width="86%"><u><strong>Meaning</strong></u></td>
+  </tr>
+  <tr> 
+	<td>&nbsp;</td>
+	<td><font color="red">???</font></td>
+	<td>Library path returned no tcl source files</td>
+  </tr>
+  <tr> 
+	<td>&nbsp;</td>
+	<td><font color="#00CC00">ok</font></td>
+	<td>All file timestamps in the path spec. coincide with APM</td>
+  </tr>
+  <tr> 
+	<td>&nbsp;</td>
+	<td><font color="red">stale</font></td>
+	<td>At least one file timestamp in the path spec. does not coincide with APM</td>
+  </tr>
+</table>
+<p>
+  @stat@
+</p>
Index: openacs-4/packages/soap-gateway/www/admin/libraries.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/admin/libraries.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/admin/libraries.tcl	17 Oct 2004 05:51:57 -0000	1.1
@@ -0,0 +1,122 @@
+# packages/soap-gateway/www/admin/libraries.tcl
+
+ad_page_contract {
+
+    @author WilliamB@ByrneLitho.com
+    @creation-date 2002-12-23
+    @cvs-id $Id: libraries.tcl,v 1.1 2004/10/17 05:51:57 ncarroll Exp $
+    
+} {
+    library_id:integer,notnull,optional
+    {delete 0}
+    {path {}}
+    {update 0}
+    {force 0}
+}
+
+# get package id
+set package_id [ad_conn package_id]
+
+# require read permission 
+ad_require_permission $package_id admin
+
+# clear status
+set stat {}
+
+# test for delete
+if [soap::server::lib::true $delete] {
+    
+    # get current
+    set current [soap::server::lib::library_get_path $library_id]
+    
+    # delete
+    soap::server::lib::library_delete $library_id
+    
+    # stop watch
+    soap::server::lib::watch -stop 1 $current
+    
+} elseif { $path != {} } {
+    
+    # test for update
+    if [info exists library_id] {
+	
+	# get current
+	set current [soap::server::lib::library_get_path $library_id]
+	
+	# stop watch
+	soap::server::lib::watch -stop 1 $current
+	
+	# update
+	soap::server::lib::library_update $library_id $path
+	
+	# update - implicit watch
+	soap::server::lib::update_libraries [list $path]
+	
+    } else {
+	
+	if [catch {
+	    
+	    # create new library
+	    soap::server::lib::library_new $path
+	    
+	}] {
+	    
+	    # report
+	    set stat "Error creating new library path:<br>&nbsp;&nbsp;<em>$path</em><br>Possible duplicate."		
+	    
+	} else {
+	    
+	    # update - implicit watch
+	    soap::server::lib::update_libraries [list $path]
+	    
+	}
+    }    
+    
+} elseif [soap::server::lib::true $update] {
+    
+    # get path from id
+    set path [soap::server::lib::library_get_path $library_id]
+    
+    # update
+    soap::server::lib::update_libraries [list $path]
+    
+}
+
+# query namespaces
+db_multirow -extend {status remove} libraries library_list {} {
+    set remove "libraries?library_id=$library_id&delete=1"
+    if ![soap::server::lib::is_library_valid $path] {
+	set status "<font color=\"red\">???</font>"
+    } elseif [soap::server::lib::is_library_dirty $path] {
+	#set status "<font color=\"red\">stale</font>"
+	set status "<a href=\"libraries?library_id=$library_id&update=1\" style=\"color: red\">stale</a>"
+    } else {
+	set status "<font color=\"#00CC00\">ok</font>"
+    }
+    
+}
+
+# clear path
+set path {}
+
+# create form
+template::form create library_form
+
+# build path input field
+template::element create library_form path \
+    -datatype text \
+    -label "Path" \
+    -html { size "100%" } \
+    -value {}; 
+
+# set up path
+template::element set_value library_form path "packages/<your-package>/lib/<your-source>.tcl"
+
+# set context
+set context "Administation"
+
+# update caption
+set caption "admin"
+
+# return template
+ad_return_template
Index: openacs-4/packages/soap-gateway/www/doc/folder.gif
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/doc/folder.gif,v
diff -u
Binary files differ
Index: openacs-4/packages/soap-gateway/www/doc/html.bmp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/doc/html.bmp,v
diff -u
Binary files differ
Index: openacs-4/packages/soap-gateway/www/doc/index.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/doc/index.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/doc/index.adp	17 Oct 2004 05:52:00 -0000	1.1
@@ -0,0 +1,120 @@
+<master src="@master@">
+<property name="context">@context@</property>
+<property name="context_bar">@context_bar@</property>
+<include src="../toolbar" caption="@caption@">
+<p><strong><font size="4" face="Arial, Helvetica, sans-serif"><a name="top"></a>soap-gateway</font></strong> 
+</p>
+<p>William Byrne / <a href="mailto:WilliamB@ByrneLitho.com">WilliamB@ByrneLitho.com</a></p>
+<p>An experimental OpenACS SOAP package that may prove itself useful. </p>
+<p>Developed using the following system configuration:</p>
+<ul>
+  <li>RedHat 7.3</li>
+  <li>OpenACS 4.5 (nightly snapshot 10/3/2002) </li>
+  <li>AOLServer 3.3ad13</li>
+  <li>nsxml 1.4 </li>
+  <li>PostgreSQL 7.2.1</li>
+</ul>
+<p class="section"></p>
+<p><u><strong><a name="abstract"></a><span class="section">Abstract </span></strong></u></p>
+<p class="text">The soap-gateway is a compilation of server side tcl procedures 
+  and pages that provide Remote Procedure Call (RPC) capabilities to OpenACS servers 
+  for clients using SOAP/HTTP. The implementation is relatively small and maintains 
+  minimal conformity to current SOAP specifications. This document describes the 
+  basic implementation.</p>
+<p class="section"><u><a name="toc"></a>Table of Contents</u></p>
+<ol>
+  <li><a href="#Overview">Overview</a></li>
+  <li><a href="#Installation">Installation</a></li>
+  <li><a href="#Samples" title="Table of Contents">Samples</a></li>
+  <li><a href="#References">References</a></li>
+  <li><a href="#License">License</a></li>
+</ol>
+<p><a name="Overview" class="section"><u>Overview</u></a> <a href="#TOC" title="Table of Contents">(toc)</a></p>
+<p>The Simple Object Access Protocol (<a href="#SOAPv12">SOAP</a>) <a href="#SOAPv11">v1.1</a> 
+  was <a href="#SOAPSubmission">submitted</a> to W3C on April 18, 2000. Its compatriot 
+  Web Services Description Language (<a href="#WSDLv11">WSDL</a>) was <a href="#WSDLSubmission">submitted</a> 
+  on March 14, 2001. Together they attempt to unify diverse systems using a form 
+  of XML RPC. Most major software vendors are involved to some extent. Its future 
+  looks bright. </p>
+<p>SOAP fits nicely into the Client/Server topology. Given a client that needs 
+  some functionality available on a server, SOAP can be used to specify an operation 
+  and its arguments to be submitted by the client to the server. At it's root, 
+  the data representing the operation is fairly basic. If the connection between 
+  the client and server were a TCP wire, a data trace would show about a page 
+  of XML. The XML is not complex and is often decipherable at a glance. The XML 
+  data is specified as a <a href="#SOAPv11">SOAP Envelope</a>. An evolving <a href="#SOAPv12">SOAP 
+  specification</a> defines the Envelope and its progeny. The XML data transmitted 
+  between the client and server is not arbitrary and should conform to a referenced 
+  WSDL instance published by the server. It's the WSDL that defines the published 
+  services and the invocation formats required for execution. The vast majority 
+  of SOAP documentation demonstrates SOAP over HTTP. Another mentioned transport 
+  is SMTP. In each case, the SOAP Envelope follows the respective header as an 
+  XML Payload.</p>
+<p>Many web servers have been retrofitted to support a SOAP subsystem; e.g., Websphere, 
+  Apache, iPlanet, IIS, etc. There are a handful of SOAP toolkits. To name a few, 
+  <a href="#MSSOAP">MSSOAP Toolkit</a> from Microsoft, <a href="#Axis">AXIS</a> 
+  from Apache, and <a href="#DataSnap">DataSnap</a> from Borland. A stand alone 
+  Tcl implementation, <a href="#TclSOAP">TclSOAP,</a> is available at Source Forge. 
+  In the <a href="#Implementation">Implementation</a> section, I'll get into the 
+  details of my retrofit for OpenACS; the soap-gateway package. Client SOAP examples 
+  using MSSOAP and AXIS can be found in the <a href="#Samples">Samples</a> section.</p>
+<p><a name="Installation" id="Installation"></a><u><span class="section">Installation</span></u> 
+  <a href="#TOC" title="Table of Contents">(toc)</a></p>
+<p class="text">Here's a short list of steps required to enable SOAP/HTTP connectivity 
+  to your server. The instructions are brief and assumes the reader has 
+  administrative experience with OpenACS. More details will be available in 
+  a subsequent release.</p>
+<ol>
+  <li>Select the SOAP Gateway from the list of packages that are available for 
+	installation. Install it.</li>
+  <li>Create a sub-site under the Main site and call it 'soap'. </li>
+  <li>Create a new application by selecting the SOAP Gateway.</li>
+  <li>For now, call the new soap-gateway application SOAP Gateway. </li>
+  <li>Refresh this page so <a href="@base@admin" title="Adminitration">this admin 
+	hot link</a> points to the soap-gateway admininistration pages.</li>
+  <li>Under the Maintenance section, you should see unpublished services: 'workspace' 
+	and 'interop'. Import both.</li>
+  <li>In the same section, you may see a message that indicates 'Registered Users' 
+	do not have 'invoke' access on the soap-gateway package. If so, go to the 
+	<a href="@permissions@" title="Permissions">permissions</a> area for the soap-gateway 
+	instance if you wish to grant 'invoke' rights to registered users.</li>
+  <li>Go to the <a href="#Samples">Samples</a> section and try the test samples. 
+	Take note of the https warning when https'ing.</li>
+</ol>
+<p><strong>Note:</strong> Verify 'public' access to your installed 'soap-gateway' 
+  using <em>http</em> and not <em>https</em>. Select the <a href="@base@">home</a> 
+  of your 'soap-gateway' subsite to retrieve a listing of available services. 
+  Also verify the WSDL for each service can be returned without the need to authenticate 
+  into your server. This will allow clients to enumerate the published services 
+  and retrieve the functional specification for each. Eliminating the need to 
+  authenticate with the server for the purpose of retrieving service WSDLs removes 
+  binding complications for client side SOAP tools.</p>
+<p>When importing a tcl library into the soap-gateway (i.e., any public methods 
+  under the ::sg::&lt;my-service&gt; namespace), the soap-gateway automatically 
+  grants public 'invoke' rights to any method named 'login'. This gives the client 
+  an opportunity to authenticate into the server before making any other calls.</p>
+<p>Service libraries shipped with the soap-gateway are located in <em>packages/soap-gateway/lib</em>.</p>
+<p><a name="Samples"><u class="section">Samples</u></a> <a href="#TOC" title="Table of Contents">(toc)</a></p>
+<p>Sample SOAP client applications can be found <a href="@base@tests">here</a>. </p>
+<p><a name="References" class="section"><u>References</u></a> <a href="#TOC" title="Table of Contents">(toc)</a></p>
+<ul>
+  <li><a name="SOAPSubmission"></a>Simple Object Access Protocol (SOAP) Submission 
+    <a href="http://www.w3.org/Submission/2000/05/" title="SOAP Submission" target="_blank">http://www.w3.org/Submission/2000/05/</a></li>
+  <li><a name="WSDLSubmission"></a>Web Services Description Language (WSDL) Submission 
+    <a href="http://www.w3.org/Submission/2001/07/" title="WSDL Submission" target="_blank">http://www.w3.org/Submission/2001/07/</a></li>
+  <li><a name="SOAPv11"></a>SOAP v1.1 <a href="http://www.w3.org/TR/SOAP/" title="SOAP v1.1" target="_blank">http://www.w3.org/TR/SOAP/</a></li>
+  <li><a name="SOAPv12"></a>SOAP v1.2 Message Framework <a href="http://www.w3.org/TR/soap12-part1/" title="SOAP v1.2 Part 1" target="_blank">http://www.w3.org/TR/soap12-part1/</a></li>
+  <li><a name="WSDLv11"></a>WSDL v1.1 <a href="http://www.w3.org/TR/wsdl" title="WSDL v1.1" target="_blank">http://www.w3.org/TR/wsdl</a></li>
+  <li>XML Schema Part 0: Primer <a href="http://www.w3.org/TR/xmlschema-0/" title="XML Schema Part 0" target="_blank">http://www.w3.org/TR/xmlschema-0/</a></li>
+  <li>XML Schema Part 1: Structures <a href="http://www.w3.org/TR/xmlschema-1/" title="XML Schema Part 1" target="_blank">http://www.w3.org/TR/xmlschema-1/</a></li>
+  <li>XML Schema Part 2: Datatypes <a href="http://www.w3.org/TR/xmlschema-2/" title="XML Schema Part 2" target="_blank">http://www.w3.org/TR/xmlschema-2/</a></li>
+  <li><a name="MSSOAP"></a>Microsoft SOAP Toolkit <a href="http://msdn.microsoft.com/soap/" title="MS SOAP Toolkit" target="_blank">http://msdn.microsoft.com/soap/</a></li>
+  <li><a name="Axis"></a>Apache AXIS <a href="http://xml.apache.org/axis/" title="Apache AXIS" target="_blank">http://xml.apache.org/axis/</a></li>
+  <li><a name="DataSnap">Borland DataSnap</a> <a href="http://www.borland.com/delphi/dsnap/index.html" title="Borland DataSnap">http://www.borland.com/delphi/dsnap/index.html</a></li>
+  <li><a name="TclSOAP">TclSOAP </a><a href="http://tclsoap.sourceforge.net/" title="TclSOAP" target="_blank">http://tclsoap.sourceforge.net/</a></li>
+</ul>
+<p><a name="License" class="section" id="License"><u>License</u></a> <a href="#TOC" title="Table of Contents">(toc)</a></p>
+<p>The SOAP Gateway package is subject to the <a href="license.txt">Lesser General 
+  Public License</a>.</p>
+</body>
+</html>
Index: openacs-4/packages/soap-gateway/www/doc/index.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/doc/index.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/doc/index.tcl	17 Oct 2004 05:52:00 -0000	1.1
@@ -0,0 +1,59 @@
+# packages/soap-gateway/www/doc/index.tcl
+
+ad_page_contract {
+    
+    @author WilliamB@ByrneLitho.com
+    @creation-date 2002-12-23
+    @cvs-id $Id: index.tcl,v 1.1 2004/10/17 05:52:00 ncarroll Exp $
+} {
+}
+
+# get package id
+set package_id [ad_conn package_id]
+
+# require read permission 
+ad_require_permission $package_id read
+
+# set context
+set context Documentation
+
+# set context bar
+set context_bar [ad_context_bar]
+
+# update caption
+set caption "help"
+
+# try
+if [catch {
+
+    # get href base
+    set base [soap::get_base_url]
+
+}] {
+
+    # report as installation error
+    error "Failure while calling soap-gateway function!\nDid you restart the server after installing soap-gateway package?\n\n"
+
+}
+
+# get package id
+set pid [soap::package_id -throw f]
+
+# set href
+set permissions "/permissions/one?object_id=$pid"
+
+# get master
+if { 1 || ![string equal [ad_conn package_key] "soap-gateway"] } {
+
+    # ???
+    set master "/packages/soap-gateway/www/master"
+	
+} else {
+
+    # same place as base
+    set master "./$base/master"
+
+}
+
+# return template
+ad_return_template
Index: openacs-4/packages/soap-gateway/www/doc/license.txt
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/doc/license.txt,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/doc/license.txt	17 Oct 2004 05:52:01 -0000	1.1
@@ -0,0 +1,20 @@
+soap-gateway package for OpenACS
+Copyright (C) 2003  William Byrne 
+
+This library 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.1 of the License, or (at your option) any later version.
+
+This library 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 this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+William Byrne
+WilliamB@ByrneLitho.com
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/www/doc/service-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/doc/service-postgresql.xql,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/doc/service-postgresql.xql	17 Oct 2004 05:52:01 -0000	1.1
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+
+<queryset>
+  <rdbms><type>postgresql</type><version>7.1</version></rdbms>
+
+  <fullquery name="namespace_select">
+    <querytext>
+      select service, uri, notes
+        from sg_namespaces
+	where namespace_id = :nid
+    </querytext>
+  </fullquery>
+
+  <fullquery name="methods_select">
+    <querytext>
+      select method_id, namespace_id, method, idl, idl_style, notes 
+	from sg_methods
+	where namespace_id = :nid
+	order by method;
+    </querytext>
+  </fullquery>
+
+</queryset>
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/www/doc/service.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/doc/service.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/doc/service.adp	17 Oct 2004 05:52:01 -0000	1.1
@@ -0,0 +1,27 @@
+<master src="../master">
+<property name="context">@context@</property>
+<include src="../toolbar" caption="@caption@">
+<table border="0">
+<tr><td width="20"></td><td width="580">
+@service_notes@
+</td></td>
+</table>
+<table border="0">
+
+<multiple name="methods"> 
+<tr><td width="20"></td><td>
+<table width="580" >
+<tr style="margin-top: 8px"><td width="600">
+<hr size="1">
+<font face="Courier New, Courier, mono">
+@methods.pretty;noquote@
+</font>
+</td></tr>
+<tr><td>
+@methods.notes;noquote@
+</td></tr>
+</table>
+</td></tr>
+</multiple> 
+
+</table>
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/www/doc/service.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/doc/service.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/doc/service.tcl	17 Oct 2004 05:52:01 -0000	1.1
@@ -0,0 +1,90 @@
+# packages/soap-gateway/www/doc/service.tcl
+
+ad_page_contract {
+
+  @author WilliamB@ByrneLitho.com
+  @creation-date 2002-12-23
+  @cvs-id $Id: service.tcl,v 1.1 2004/10/17 05:52:01 ncarroll Exp $
+} {
+	service:notnull
+}
+
+# get package id
+set package_id [ad_conn package_id]
+
+# require read permission 
+ad_require_permission $package_id read
+
+# get namespace id
+set nid [soap::server::namespace_get_id $service]
+
+# check
+if { $nid < 0 } {
+	# throw
+	soap::fault::raise "Invalid service: $service"
+}
+
+# query for namespace attributes
+db_1row namespace_select {}
+
+# preserve
+set service_notes $notes
+
+# query methods
+db_multirow -extend {pretty} methods methods_select {} {
+
+	# set up regexp expression for "C" style function 
+	set expr [soap::wsdl::get_style_parser_expr C]
+	
+	# invoke regexp
+	regexp $expr $idl {} rtyp meth argz
+	
+	# get arg parser expr
+	set expr [soap::wsdl::get_style_parser_expr -argpart 1 C]
+	
+	# decl pretty args
+	set pargs {}
+	
+	# loop through args
+	foreach a [split $argz ,] {
+		
+		# split arg type from its name
+		if ![regexp $expr $a {} atyp nam] {
+		
+			# format problem
+			error "unexpected argument format: $a"
+		
+		}
+		
+		# add arg 
+		if { $pargs == {} } {
+
+			# set
+			set pargs "<font color=\"blue\">$atyp</font> $nam"
+		
+		} else {
+
+			# append
+			append pargs ", <font color=\"blue\">$atyp</font> $nam"
+		
+		}
+	
+	}
+	
+	# make pretty
+	set pretty "<font color=\"blue\">$rtyp</font> <b>$meth</b>($pargs)"
+
+}
+
+# set context
+set context [list Documentation]
+
+# update caption
+set caption "$service service"
+
+# return template
+ad_return_template
+
+
+
+
Index: openacs-4/packages/soap-gateway/www/doc/tcl.gif
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/doc/tcl.gif,v
diff -u
Binary files differ
Index: openacs-4/packages/soap-gateway/www/doc/text.gif
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/doc/text.gif,v
diff -u
Binary files differ
Index: openacs-4/packages/soap-gateway/www/doc/www.gif
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/doc/www.gif,v
diff -u
Binary files differ
Index: openacs-4/packages/soap-gateway/www/tests/index.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/tests/index.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/tests/index.adp	17 Oct 2004 05:52:02 -0000	1.1
@@ -0,0 +1,19 @@
+<master src="../master">
+<property name="context">@context@</property>
+<include src="../toolbar" caption="@caption@">
+<p><font face="Arial, Helvetica, sans-serif"><strong>Limited interoperability 
+  tests</strong></font></p>
+<p><a href="mssoap" title="Microsoft SOAP Toolkit">Using Microsoft 
+  SOAP Toolkit</a></p>
+<p><a href="axis">Using Apache AXIS Toolkit</a></p>
+<p>Refer to the <a href="@documentation@">soap-gateway documentation</a> for more 
+  information on how to get the SOAP toolkits.</p>
+<if @http@ not nil>
+<p><em><strong><font color="#FF0000">SSL connections, SOAP/HTTPS, may not work 
+  correctly. For testing, try launching the demo's using <a href="@http@">http</a> 
+  instead of https. Service Side Certificates need to be trusted by the Client 
+  software without the need for user confirmation. In other words, the SOAP toolkits 
+  can't handle popup dialogs very well. And we usually get dialogs when the Server's 
+  Certificate cannot be chained to a trusted authority. Free certificates are 
+  available from freessl.com.</font></strong></em></p>
+</if>
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/www/tests/index.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/tests/index.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/tests/index.tcl	17 Oct 2004 05:52:02 -0000	1.1
@@ -0,0 +1,36 @@
+# packages/soap-gateway/www/tests/index.tcl
+
+ad_page_contract {
+
+  @author WilliamB@ByrneLitho.com
+  @creation-date 2002-12-23
+  @cvs-id $Id: index.tcl,v 1.1 2004/10/17 05:52:02 ncarroll Exp $
+} {
+}
+
+# get package id
+set package_id [ad_conn package_id]
+
+# require read permission 
+ad_require_permission $package_id read
+
+# set documentation path
+set documentation [file join [ad_conn object_url] doc]
+
+# set context
+set context "Tests"
+
+# update caption
+set caption "tests"
+
+# is this connection secure
+if [ad_secure_conn_p] {
+
+	# calc http name
+	set http [format "http://%s%s"  [ns_info hostname] [file join / [soap::get_base_url] tests]]
+
+}
+
+# return template
+ad_return_template
+
Index: openacs-4/packages/soap-gateway/www/tests/axis/axis.zip
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/tests/axis/axis.zip,v
diff -u
Binary files differ
Index: openacs-4/packages/soap-gateway/www/tests/axis/index.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/tests/axis/index.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/tests/axis/index.adp	17 Oct 2004 05:52:04 -0000	1.1
@@ -0,0 +1,5 @@
+<master src="../../master">
+<property name="context">@context@</property>
+<include src="../../toolbar" caption="@caption@">
+Download the following <a href="axis.zip">archive</a> and refer to the enclosed documentation.<br>
+See the <a href="@references@">references</a> section for links to AXIS.
\ No newline at end of file
Index: openacs-4/packages/soap-gateway/www/tests/axis/index.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/tests/axis/index.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/tests/axis/index.tcl	17 Oct 2004 05:52:04 -0000	1.1
@@ -0,0 +1,27 @@
+# packages/soap-gateway/www/test/axis/index.tcl
+
+ad_page_contract {
+
+  @author WilliamB@ByrneLitho.com
+  @creation-date 2002-12-23
+  @cvs-id $Id: index.tcl,v 1.1 2004/10/17 05:52:04 ncarroll Exp $
+} {
+}
+
+# get package id
+set package_id [ad_conn package_id]
+
+# require read permission 
+ad_require_permission $package_id read
+
+# set context
+set context [list [list .. Tests] {AXIS}]
+
+# update caption
+set caption "axis toolkit"
+
+# update references
+set references [file join [ad_conn object_url] doc #References]
+
+# return template
+ad_return_template
Index: openacs-4/packages/soap-gateway/www/tests/mssoap/bio-small.jpg
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/tests/mssoap/bio-small.jpg,v
diff -u
Binary files differ
Index: openacs-4/packages/soap-gateway/www/tests/mssoap/bio.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/tests/mssoap/bio.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/tests/mssoap/bio.adp	17 Oct 2004 05:52:05 -0000	1.1
@@ -0,0 +1,172 @@
+<master src="../../master">
+<property name="context">@context@</property>
+<include src="../../toolbar" caption="@caption@">
+<script language="VBScript">
+	
+	dim Stub
+	
+	sub window_onload
+	
+		' clear
+		set Stub = Nothing
+	
+	end sub
+	
+	sub DoInit
+	
+		' test 
+		if not Stub is Nothing then exit sub
+
+		' Create stub
+		set Stub = CreateObject("MSSOAP.SoapClient30")
+		
+		' specify desired service		
+		service = "workspace"
+
+		' get protocol and base location
+		base = location.protocol & "//" & location.host
+		
+		' build wsdl file location
+		WsdlFile = base & "/soap/wsdl?service=" & service
+		
+		' get trace
+		trace = document.frm.txtTrace.value
+		
+		' test
+		if trace <> "" then		
+		
+			' add trace info
+		 	WsdlFile = WsdlFile & "&trace=" & trace
+			
+		end if
+		
+		' test for oneway disable
+		if document.frm.chkOneway.checked then
+			
+			' add disable flag
+			WsdlFile = WsdlFile & "&oneway=0"
+			
+		end if
+		
+		' build service namespace
+		Namespace = "http://" & service & ".openacs.org/wsdl/"
+		
+		' initialize stub
+		Stub.MSSoapInit2 WsdlFile, "", service, service & "SoapPort", Namespace
+		
+		' disable
+		document.frm.chkOneway.disabled = True
+		document.frm.txtTrace.disabled = True
+		
+	end sub
+	
+	sub DoLogin
+
+		' init
+		DoInit
+	
+		' get form params
+		user = document.frm.txtUser.value
+		password = document.frm.txtPassword.value
+		
+		' invoke
+		call Stub.login(user, password)
+
+		' enabled/disable button
+		document.frm.btnLogin.disabled = True
+		document.frm.btnLogout.disabled = False
+		document.frm.txtFirstname.disabled = False
+		document.frm.txtLastname.disabled = False
+		document.frm.btnUpdate.disabled = False
+		
+		' get name
+		parts = Split(Stub.getName(), " ")
+		
+		' set first
+		document.frm.txtFirstname.value = Trim(parts(0))
+
+		' set last
+		if UBound(parts) > 0 then
+			document.frm.txtLastname.value = Trim(parts(1))
+		end if
+		
+		
+		
+	end sub
+	
+	sub DoLogout
+	
+		' init
+		DoInit
+
+		' invoke
+		call Stub.logout()
+
+		' enabled/disable button
+		document.frm.btnUpdate.disabled = True
+		document.frm.btnLogin.disabled = False
+		document.frm.btnLogout.disabled = True
+		document.frm.txtFirstname.disabled = True
+		document.frm.txtLastname.disabled = True
+		document.frm.txtFirstname.value = ""
+		document.frm.txtLastname.value = ""
+		document.frm.txtPassword.value = ""
+		
+	end sub
+	
+	sub DoUpdate
+
+		' init
+		DoInit
+
+		' get form params
+		firstname = document.frm.txtFirstname.value
+		lastname = document.frm.txtLastname.value
+		
+		' invoke 
+		call Stub.setName(firstname, lastname)
+		
+		' ok
+		MsgBox "OK"
+		
+	end sub
+	
+</script>
+<h3>workspace::setName</h3>
+<form name="frm">
+  <table width="320" height="114" border="1">
+	<tr> 
+	  <td align="left"> <input type="text" name="txtUser"> User<br>
+	  <input type="password" name="txtPassword"> Password </td>
+	</tr>
+	<tr> 
+	  <td align="center">
+	 <input name="btnLogin" type="button" onClick="DoLogin" value="Login" language="VBScript">
+		&nbsp;&nbsp; 
+		<input name="btnLogout" type="button" disabled="true" onClick="DoLogout" value="Logout" language="VBScript">
+	  </td>
+	</tr>
+  </table><br>
+  <table width="320" border="1">
+	<tr>
+	  <td height="61" align="left"> 
+		<input name="txtFirstname" type="text" disabled="true" id="txtFirstname">
+		First Name<br> 
+		<input name="txtLastname" type="text" disabled="true" id="txtLastname">
+		Last Name</td>
+	</tr>
+	<tr>
+	  <td height="43" align="center"> 
+		<input name="btnUpdate" type="button" disabled="true" id="btnUpdate" onClick="DoUpdate" value="Update" language="VBScript">
+	  </td>
+	</tr>
+  </table>
+  <br>
+  <table width="320" border="1" bordercolor="#000000">
+	<tr> 
+	  <td width="100%" bordercolor="#000000">Debug Trace (e.g., http://locahost:8080)<br> <input type="text" name="txtTrace"> 
+		<br> <input type="checkbox" name="chkOneway" checked="true">
+		Disable one-way's</td>
+	</tr>
+  </table>
+</form>
Index: openacs-4/packages/soap-gateway/www/tests/mssoap/bio.jpg
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/tests/mssoap/bio.jpg,v
diff -u
Binary files differ
Index: openacs-4/packages/soap-gateway/www/tests/mssoap/bio.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/tests/mssoap/bio.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/tests/mssoap/bio.tcl	17 Oct 2004 05:52:05 -0000	1.1
@@ -0,0 +1,24 @@
+# packages/soap-gateway/www/test/mssoap/index.tcl
+
+ad_page_contract {
+
+  @author WilliamB@ByrneLitho.com
+  @creation-date 2002-12-23
+  @cvs-id $Id: bio.tcl,v 1.1 2004/10/17 05:52:05 ncarroll Exp $
+} {
+}
+
+# get package id
+set package_id [ad_conn package_id]
+
+# require read permission 
+ad_require_permission $package_id read
+
+# set context
+set context [list [list .. Tests] {MS SOAP}]
+
+# update caption
+set caption "bio test"
+
+# return template
+ad_return_template
Index: openacs-4/packages/soap-gateway/www/tests/mssoap/echo-small.jpg
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/tests/mssoap/echo-small.jpg,v
diff -u
Binary files differ
Index: openacs-4/packages/soap-gateway/www/tests/mssoap/echo.jpg
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/tests/mssoap/echo.jpg,v
diff -u
Binary files differ
Index: openacs-4/packages/soap-gateway/www/tests/mssoap/index.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/tests/mssoap/index.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/tests/mssoap/index.adp	17 Oct 2004 05:52:05 -0000	1.1
@@ -0,0 +1,24 @@
+<master src="../../master">
+<property name="context">@context@</property>
+<include src="../../toolbar" caption="@caption@">
+<table width="640""0">
+  <tr>
+	<td> To run the following tests, you'll need IE and the <a href="@references@">MSSOAP 
+	  Toolkit</a><br>
+</td></tr>
+<tr><td>
+More than likely, you'll experience a security issue when attempting to instantiate the 
+MSSOAP Toolkit from within a page that originated from an untrusted server. Adding your trusted server to the list of <a href="trusted.jpg">Trusted Servers</a> in IE should help.
+</td></tr>
+</table>
+<br>
+<table width="499" height="394" border="1" align="center">
+  <tr> 
+	<td width="239" height="388" align="center" valign="bottom"> 
+	  <p><a href="echo.jpg"><img src="echo-small.jpg" width="200" height="303" border="0"></a></p>
+	  <p><a href="interop">Basic Interop Tests</a></p></td>
+	<td width="244" align="center" valign="bottom"> 
+	  <p><a href="bio.jpg"><img src="bio-small.jpg" width="194" height="285" border="0"></a></p>
+	  <p><a href="bio">User Bio</a></p></td>
+  </tr>
+</table>
Index: openacs-4/packages/soap-gateway/www/tests/mssoap/index.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/tests/mssoap/index.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/tests/mssoap/index.tcl	17 Oct 2004 05:52:05 -0000	1.1
@@ -0,0 +1,27 @@
+# packages/soap-gateway/www/test/mssoap/index.tcl
+
+ad_page_contract {
+
+  @author WilliamB@ByrneLitho.com
+  @creation-date 2002-12-23
+  @cvs-id $Id: index.tcl,v 1.1 2004/10/17 05:52:05 ncarroll Exp $
+} {
+}
+
+# get package id
+set package_id [ad_conn package_id]
+
+# require read permission 
+ad_require_permission $package_id read
+
+# set context
+set context [list [list .. Tests] {MS SOAP}]
+
+# update caption
+set caption "mssoap toolkit"
+
+# update references
+set references [file join [ad_conn object_url] doc #References]
+
+# return template
+ad_return_template
Index: openacs-4/packages/soap-gateway/www/tests/mssoap/interop.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/tests/mssoap/interop.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/tests/mssoap/interop.adp	17 Oct 2004 05:52:05 -0000	1.1
@@ -0,0 +1,198 @@
+<master src="../../master">
+<property name="context">@context@</property>
+<include src="../../toolbar" caption="@caption@">
+<script language="VBScript">
+	
+	dim Stub
+	
+	sub window_onload
+	
+		' clear
+		set Stub = Nothing
+	
+	end sub
+	
+	sub DoInit
+	
+		' test 
+		if not Stub is Nothing then exit sub
+
+		' Create stub
+		set Stub = CreateObject("MSSOAP.SoapClient30")
+		
+		' specify desired service		
+		service = "interop"
+
+		' get protocol and base location
+		base = location.protocol & "//" & location.host
+		
+		' build wsdl file location
+		WsdlFile = base & "/soap/wsdl?service=" & service
+		
+		' get trace
+		trace = document.frm.txtTrace.value
+		
+		' test
+		if trace <> "" then		
+		
+			' add trace info
+		 	WsdlFile = WsdlFile & "&trace=" & trace
+			
+		end if
+		
+		' test for oneway disable
+		if document.frm.chkOneway.checked then
+			
+			' add disable flag
+			WsdlFile = WsdlFile & "&oneway=0"
+			
+		end if
+		
+		' build service namespace
+		Namespace = "http://" & service & ".openacs.org/wsdl/"
+		
+		' initialize stub
+		Stub.MSSoapInit2 WsdlFile, "", service, service & "SoapPort", Namespace
+		
+		' disable
+		document.frm.chkOneway.disabled = True
+		document.frm.txtTrace.disabled = True
+		
+	end sub
+	
+	sub DoLogin
+
+		' init
+		DoInit
+	
+		' get form params
+		user = document.frm.txtUser.value
+		password = document.frm.txtPassword.value
+		
+		' invoke
+		call Stub.login(user, password)
+
+		' enabled/disable button
+		document.frm.btnLogin.disabled = True
+		document.frm.btnLogout.disabled = False
+		
+	end sub
+	
+	sub DoLogout
+	
+		' init
+		DoInit
+
+		' invoke
+		call Stub.logout()
+
+		' enabled/disable button
+		
+		document.frm.btnLogin.disabled = False
+		document.frm.btnLogout.disabled = True
+		
+	end sub
+	
+	sub DoEchoString
+
+		' init
+		DoInit
+
+		' get form params
+		echo = document.frm.txtEchoString.value
+		
+		' invoke and show results
+		MsgBox Stub.echoString(echo)
+		
+	end sub
+
+	sub DoEchoInteger
+
+		' init
+		DoInit
+
+		' get form params
+		echo = document.frm.txtEchoInteger.value
+		
+		' invoke and show results
+		MsgBox Stub.echoInteger(echo)
+		
+	end sub
+	
+	sub DoEchoFloat
+
+		' init
+		DoInit
+
+		' get form params
+		echo = document.frm.txtEchoFloat.value
+		
+		' invoke and show results
+		MsgBox Stub.echoFloat(echo)
+		
+	end sub
+
+	sub DoEchoVoid
+
+		' init
+		DoInit
+
+		' get form params
+		echo = document.frm.txtEchoVoid.value
+		
+		' invoke and show results
+		Stub.echoVoid
+		
+	end sub
+
+</script>
+<h3>interop::echo* test</h3>
+<form name="frm">
+  <table width="320" height="114" border="1">
+	<tr> 
+	  <td align="left"> <input type="text" name="txtUser"> User<br>
+	  <input type="password" name="txtPassword"> Password </td>
+	</tr>
+	<tr> 
+	  <td align="center">
+	 <input name="btnLogin" type="button" onClick="DoLogin" value="Login" language="VBScript">
+		&nbsp;&nbsp; 
+		<input name="btnLogout" type="button" disabled="true" onClick="DoLogout" value="Logout" language="VBScript">
+	  </td>
+	</tr>
+  </table>
+  <br>
+  <table width="320" border="1">
+	<tr> 
+	  <td width="61">String</td>
+	  <td width="161"><input name="txtEchoString" type="text" id="txtEchoString" value="this is an echo"></td>
+	  <td width="76" align="center"> 
+		<input name="btnEchoString" type="button" id="btnEchoString" onClick="DoEchoString" value="Echo" language="VBScript"> 
+	  </td>
+	</tr>
+	<tr> 
+	  <td>Integer</td>
+	  <td><input name="txtEchoInteger" type="text" id="txtEchoInteger" value="123456"></td>
+	  <td align="center"><input name="btnEchoInteger" type="button" id="btnEchoInteger" onClick="DoEchoInteger" value="Echo" language="VBScript"></td>
+	</tr>
+	<tr> 
+	  <td>Float</td>
+	  <td><input name="txtEchoFloat" type="text" id="txtEchoFloat" value="123.45"></td>
+	  <td align="center"><input name="btnEchoFloat" type="button" id="btnEchoFloat" onClick="DoEchoFloat" value="Echo" language="VBScript"></td>
+	</tr>
+	<tr> 
+	  <td>Void</td>
+	  <td><input name="txtEchoVoid" type="text" id="txtEchoVoid"></td>
+	  <td align="center"><input name="btnEchoVoid" type="button" id="btnEchoVoid" onClick="DoEchoVoid" value="Echo" language="VBScript"></td>
+	</tr>
+  </table>
+  <br>
+  <br>
+  <table width="320" border="1" bordercolor="#000000">
+	<tr> 
+	  <td width="100%" bordercolor="#000000">Debug Trace (e.g., http://locahost:8080)<br> <input type="text" name="txtTrace"> 
+		<br> <input type="checkbox" name="chkOneway" checked="true">
+		Disable one-way's</td>
+	</tr>
+  </table>
+</form>
Index: openacs-4/packages/soap-gateway/www/tests/mssoap/interop.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/tests/mssoap/interop.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/soap-gateway/www/tests/mssoap/interop.tcl	17 Oct 2004 05:52:05 -0000	1.1
@@ -0,0 +1,24 @@
+# packages/soap-gateway/www/test/mssoap/interop.tcl
+
+ad_page_contract {
+
+  @author WilliamB@ByrneLitho.com
+  @creation-date 2002-12-23
+  @cvs-id $Id: interop.tcl,v 1.1 2004/10/17 05:52:05 ncarroll Exp $
+} {
+}
+
+# get package id
+set package_id [ad_conn package_id]
+
+# require read permission 
+ad_require_permission $package_id read
+
+# set context
+set context [list [list .. Tests] {MS SOAP}]
+
+# update caption
+set caption "interop test"
+
+# return template
+ad_return_template
Index: openacs-4/packages/soap-gateway/www/tests/mssoap/trusted.jpg
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/soap-gateway/www/tests/mssoap/trusted.jpg,v
diff -u
Binary files differ