Index: fedd/fedd.py
===================================================================
--- fedd/fedd.py	(revision 0a47d52f26f152e6f38f4cc3c00274a3cb88a3ab)
+++ fedd/fedd.py	(revision bb3769ac25051bcf7f09fdfe67757a05f649195e)
@@ -123,8 +123,8 @@
 			    fedid(cert=self.request.get_peer_cert()))
 		data = xmlrpclib.dumps((resp,), methodresponse=True)
-	    except Fault, f:
-		xf = xmlrpclib.Fault(f.code, f.string)
-		data = xmlrpclib.dumps(xf, methodresponse=True)
-		resp = None
+	    #except Fault, f:
+	#	xf = xmlrpclib.Fault(f.code, f.string)
+	#	data = xmlrpclib.dumps(xf, methodresponse=True)
+	#	resp = None
 	    except xmlrpclib.Fault, f:
 		data = xmlrpclib.dumps(f, methodresponse=True)
Index: fedd/fedd_bindings.wsdl
===================================================================
--- fedd/fedd_bindings.wsdl	(revision 0a47d52f26f152e6f38f4cc3c00274a3cb88a3ab)
+++ fedd/fedd_bindings.wsdl	(revision bb3769ac25051bcf7f09fdfe67757a05f649195e)
@@ -22,10 +22,10 @@
 	<soap:operation soapAction=""/> 
 	<input>
-	  <soap:body use="encoded" part="tns:RequestAccessRequestBody"
+	  <soap:body use="encoded" parts="tns:RequestAccessRequestBody"
 	    namespace="http://www.isi.edu/faber/fedd.wsdl"
 	    encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
 	</input>
 	<output>
-	  <soap:body use="encoded" part="tns:RequestAccessResponseBody"
+	  <soap:body use="encoded" parts="tns:RequestAccessResponseBody"
 	    namespace="http://www.isi.edu/faber/fedd.wsdl"
 	    encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
Index: fedd/fedd_client.py
===================================================================
--- fedd/fedd_client.py	(revision 0a47d52f26f152e6f38f4cc3c00274a3cb88a3ab)
+++ fedd/fedd_client.py	(revision bb3769ac25051bcf7f09fdfe67757a05f649195e)
@@ -13,4 +13,7 @@
 from xmlrpclib import ServerProxy, Error, dumps, loads
 from ZSI import SoapWriter
+from ZSI.TC import QName, String, URI, AnyElement, UNBOUNDED, Any
+from ZSI.wstools.Namespaces import SOAP
+from ZSI.fault import FaultType, Detail
 
 import xmlrpclib
@@ -20,4 +23,6 @@
 
 from optparse import OptionParser, OptionValueError
+
+import parse_detail
 
 # Turn off the matching of hostname to certificate ID
@@ -269,4 +274,6 @@
 if opts.debug > 1: print >>sys.stderr, msg
 
+print FaultType.typecode;
+
 if opts.transport == "soap":
     loc = feddServiceLocator();
@@ -292,5 +299,11 @@
 	sys.exit("Malformed response (XMLPRC?): %s" % e)
     except ZSI.FaultException, e:
-	sys.exit("Fault: %s" % e)
+	print dir(e.fault.detail[0])
+	print e.fault.detail[0].RequestAccessFaultBody.get_element_code()
+	d = unpack_soap(e.fault.detail[0].get_element_RequestAccessFaultBody())
+	f = unpack_soap(e.fault.detail[0])
+	print "unpack ", d
+	print "unpack ", f
+	sys.exit("Fault: %s %s" % (str(e.fault.code), str(e.fault.string)))
 
 
Index: fedd/fedd_messages.wsdl
===================================================================
--- fedd/fedd_messages.wsdl	(revision 0a47d52f26f152e6f38f4cc3c00274a3cb88a3ab)
+++ fedd/fedd_messages.wsdl	(revision bb3769ac25051bcf7f09fdfe67757a05f649195e)
@@ -15,4 +15,8 @@
   </message>
 
+  <message name="RequestAccessFaultMessage">
+    <part name="RequestAccessFaultBody" type="xsd1:faultType"/>
+  </message>
+
 
   <portType name="feddPortType">
@@ -24,5 +28,5 @@
       <output message="tns:RequestAccessResponseMessage"/>
       <fault name="RequestAccessFault" 
-	message="tns:RequestAccessResponseMessage"/>
+	message="tns:RequestAccessFaultMessage"/>
     </operation>
   </portType>
Index: fedd/fedd_proj.py
===================================================================
--- fedd/fedd_proj.py	(revision 0a47d52f26f152e6f38f4cc3c00274a3cb88a3ab)
+++ fedd/fedd_proj.py	(revision bb3769ac25051bcf7f09fdfe67757a05f649195e)
@@ -20,4 +20,13 @@
 from fedd_services import *
 from fedd_util import *
+
+if False:
+    _RequestAccessFault_typecode = Struct(pname=("http://www.isi.edu/faber/fedd.wsdl", 'RequestAccessFault'), ofwhat=[ns0.faultType_Def( pname=("http://www.isi.edu/faber/fedd.wsdl", "RequestAccessFaultBody"), aname="_RequestAccessFaultBody", minoccurs=0, maxoccurs=1, nillable=True, encoded=None, typed=True)], pyclass=None)
+    class RequestAccessFault:
+	typecode = _RequestAccessFault_typecode
+	__metaclass__ = pyclass_type
+	def __init__(self, code=0, str="str"):
+	    self._RequestAccessFaultBody = None
+    RequestAccessFault.typecode.pyclass=RequestAccessFault
 
 class fedd_proj:
@@ -57,8 +66,12 @@
 		return "access_proj('%s', [])" % self.name
 
-
-    class parse_error(RuntimeError):
-	"""Raised if the configuration file is unparsable"""
-	pass
+    # These are used to make the error reporting independent of the transport.
+    # The XMLRPC and SOAP dispatchers will convert them to transport-specific
+    # errors
+    class server_error(RuntimeError): pass
+    class client_error(RuntimeError): pass
+    # Error parsing config
+    class parse_error(RuntimeError): pass
+
 
     def __init__(self, config=None):
@@ -216,5 +229,5 @@
 		    rc = subprocess.call(cmd)
 		except OSerror, e:
-		    raise Fault(Fault.Server, 
+		    raise fedd_proj.server_error(
 			    "Dynamic project subprocess creation error "+ \
 				    "[%s] (%s)" %  (cmd[1], e.strerror))
@@ -223,5 +236,5 @@
 
 	    if rc != 0: 
-		raise Fault(Fault.Server,
+		raise fedd_proj.server_error(
 			"Dynamic project subprocess error " +\
 				"[%s] (%d)" % (cmd[1], rc))
@@ -253,5 +266,5 @@
 	    ctx = fedd_ssl_context(self.cert_file, tc, password=self.cert_pwd)
 	except SSL.SSLError:
-	    raise Fault(Fault.Server, "Server certificates misconfigured")
+	    raise fedd_proj.server_error("Server certificates misconfigured")
 
 	# Of all the dumbass things.  The XMLRPC library in use here won't
@@ -274,10 +287,10 @@
 	    resp, method = xmlrpclib.loads(resp)
 	except xmlrpclib.Error, e:
-	    raise Fault(Fault.Server, "Remote XMLRPC Fault: %s" % e)
+	    raise fedd_proj.server_error("Remote XMLRPC Fault: %s" % e)
 	
 	if resp[0].has_key('RequestAccessResponseBody'):
 	    return resp[0]['RequestAccessResponseBody']
 	else:
-	    raise Fault(Fault.Server, "Bad proxy response")
+	    raise fedd_proj.server_error("Bad proxy response")
 
     def proxy_request(self, dt, req):
@@ -295,5 +308,5 @@
 	    ctx = fedd_ssl_context(self.cert_file, tc, password=self.cert_pwd)
 	except SSL.SSLError:
-	    raise Fault(Fault.Server, "Server certificates misconfigured")
+	    raise fedd_proj.server_error("Server certificates misconfigured")
 
 	loc = feddServiceLocator();
@@ -309,5 +322,5 @@
 	    resp = port.RequestAccess(msg)
 	except ZSI.ParseException, e:
-	    raise Fault(Fault.Server, "Bad format message (XMLRPC??): %s" %
+	    raise fedd_proj.server_error("Bad format message (XMLRPC??): %s" %
 		    str(e))
 	except ZSI.FaultException, e:
@@ -319,5 +332,5 @@
 	    return r['RequestAccessResponseBody']
 	else:
-	    raise Fault(Fault.Server, "Bad proxy response")
+	    raise fedd_proj.server_error("Bad proxy response")
 
     def permute_wildcards(self, a, p):
@@ -388,8 +401,8 @@
 		fedids = [ u for u in user if isinstance(u, type(fid))]
 		if len(fedids) > 1:
-		    raise Fault(Fault.Client,
+		    raise fedd_proj.client_error(
 			    "User asserting multiple fedids")
 		elif len(fedids) == 1 and fedids[0] != fid:
-		    raise Fault(Fault.Client, 
+		    raise fedd_proj.client_error(
 			    "User asserting different fedid")
 	    project = None
@@ -397,5 +410,5 @@
 	elif principal_type == "project":
 	    if isinstance(project, type(fid)) and fid != project:
-		raise Fault(Fault.Client,
+		raise fedd_proj.client_error(
 			"Project asserting different fedid")
 	    tb = None
@@ -406,5 +419,5 @@
 	print "Found: ", found
 	
-	if found == None: raise Fault(Fault.Server, "Access denied")
+	if found == None: raise fedd_proj.server_error("Access denied")
 
 	# resolve <dynamic> and <same> in found
@@ -416,5 +429,5 @@
 		found[0].name = project
 	    else : 
-		raise Fault(Fault.Server, 
+		raise fedd_proj.server_error(
 			"Project matched <same> when no project given")
 	elif found[0].name == "<dynamic>":
@@ -425,5 +438,5 @@
 	    if user_match == "<any>":
 		if user != None: found = (found[0], user[0])
-		else: raise Fault(Fault.Server,
+		else: raise fedd_proj.server_error(
 			"Matched <same> on anonymous request")
 	    else:
@@ -474,5 +487,5 @@
 	    req = req['RequestAccessRequestBody']
 	else:
-	    raise Fault(Fault.Client, "No request!?")
+	    raise fedd_proj.client_error("No request!?")
 
 	if req.has_key('destinationTestbed'):
@@ -492,5 +505,5 @@
 						t not in found[0].node_types]
 		if len(inaccessible) > 0:
-		    raise Fault(Fault.Server, 
+		    raise fedd_proj.server_error(
 			    "Access denied (nodetypes %s)" % \
 			    str(', ').join(inaccessible))
@@ -503,5 +516,5 @@
 		else: pass    # SSH key additions
 	    else:
-		raise Fault(Fault.Client, "SSH access parameters required")
+		raise fedd_proj.client_error("SSH access parameters required")
 
 	    resp = self.build_response(req['allocID'], found, ssh)
@@ -512,5 +525,5 @@
 		# Proxy the request using SOAP
 		return self.proxy_request(dt, req)
-	    except Fault, f:
+	    except RuntimeError, f:
 		p_fault = f
 	  
@@ -519,5 +532,6 @@
 	    try:
 		return self.proxy_xmlrpc_request(dt, req)
-	    except Fault:
+		print "here"
+	    except RuntimeError:
 		# Both failed, return the SOAP error.  If somehow that
 		# exception is gone, return the XMLRPC one
@@ -529,14 +543,18 @@
 
 	msg = self.RequestAccess(unpack_soap(req), fedid)
+	
 	resp = RequestAccessResponseMessage()
-
 	resp.set_element_RequestAccessResponseBody(
 		pack_soap(resp, "RequestAccessResponseBody", msg))
+
 	return resp
 
     def xmlrpc_RequestAccess(self, params, fid):
 	msg = self.RequestAccess(params[0], fedid)
+
 	if msg != None:
 	    return xmlrpclib.dumps(({ "RequestAccessResponseBody": msg },))
+	else:
+	    raise server_error("No response generated?!");
 
     def read_trust(self, trust):
@@ -709,5 +727,14 @@
     def soap_dispatch(self, method, req, fid):
 	if fedd_proj.soap_methods.has_key(method):
-	    return getattr(self, fedd_proj.soap_methods[method])(req, fid)
+	    try:
+		return getattr(self, fedd_proj.soap_methods[method])(req, fid)
+	    except fedd_proj.server_error, e:
+		de = ns0.faultType_Def((ns0.faultType_Def.schema,"RequestAccessFaultBody")).pyclass()
+		de._code=100
+		de._desc="temp"
+		f = Fault(Fault.Server, "Server Test", detail=de)
+		raise f
+	    except fedd_proj.client_error, e:
+		raise Fault(Fault.Client, str(e))
 	else:
 	    raise Fault(Fault.Client, "Unknown method: %s" % method)
@@ -715,5 +742,10 @@
     def xmlrpc_dispatch(self, method, req, fid):
 	if fedd_proj.xmlrpc_methods.has_key(method):
-	    return getattr(self, fedd_proj.xmlrpc_methods[method])(req, fid)
+	    try:
+		return getattr(self, fedd_proj.xmlrpc_methods[method])(req, fid)
+	    except fedd_proj.server_error, e:
+		raise xmlrpclib.Fault("server", str(e))
+	    except fedd_proj.client_error, e:
+		raise xmlrpclib.Fault("client", str(e))
 	else:
 	    raise xmlrpclib.Fault(100, "Unknown method: %s" % method)
Index: fedd/fedd_types.xsd
===================================================================
--- fedd/fedd_types.xsd	(revision 0a47d52f26f152e6f38f4cc3c00274a3cb88a3ab)
+++ fedd/fedd_types.xsd	(revision bb3769ac25051bcf7f09fdfe67757a05f649195e)
@@ -183,3 +183,10 @@
   </xsd:complexType>
 
+  <xsd:complexType name="faultType">
+    <xsd:sequence>
+      <xsd:element name="code" type="xsd:int"/>
+      <xsd:element name="desc" type="xsd:string"/>
+    </xsd:sequence>
+  </xsd:complexType>
+
 </xsd:schema>
Index: fedd/parse_detail.py
===================================================================
--- fedd/parse_detail.py	(revision bb3769ac25051bcf7f09fdfe67757a05f649195e)
+++ fedd/parse_detail.py	(revision bb3769ac25051bcf7f09fdfe67757a05f649195e)
@@ -0,0 +1,40 @@
+#!/usr/local/bin/python
+
+from fedd_services import *
+
+from ZSI.TC import QName, String, URI, AnyElement, UNBOUNDED, Any
+from ZSI.wstools.Namespaces import SOAP
+from ZSI.fault import FaultType
+
+
+# This is a bit of minimal trickery to integrate detail parsing of SOAP faults.
+# ZSI expects detail fields to parse to a class with an "any" attribute.  This
+# little class has such an attribute pointed at itself, so when
+# ZSI.fault.FaultFromMessage extracts that field, it places this object into
+# the new Fault object.  One can also get around this using an extra XML field
+# in the message, parsing the wrapper to the any attribute and then actial body
+# to the class in the any attribute, but this does not perturb the WSDL.
+class detail_faultType:
+    def __init__(self):
+	self.RequestAccessFaultBody = None
+	self.any = self
+    def get_element_RequestAccessFaultBody(self):
+	return self.RequestAccessFaultBody
+
+# Override ZSI.fault.FaultType.typecode - give a parser that speaks our
+# language.
+FaultType.typecode = \
+    Struct(FaultType,
+    [QName(pname='faultcode'),
+    String(pname='faultstring'),
+    URI(pname=(SOAP.ENV,'faultactor'), minOccurs=0),
+    Struct(pname='detail', aname='detail', 
+	ofwhat=[ns0.faultType_Def((ns0.faultType_Def.schema,
+	    "RequestAccessFaultBody"))],
+	pyclass=detail_faultType, minOccurs=0),
+    ],  
+    pname=(SOAP.ENV,'Fault'),
+    inline=True,
+    hasextras=0,
+)
+
