private void CanReadResponse(XmppClient Client, string Type, XmlNodeList Response, ref StanzaError Error, object State)
        {
            object[]        P        = (object[])State;
            CanReadCallback Callback = (CanReadCallback)P [0];
            object          State2   = (object)P [1];
            string          Hash     = (string)P [2];
            ReadoutRequest  Request  = (ReadoutRequest)P [3];
            bool            CanRead  = 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 == "canReadResponse" && (E = N as XmlElement) != null)
                    {
                        CanRead       = XmlUtilities.GetAttribute(E, "result", false);
                        Request.Types = ReadoutRequest.ParseReadoutType(E);

                        List <NodeReference> Nodes;
                        List <string>        FieldNames;

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

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

                        if (FieldNames == null)
                        {
                            Request.SetFields(null);
                        }
                        else
                        {
                            Request.SetFields(FieldNames.ToArray());
                        }
                        break;
                    }
                }
            }

            CanReadEventArgs e = new CanReadEventArgs(Jid, CanRead, Request, State2);

            if (Callback != null)
            {
                try
                {
                    Callback(e);
                } catch (Exception ex)
                {
                    Log.Exception(ex);
                }
            }
        }
        /// <summary>
        /// Determines whether a readout can be performed, partially performed or be rejected.
        /// </summary>
        /// <param name="Request">Readout request.</param>
        /// <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>
        public void CanRead(ReadoutRequest Request, string From, CanReadCallback Callback, object State)
        {
            string BareJid = XmppClient.StripResource(From);

            if (BareJid == this.address)
            {
                if (Callback != null)
                {
                    CanReadEventArgs e = new CanReadEventArgs(BareJid, true, Request, 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("canRead", "urn:xmpp:iot:provisioning");
                w.WriteAttributeString("jid", BareJid);

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

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

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

                WriteReadoutTypes(w, Request.Types);
                WriteNodes(w, Request.Nodes);
                WriteFields(w, Request.GetFields());

                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.CanReadResponse(this.client, string.Empty, Response, ref Error, new object[] {
                        Callback,
                        State,
                        null,
                        Request
                    });
                }
                else
                {
                    this.client.IqGet(Xml, this.address, this.CanReadResponse, new object[] { Callback, State, Hash, Request }, "Can Read?");
                }
            }
        }