Patch #531629: Add multicall support.
diff --git a/Doc/lib/libxmlrpclib.tex b/Doc/lib/libxmlrpclib.tex
index f420f25..a285c16 100644
--- a/Doc/lib/libxmlrpclib.tex
+++ b/Doc/lib/libxmlrpclib.tex
@@ -252,6 +252,35 @@
 triggered the error.
 \end{memberdesc}
 
+\subsection{MultiCall Objects}
+
+\versionadded{2.4}
+
+In \url{http://www.xmlrpc.com/discuss/msgReader\$1208}, an approach
+is presented to encapsulate multiple calls to a remote server into
+a single request.
+
+\begin{classdesc}{MultiCall}{server}
+
+Create an object used to boxcar method calls. \var{server} is the
+eventual target of the call. Calls can be made to the result object,
+but they will immediately return \var{None}, and only store the
+call name and parameters in the \class{MultiCall} object. Calling
+the object itself causes all stored calls to be transmitted as
+a single \code{system.multicall} request. The result of this call
+is a generator; iterating over this generator yields the individual
+results.
+
+\end{classdesc}
+
+A usage example of this class is
+
+\begin{verbatim}
+multicall = MultiCall(server_proxy)
+multicall.add(2,3)
+multicall.get_address("Guido")
+add_result, address = multicall()
+\end{verbatim}
 
 \subsection{Convenience Functions}
 
diff --git a/Lib/xmlrpclib.py b/Lib/xmlrpclib.py
index 20d6e71..f06cfd7 100644
--- a/Lib/xmlrpclib.py
+++ b/Lib/xmlrpclib.py
@@ -50,6 +50,7 @@
 # 2003-04-25 ak  Add support for nil
 # 2003-06-15 gn  Add support for time.struct_time
 # 2003-07-12 gp  Correct marshalling of Faults
+# 2003-10-31 mvl Add multicall support
 #
 # Copyright (c) 1999-2002 by Secret Labs AB.
 # Copyright (c) 1999-2002 by Fredrik Lundh.
@@ -108,6 +109,7 @@
 
   ServerProxy    Represents a logical connection to an XML-RPC server
 
+  MultiCall      Executor of boxcared xmlrpc requests 
   Boolean        boolean wrapper to generate a "boolean" XML-RPC value
   DateTime       dateTime wrapper for an ISO 8601 string or time tuple or
                  localtime integer value to generate a "dateTime.iso8601"
@@ -875,7 +877,69 @@
         self._type = "methodName" # no params
     dispatch["methodName"] = end_methodName
 
+## Multicall support
+#
 
+class _MultiCallMethod:
+    # some lesser magic to store calls made to a MultiCall object
+    # for batch execution
+    def __init__(self, call_list, name):
+        self.__call_list = call_list
+        self.__name = name
+    def __getattr__(self, name):
+        return _MultiCallMethod(self.__call_list, "%s.%s" % (self.__name, name))
+    def __call__(self, *args):
+        self.__call_list.append((self.__name, args))
+
+def MultiCallIterator(results):
+    """Iterates over the results of a multicall. Exceptions are
+    thrown in response to xmlrpc faults."""
+    
+    for i in results:
+        if type(i) == type({}):
+            raise Fault(i['faultCode'], i['faultString'])
+        elif type(i) == type([]):
+            yield i[0]
+        else:
+            raise ValueError,\
+                  "unexpected type in multicall result"
+        
+class MultiCall:
+    """server -> a object used to boxcar method calls
+
+    server should be a ServerProxy object.
+
+    Methods can be added to the MultiCall using normal
+    method call syntax e.g.:
+
+    multicall = MultiCall(server_proxy)
+    multicall.add(2,3)
+    multicall.get_address("Guido")
+
+    To execute the multicall, call the MultiCall object e.g.:
+
+    add_result, address = multicall()
+    """
+    
+    def __init__(self, server):
+        self.__server = server
+        self.__call_list = []
+        
+    def __repr__(self):
+        return "<MultiCall at %x>" % id(self)
+    
+    __str__ = __repr__
+
+    def __getattr__(self, name):
+        return _MultiCallMethod(self.__call_list, name)
+
+    def __call__(self):
+        marshalled_list = []
+        for name, args in self.__call_list:
+            marshalled_list.append({'methodName' : name, 'params' : args})
+
+        return MultiCallIterator(self.__server.system.multicall(marshalled_list))
+        
 # --------------------------------------------------------------------
 # convenience functions
 
@@ -1328,7 +1392,7 @@
             )
 
     __str__ = __repr__
-
+    
     def __getattr__(self, name):
         # magic method dispatcher
         return _Method(self.__request, name)
diff --git a/Misc/NEWS b/Misc/NEWS
index 970c814..2449dec 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -101,6 +101,8 @@
 Library
 -------
 
+- xmlrpclib.MultiCall has been added.
+
 - poplib.POP3_SSL has been added.
 
 - tmpfile.mkstemp now returns an absolute path even if dir is relative.