// Execute multiple calls and return the results in an array.
        public bool executeMulticall(string methodNameRoot, XmlRpcValue parms, XmlRpcValue result)
        {
            if (methodNameRoot != SYSTEM_MULTICALL)
            {
                return(false);
            }

            // There ought to be 1 parameter, an array of structs
            if (parms.Length != 1 || parms[0].Type != XmlRpcValue.ValueType.TypeArray)
            {
                throw new XmlRpcException(SYSTEM_MULTICALL + ": Invalid argument (expected an array)");
            }

            int nc = parms[0].Length;

            result.SetArray(nc);

            for (int i = 0; i < nc; ++i)
            {
                if (!parms[0][i].hasMember(METHODNAME) ||
                    !parms[0][i].hasMember(PARAMS))
                {
                    result[i].Set(FAULTCODE, -1);
                    result[i].Set(FAULTSTRING, SYSTEM_MULTICALL + ": Invalid argument (expected a struct with members methodName and params)");
                    continue;
                }

                string      methodName   = parms[0][i][METHODNAME].GetString();
                XmlRpcValue methodParams = parms[0][i][PARAMS];

                XmlRpcValue resultValue = new XmlRpcValue();
                resultValue.SetArray(1);
                try
                {
                    if (!executeMethod(methodName, methodParams, resultValue[0]) &&
                        !executeMulticall(methodName, parms, resultValue[0]))
                    {
                        result[i].Set(FAULTCODE, -1);
                        result[i].Set(FAULTSTRING, methodName + ": unknown method name");
                    }
                    else
                    {
                        result[i] = resultValue;
                    }
                }
                catch (XmlRpcException fault)
                {
                    result[i].Set(FAULTCODE, 0);
                    result[i].Set(FAULTSTRING, fault.Message);
                }
            }

            return(true);
        }
        private void listMethods(XmlRpcValue result)
        {
            int i = 0;

            result.SetArray(_methods.Count + 1);

            foreach (var rec in _methods)
            {
                result.Set(i++, rec.Key);
            }

            // Multicall support is built into XmlRpcServerConnection
            result.Set(i, MULTICALL);
        }
        // Parse the method name and the argument values from the request.
        private string parseRequest(XmlRpcValue parms, string _request)
        {
            bool   success    = true;
            string methodName = "unknown";

            //XmlRpcValue result = null;
            using (XmlReader reader = XmlReader.Create(new StringReader(_request)))
            {
                XmlDocument xmldoc = new XmlDocument();
                xmldoc.Load(reader);

                // Parse response xml into result
                //int offset = 0;
                XmlNodeList xmlMethodNameList = xmldoc.GetElementsByTagName("methodName");
                if (xmlMethodNameList.Count > 0)
                {
                    XmlNode xmlMethodName = xmlMethodNameList[0];
                    methodName = xmlMethodName.InnerText;
                }

                XmlNodeList xmlParameters = xmldoc.GetElementsByTagName("param");
                XmlNodeList xmlFault      = xmldoc.GetElementsByTagName("fault");
                if (xmlParameters.Count == 0)
                {
                    XmlRpcUtil.error("Error in XmlRpcServer::parseRequest: Invalid request - no methodResponse. Request:\n{0}", _request);
                    return(null);
                }

                parms.SetArray(xmlParameters.Count);

                for (int i = 0; i < xmlParameters.Count; i++)
                {
                    var value = new XmlRpcValue();
                    value.fromXml(xmlParameters[i]["value"]);
                    parms.asArray[i] = value;
                }

                if (xmlFault.Count > 0 && parms.fromXml(xmlFault[0]))
                {
                    XmlRpcUtil.log(XmlRpcUtil.XMLRPC_LOG_LEVEL.WARNING, "Read fault on response for request:\n{0}\nFAULT: {1}", _request, parms.ToString());
                }
            }

            return(methodName);
        }
        // Convert the response xml into a result value
        private bool parseResponse(XmlRpcValue result, string _response)
        {
            bool success = true;

            //XmlRpcValue result = null;
            using (XmlReader reader = XmlReader.Create(new StringReader(_response)))
            {
                XmlDocument response = new XmlDocument();
                response.Load(reader);
                // Parse response xml into result
                //int offset = 0;
                XmlNodeList resp         = response.GetElementsByTagName("methodResponse");
                XmlNode     responseNode = resp[0];

                //if (!XmlRpcUtil.findTag(METHODRESPONSE_TAG, _response, out offset))
                if (resp.Count == 0)
                {
                    XmlRpcUtil.error("Error in XmlRpcClient::parseResponse: Invalid response - no methodResponse. Response:\n{0}", _response);
                    return(false);
                }

                XmlElement pars  = responseNode["params"];
                XmlElement fault = responseNode["fault"];

                //result = new XmlRpcValue();
                if (pars != null)
                {
                    bool isArray   = false;
                    var  selection = pars.SelectNodes("param");
                    if (selection.Count > 1)
                    {
                        result.SetArray(selection.Count);
                        int i = 0;
                        foreach (XmlNode par in selection)
                        {
                            var value = new XmlRpcValue();
                            value.fromXml(par["value"]);
                            result[i++] = value;
                        }
                    }
                    else if (selection.Count == 1)
                    {
                        result.fromXml(selection[0]["value"]);
                    }
                    else
                    {
                        success = false;
                    }
                }
                else if (fault != null && result.fromXml(fault))
                {
                    success = false;
                }
                else
                {
                    XmlRpcUtil.error("Error in XmlRpcClient::parseResponse: Invalid response - no param or fault tag. Response:\n{0}", _response);
                }
                _response = "";
            }
            return(success);
        }