private void GotItems(object sender, IQ iq, object onode) { DiscoNode dn = onode as DiscoNode; Debug.Assert(dn != null); if (iq.Type != IQType.result) { // protocol error dn.AddItems(this, null); return; } DiscoItems items = iq.Query as DiscoItems; if (items == null) { // protocol error dn.AddItems(this, null); return; } dn.AddItems(this, items.GetItems()); // automatically info everything we get an item for. foreach (DiscoNode n in dn.Children) { if (n.Features == null) { RequestInfo(n); } } }
public void Call(DiscoNode node) { if (callback != null) { callback(manager, node, state); } }
public void GotRootItems(DiscoManager manager, DiscoNode node, object state) { m_outstanding = node.Children.Count; foreach (DiscoNode n in node.Children) { manager.BeginGetFeatures(n, new DiscoNodeHandler(GotFeatures), state); } }
/// <summary> /// Deletes the cache. /// </summary> public void Clear() { lock (m_items) { m_root = null; m_items.Clear(); } }
internal DiscoNode AddItem(DiscoManager manager, DiscoItem di) { DiscoNode dn = manager.GetNode(di.Jid, di.Node); if ((di.Named != null) && (di.Named != "")) { dn.Name = di.Named; } Children.Add(dn); return(dn); }
/// <summary> /// Retrieves the child items associated with this node, /// and then calls back on the handler. /// If the information is in the cache, handler gets /// called right now. /// </summary> /// <param name="node">Disco node to search.</param> /// <param name="handler">Callback that gets called with the items.</param> /// <param name="state">Context to pass back to caller when complete</param> public void BeginGetItems(DiscoNode node, DiscoNodeHandler handler, object state) { if (node == null) { node = Root; } if (node.AddItemsCallback(this, handler, state)) { RequestItems(node); } }
/// <summary> /// Retrieves the features associated with this node and /// then calls back on the handler. /// If the information is in the cache, handler gets called right now. /// </summary> /// <param name="node">Node to look for.</param> /// <param name="handler">Callback to use afterwards.</param> /// <param name="state">Context to pass back to caller when complete</param> public void BeginGetFeatures(DiscoNode node, DiscoNodeHandler handler, object state) { if (node == null) { node = Root; } if (node.AddFeatureCallback(this, handler, state)) { RequestInfo(node); } }
/// <summary> /// Create a CapsManager from an existing Disco Node. Pass in null /// to use a placeholder. /// </summary> /// <param name="node"></param> public CapsManager(DiscoNode node) { InitializeComponent(); this.OnStreamChanged += new bedrock.ObjectHandler(CapsManager_OnStreamChanged); if (node == null) { m_disco = new DiscoNode(new JID(null, "placeholder", null), null); } else { m_disco = node; } }
/// <summary> /// Creates nodes and ensure that they are cached. /// </summary> /// <param name="jid">JID associated with DiscoNode.</param> /// <param name="node">Node associated with DiscoNode.</param> /// <returns> /// If DiscoNode exists, returns the found node. /// Otherwise it creates the node and return it. /// </returns> public DiscoNode GetNode(JID jid, string node) { lock (m_items) { string key = DiscoNode.GetKey(jid, node); DiscoNode n = (DiscoNode)m_items[key]; if (n == null) { n = new DiscoNode(jid, node); m_items.Add(key, n); } return(n); } }
private void RequestItems(DiscoNode node) { lock (node) { if (!node.PendingItems) { IQ iq = node.ItemsIQ(m_stream.Document); JabberService js = m_stream as JabberService; if (js != null) { iq.From = js.ComponentID; } BeginIQ(iq, new IqCB(GotItems), node); } } }
public void GotFeatures(DiscoManager manager, DiscoNode node, object state) { // yes, yes, this may call the handler more than once in multi-threaded world. Punt for now. if (m_handler != null) { if (node.HasFeature(m_URI)) { m_handler(manager, node, state); m_handler = null; } } if (Interlocked.Decrement(ref m_outstanding) == 0) { if (m_handler != null) { m_handler(manager, null, state); } } }
private void GotInfo(object sender, IQ iq, object onode) { DiscoNode dn = onode as DiscoNode; Debug.Assert(dn != null); if (iq.Type == IQType.error) { if (dn == m_root) { // root node. // Try agents. Error err = iq.Error; if (err != null) { string cond = err.Condition; if ((cond == Error.FEATURE_NOT_IMPLEMENTED) || (cond == Error.SERVICE_UNAVAILABLE)) { IQ aiq = new AgentsIQ(m_stream.Document); BeginIQ(aiq, new IqCB(GotAgents), m_root); return; } } } } if (iq.Type != IQType.result) { // protocol error dn.AddInfo(null); return; } dn.AddInfo(iq.Query as DiscoInfo); if (dn == m_root) { RequestItems(m_root); } }
private void GotCaps(DiscoManager m, DiscoNode node, object state) { // timeout if (node == null) { return; } string ver = (string)state; string calc = CalculateVer(node); if (ver != calc) { Debug.WriteLine("WARNING: invalid caps ver hash: '" + ver + "' != '" + calc + "'"); if (node.Info != null) { Debug.WriteLine(node.Info.OuterXml); } return; } m_cache[ver] = node.Info; }
private string CalculateVer(DiscoNode n) { if (m_hash == null) { return(null); } // 1. Initialize an empty string S. StringBuilder S = new StringBuilder(); // 2. Sort the service discovery identities [16] by category and then by type // (if it exists) and then by xml:lang (if it exists), formatted as // CATEGORY '/' [TYPE] '/' [LANG] '/' [NAME]. Note that each slash is // included even if the TYPE, LANG, or NAME is not included. Ident[] ids = n.GetIdentities(); Array.Sort(ids); // 3. For each identity, append the 'category/type/lang/name' to S, followed by // the '<' character. foreach (Ident id in ids) { S.Append(id.Key); S.Append(SEP); } // 4. Sort the supported service discovery features. string[] features = n.FeatureNames; Array.Sort(features); // 5. For each feature, append the feature to S, followed by the '<' character. foreach (string feature in features) { S.Append(feature); S.Append(SEP); } // 6. If the service discovery information response includes XEP-0128 data forms, // sort the forms by the FORM_TYPE (i.e., by the XML character // data of the <value/> element). Data[] ext = n.Extensions; if (ext != null) { Array.Sort(ext, new FormTypeComparer()); foreach (Data x in ext) { // For each extended service discovery information form: // 1. Append the XML character data of the FORM_TYPE field's <value/> // element, followed by the '<' character. S.Append(x.FormType); S.Append(SEP); // 2. Sort the fields by the value of the "var" attribute. bedrock.collections.Tree fields = new bedrock.collections.Tree(); foreach (Field f in x.GetFields()) { fields[f.Var] = f; } // 3. For each field: foreach (System.Collections.DictionaryEntry entry in fields) { Field f = (Field)entry.Value; if (f.Var == "FORM_TYPE") { continue; } // 1. Append the value of the "var" attribute, followed by the '<' character. S.Append(f.Var); S.Append(SEP); // 2. Sort values by the XML character data of the <value/> element. string[] values = f.Vals; Array.Sort(values); foreach (string v in values) { // 3. For each <value/> element, append the XML character data, followed by the '<' character. S.Append(v); S.Append(SEP); } } } } // Ensure that S is encoded according to the UTF-8 encoding (RFC 3269 [16]). byte[] input = Encoding.UTF8.GetBytes(S.ToString()); // Compute the verification string by hashing S using the algorithm specified // in the 'hash' attribute (e.g., SHA-1 as defined in RFC 3174 [17]). The hashed // data MUST be generated with binary output and encoded using Base64 as specified // in Section 4 of RFC 4648 [18] (note: the Base64 output MUST NOT include // whitespace and MUST set padding bits to zero). [19] HashAlgorithm hasher = GetHasher(m_hash); byte[] hash = hasher.ComputeHash(input, 0, input.Length); return(Convert.ToBase64String(hash)); }
/// <summary> /// Retrieves the child items associated with this node, /// and then calls back on the handler. /// /// If caching is specified, items already in the cache call the handler /// immediately. /// </summary> /// <param name="jid">JID of Service to query.</param> /// <param name="node">Node on the service to interact with.</param> /// <param name="handler">Callback that gets called with the items.</param> /// <param name="state">Context to pass back to caller when complete</param> /// <param name="cache">Should caching be performed on this request?</param> public void BeginGetItems(JID jid, string node, DiscoNodeHandler handler, object state, bool cache) { DiscoNode dn = cache ? GetNode(jid, node) : new DiscoNode(jid, node); BeginGetItems(dn, handler, state); }
private void GotAgents(object sender, IQ iq, object onode) { DiscoNode dn = onode as DiscoNode; Debug.Assert(dn != null); if (iq.Type != IQType.result) { dn.AddItems(this, null); return; } AgentsQuery aq = iq.Query as AgentsQuery; if (aq == null) { dn.AddItems(this, null); return; } if (dn.Children == null) { dn.Children = new Set(); } foreach (Agent agent in aq.GetAgents()) { DiscoItem di = new DiscoItem(m_stream.Document); di.Jid = agent.JID; di.Named = agent.AgentName; DiscoNode child = dn.AddItem(this, di); if (child.Features == null) { child.Features = new StringSet(); } if (child.Identity == null) { child.Identity = new Set(); } Ident id = new Ident(); id.Name = agent.Description; switch (agent.Service) { case "groupchat": id.Category = "conference"; id.Type = "text"; child.Identity.Add(id); break; case "jud": id.Category = "directory"; id.Type = "user"; child.Identity.Add(id); break; case null: case "": break; default: // guess this is a transport id.Category = "gateway"; id.Type = agent.Service; child.Identity.Add(id); break; } if (agent.Register) { child.Features.Add(URI.REGISTER); } if (agent.Search) { child.Features.Add(URI.SEARCH); } if (agent.Groupchat) { child.Features.Add(URI.MUC); } if (agent.Transport) { if (id.Category != "gateway") { Ident tid = new Ident(); tid.Name = id.Name; tid.Category = "gateway"; child.Identity.Add(tid); } } foreach (XmlElement ns in agent.GetElementsByTagName("ns")) { child.Features.Add(ns.InnerText); } child.AddItems(this, null); child.AddIdentities(null); child.AddFeatures((StringSet)null); } dn.AddItems(this, null); dn.AddIdentities(null); dn.AddFeatures((StringSet)null); }