private void CanControlResponse(XmppClient Client, string Type, XmlNodeList Response, ref StanzaError Error, object State)
        {
            object[]           P        = (object[])State;
            CanControlCallback Callback = (CanControlCallback)P [0];
            object             State2   = (object)P [1];
            string             Hash     = (string)P [2];

            string[]        Parameters     = (string[])P [3];
            NodeReference[] NodeReferences = (NodeReference[])P [4];
            bool            CanControl     = false;
            string          Jid            = string.Empty;
            XmlElement      E;

            if (Error != null)
            {
                Error = null;
            }
            else if (Response != null)
            {
                if (Hash != null)
                {
                    this.AddToCache(Hash, Response);
                }

                foreach (XmlNode N in Response)
                {
                    if (N.LocalName == "canControlResponse" && (E = N as XmlElement) != null)
                    {
                        CanControl = XmlUtilities.GetAttribute(E, "result", false);

                        List <NodeReference> Nodes;
                        List <string>        ParameterNames;

                        ReadoutRequest.ParseNodesAndFieldNames(E, out Nodes, out ParameterNames);

                        if (Nodes == null)
                        {
                            NodeReferences = null;
                        }
                        else
                        {
                            NodeReferences = Nodes.ToArray();
                        }

                        if (ParameterNames == null)
                        {
                            Parameters = null;
                        }
                        else
                        {
                            Parameters = ParameterNames.ToArray();
                        }
                        break;
                    }
                }
            }

            CanControlEventArgs e = new CanControlEventArgs(Jid, CanControl, Parameters, NodeReferences, State2);

            if (Callback != null)
            {
                try
                {
                    Callback(e);
                } catch (Exception ex)
                {
                    Log.Exception(ex);
                }
            }
        }
        /// <summary>
        /// Determines whether a control operation can be performed, partially performed or be rejected.
        /// </summary>
        /// <param name="From">JID from which the request was made.</param>
        /// <param name="Callback">Callback method to call, when the response is available.</param>
        /// <param name="State">State object to pass on to the response callback.</param>
        /// <param name="ServiceToken">Optional service token provided in the request.</param>
        /// <param name="DeviceToken">Optional device token provided in the request.</param>
        /// <param name="UserToken">Optional user token provided in the request.</param>
        /// <param name="Parameters">Control parameters to control.</param>
        /// <param name="NodeReferenes">Any node references in the request. Can be null, if none.</param>
        public void CanControl(string From, CanControlCallback Callback, object State, string ServiceToken, string DeviceToken, string UserToken, string[] Parameters, NodeReference[] NodeReferences)
        {
            string BareJid = XmppClient.StripResource(From);

            if (BareJid == this.address)
            {
                if (Callback != null)
                {
                    CanControlEventArgs e = new CanControlEventArgs(BareJid, true, Parameters, NodeReferences, State);

                    try
                    {
                        Callback(e);
                    } catch (Exception ex)
                    {
                        Log.Exception(ex);
                    }
                }
            }
            else
            {
                StringBuilder sb = new StringBuilder();
                XmlWriter     w  = XmlWriter.Create(sb, XmlUtilities.GetXmlWriterSettings(false, true, true));

                w.WriteStartElement("canControl", "urn:xmpp:iot:provisioning");
                w.WriteAttributeString("jid", BareJid);

                if (!string.IsNullOrEmpty(ServiceToken))
                {
                    w.WriteAttributeString("serviceToken", ServiceToken);
                    this.UpdateTokenSource(ServiceToken, From);
                }

                if (!string.IsNullOrEmpty(DeviceToken))
                {
                    w.WriteAttributeString("deviceToken", DeviceToken);
                    this.UpdateTokenSource(DeviceToken, From);
                }

                if (!string.IsNullOrEmpty(UserToken))
                {
                    w.WriteAttributeString("userToken", UserToken);
                    this.UpdateTokenSource(UserToken, From);
                }

                if (NodeReferences != null && NodeReferences.Length > 0)
                {
                    foreach (NodeReference Node in NodeReferences)
                    {
                        w.WriteStartElement("node");
                        w.WriteAttributeString("nodeId", Node.NodeId);

                        if (!string.IsNullOrEmpty(Node.SourceId))
                        {
                            w.WriteAttributeString("sourceId", Node.SourceId);
                        }

                        if (!string.IsNullOrEmpty(Node.CacheType))
                        {
                            w.WriteAttributeString("cacheType", Node.CacheType);
                        }

                        w.WriteEndElement();
                    }
                }

                if (Parameters != null && Parameters.Length > 0)
                {
                    foreach (string Parameter in Parameters)
                    {
                        w.WriteStartElement("parameter");
                        w.WriteAttributeString("name", Parameter);
                        w.WriteEndElement();
                    }
                }

                w.WriteEndElement();

                w.Flush();
                string      Xml   = sb.ToString();
                string      Hash  = this.CalcHash(Xml);
                StanzaError Error = null;
                XmlNodeList Response;

                if ((Response = this.GetCachedResponse(Hash)) != null)
                {
                    this.CanControlResponse(this.client, string.Empty, Response, ref Error, new object[] {
                        Callback,
                        State,
                        null,
                        Parameters,
                        NodeReferences
                    });
                }
                else
                {
                    this.client.IqGet(Xml, this.address, this.CanControlResponse, new object[] {
                        Callback,
                        State,
                        Hash,
                        Parameters,
                        NodeReferences
                    }, "Can Control?");
                }
            }
        }