Not logged in. · Lost password · Register
Forum: MatriX RSS
Page:  1  2  next
Avatar
Lightbarrier #1
Member since Jul 2014 · 52 posts
Group memberships: Members
Show profile · Link to this post
Subject: Ways to Create new Iq
First off thanks again for the help.

I have the server set up to automatically archive any messages that pass through, and now I want to allow the client to retrieve their messages. I realize that there’s xep-0136 for this, but now I want to make a iq to retrieve them using your library. From looking at your tutorial, you can create a class that inherits XmppXElement, and then stick that in a a class that inherits from iq. However, if possible I would prefer to just build it as a string, and then just send it with IqFilter.SendIq. Is there a way to do this?

That being said, I do think it would be possible to do it the way you show in the tutorial however, I'm not quite sure how to go from xml code snippet below to the class set up, although I did make a rough attempt at it. Regardless the class format seems drawn out for such a small snippet of code.

My question, what ways are there to create a new Iq?


XML Code I want to Send:
  1. <iq type='get' id='page1'>
  2.  <retrieve xmlns='urn:xmpp:archive'
  3.             with='juliet@capulet.com/chamber'
  4.             start='1469-07-21T02:56:15Z'>
  5.     <set xmlns='http://jabber.org/protocol/rsm'>
  6.       <max>100</max>
  7.     </set>
  8.  </retrieve>
  9. </iq>

C# Code to create new Iq:
  1. using Matrix.Xml;
  2. namespace Example
  3. {
  4.     public class Set: XmppXElement
  5.     {
  6.         public Set() : base("http://jabber.org/protocol/rsm")
  7.         {
  8.         }
  9.        
  10.         public int Max
  11.         {
  12.             get { return GetTagInt("max"); }
  13.             set { SetTag("max", value); }
  14.         }
  15.     }
  16.    
  17.     public class Retrieve: XmppXElement
  18.     {
  19.         public Retrieve() : base("urn:xmpp:", "archive")
  20.         {
  21.         }
  22.  
  23.         public string With
  24.         {
  25.             get { return GetTag("with"); }
  26.             set { SetTag("zip", value); }
  27.         }
  28.  
  29.         public string Start
  30.         {
  31.             get { return GetTag("zip"); }
  32.             set { SetTag("start", value); }
  33.         }
  34.        
  35.         public Set Set
  36.         {
  37.             get { return GetTag("set"); }
  38.             set { SetTag("set", value); }
  39.         }
  40.     }
  41.    
  42.     public class RetrieveIq : Iq
  43.     {
  44.         public RetrieveIq()
  45.         {
  46.             GenerateId();
  47.         }
  48.          
  49.         public Retrieve Retrieve
  50.         {
  51.             get { return Element<Retrieve>(); }
  52.             set { Replace(value); }
  53.         }
  54.     }
  55. }
This post was edited on 2014-08-08, 00:59 by Lightbarrier.
Avatar
Alex #2
Member since Feb 2003 · 4327 posts · Location: Germany
Group memberships: Administrators, Members
Show profile · Link to this post
yes you can build packets also from an xml string. But I would not suggest to do that. Its fine for prototying, but for production code I personally prefer strongly typed classes which build correct XMl.

Here is an example:
  1. string xml = @"<message type='chat' to='alex@ag-software.net/MatriX' id='f801199c-7bd6-4455-af7c-42e2e7e6be16' xmlns='jabber:client'><body>Hello World</body></message>";
  2. XmppXElement el = XmppXElement.LoadXml(xml);
  3. xmppClient.Send(el);


The Set class for result set management is already implemented in MatriX. You can find it in the Matrix.Xmpp.ResultSetManagement namespace.

I have fixed your retrieve class:
  1. public class Retrieve : XmppXElement
  2. {
  3.     public Retrieve()
  4.         : base("urn:xmpp:archive", "retrieve")
  5.     {
  6.     }
  7.  
  8.     public string With
  9.     {
  10.         get { return GetAttribute("with"); }
  11.         set { SetAttribute("with", value); }
  12.     }
  13.  
  14.     public DateTime Start
  15.     {
  16.         get { return  Matrix.Util.Time.Iso8601Date(GetAttribute("start")); }
  17.         set { SetAttribute("start", Matrix.Util.Time.Iso8601Date(value)); }
  18.     }
  19.  
  20.     public Set Set
  21.     {
  22.         get { return Element<Set>(); }
  23.         set { Replace(value); }
  24.     }
  25. }

here is a small snippet how to use it:
  1. var retrieve = new Retrieve
  2. {
  3.     With = "juliet@capulet.com/chamber",
  4.     Start = DateTime.Now,
  5.     Set = new Set {Maximum = 100},
  6. };
  7.  
  8. Debug.WriteLine(retrieve.ToString());
  9.  
  10. // build an Iq
  11. var iq = new IqQuery<Retrieve>(retrieve);
  12. Debug.WriteLine(iq.ToString());

Hope this helps.

Alex
Avatar
Lightbarrier #3
Member since Jul 2014 · 52 posts
Group memberships: Members
Show profile · Link to this post
Subject: Follow Up
Thanks for your help, that seems to have gotten me sending requests to the server however, it seems that when I make the request for the collection I get an error that said's can't be found, even though I can retrieve a list of collections. I'm not sure if this is the server side's problem or what, but I thought I would post the log file here to see if you could help.

Thanks again.

Examples:

Retrieve list of Collections
  1. <iq type='get' id='juliet1'>
  2.  <list xmlns='urn:xmpp:archive'
  3.         with='juliet@capulet.com'>
  4.     <set xmlns='http://jabber.org/protocol/rsm'>
  5.       <max>30</max>
  6.     </set>
  7.  </list>
  8. </iq>

Retrieve Collection
  1. <iq type='get' id='page1'>
  2.  <retrieve xmlns='urn:xmpp:archive'
  3.             with='juliet@capulet.com/chamber'
  4.             start='1469-07-21T02:56:15Z'>
  5.     <set xmlns='http://jabber.org/protocol/rsm'>
  6.       <max>100</max>
  7.     </set>
  8.  </retrieve>
  9. </iq>
The author has attached one file to this post:
Retrieveing list and collection.txt 17.1 kBytes
You have no permission to open this file.
Avatar
Alex #4
Member since Feb 2003 · 4327 posts · Location: Germany
Group memberships: Administrators, Members
Show profile · Link to this post
This error message gets sent normally when collection for the requested entity does not exist.
Are you sure that there is a collection for this user?

Alex
Avatar
Alex #5
Member since Feb 2003 · 4327 posts · Location: Germany
Group memberships: Administrators, Members
Show profile · Link to this post
checked your logs again. I think you request the collection for the wrong entity.

Your list request returns:
  1. <iq type="result" id="guest1" to="guest@mq1wxibpf0sx2xt/MatriX" xmlns="jabber:client">
  2.  <list xmlns="urn:xmpp:archive">
  3.     <chat with="hotel.agent1@mq1wxibpf0sx2xt" start="2014-08-07T18:38:39.157Z" />
  4.     <set xmlns="http://jabber.org/protocol/rsm">
  5.       <first index="0">4</first>
  6.       <last>4</last>
  7.       <count>1</count>
  8.     </set>
  9.  </list>
  10. </iq>

which means that there is a collection with hotel.agent1@mq1wxibpf0sx2xt

but you requet the collection for youself guest@mq1wxibpf0sx2xt
  1. <iq id="4" type="get" xmlns="jabber:client">
  2.  <retrieve with="guest@mq1wxibpf0sx2xt" start="2014-08-07T07:00:00.000Z" xmlns="urn:xmpp:archive">
  3.     <set xmlns="http://jabber.org/protocol/rsm">
  4.       <max>100</max>
  5.     </set>
  6.  </retrieve>
  7. </iq>

Alex
Avatar
Lightbarrier #6
Member since Jul 2014 · 52 posts
Group memberships: Members
Show profile · Link to this post
Subject: Thanks
Thanks I got it to work.

For people who look at this post in the future it appears that you have to give the exact time when requesting any messages as you'll be basically requesting a conversation, so it makes since to use step 1 first, on the user you care about to get all their conversations and times. Then using step 2, pick the the conversations you care about to request their messages.

Step 1:
  1. <iq type='get' id='juliet1'>
  2.  <list xmlns='urn:xmpp:archive'
  3.         with='juliet@capulet.com'>
  4.     <set xmlns='http://jabber.org/protocol/rsm'>
  5.       <max>30</max>
  6.     </set>
  7.  </list>
  8. </iq>

Step 2:
  1. <iq type='get' id='page1'>
  2.  <retrieve xmlns='urn:xmpp:archive'
  3.             with='juliet@capulet.com/chamber'
  4.             start='1469-07-21T02:56:15Z'>
  5.     <set xmlns='http://jabber.org/protocol/rsm'>
  6.       <max>100</max>
  7.     </set>
  8.  </retrieve>
  9. </iq>
Avatar
Lightbarrier #7
Member since Jul 2014 · 52 posts
Group memberships: Members
Show profile · Link to this post
Subject: One more Question
Ok one last question. I retrieve my data however, I'm confused on how I should deserialize it when it's in a list type format like the one seen below. I've tried pulling it a part a few times however, for some reason I just can't seem to get it, I'm hoping that you can help me here.

Thanks again.

  1. <iq type="result" id="hotel.agent1" to="guest@kasdfjaksadfjka/MatriX" xmlns="jabber:client">
  2.  <list xmlns="urn:xmpp:archive">
  3.     <chat with="hotel.agent1@kasdfjaksadfjka" start="2014-08-07T18:38:39.157Z" />
  4.     <chat with="hotel.agent2@kasdfjaksadfjka" start="2014-08-11T15:09:00.319Z" />
  5.     <set xmlns="http://jabber.org/protocol/rsm">
  6.       <first index="0">4</first>
  7.       <last>31</last>
  8.       <count>2</count>
  9.     </set>
  10.  </list>
  11. </iq>
Avatar
Alex #8
Member since Feb 2003 · 4327 posts · Location: Germany
Group memberships: Administrators, Members
Show profile · Link to this post
You have the following object hierarchy

* Iq
   * List
      * Chat
      * Chat
      * Set

MatriX is serializing everything automatically when the objects exist and are registered in the Factory.

To get the List object you do:
  1. var list = iq.Element<List>();

To get multiple objects of the same type on the same level there is the Elements member in XmppXElement which gives you back a collection.

  1. var chats = list.Elements<Chat>();
  2. var set = list.Element<Set>();

What I normally do is add a property or method to the List class which retrieves the Chat objects as collection. Looks like:
  1. public IEnumerable<Chat> Chats()
  2. {
  3.    get { return Elements<Chat>(); }
  4. }
Avatar
Lightbarrier #9
Member since Jul 2014 · 52 posts
Group memberships: Members
Show profile · Link to this post
Thanks, but when I try to deserialize the list I keep getting null. Admittedly, I thought it was odd that that I should deserialize the iq, and not the query as that contains the list, but I've tried both and neither work. I don't think there's anything wrong with my list class, but I've posted it below in case there was something obvious which I was just missing. I am however, reusing the same list class which I used to make make the request for conversations however, I  this should effect my output as long as I don't try to add these to the xml when sending the request for conversations to the server. One other thing, I'm not sure if the Chat class base("urn:xmpp:archive", "chat") is done correctly however, a chat object within the list doesn't seem to have a namespace so, I'm not quite sure how to work with that, I'm guessing it just doesn't matter.

Thanks again for the help.

  1.  
  2.     private void ArchiveResponseConversations(object sender, IqEventArgs result)
  3.     {
  4.             var iq = result.Iq;
  5.             if (iq.Type == IqType.result)
  6.             {
  7.                 // Both of these get me null
  8.                 var list = iq.Element<List>();
  9.                 var list = iq.Query.Element<List>();
  10.             }
  11.     }
  12.  
  13.     public class List : XmppXElement
  14.     {
  15.         public List()
  16.             : base("urn:xmpp:archive", "list")
  17.         {
  18.         }
  19.  
  20.         public Set Set
  21.         {
  22.             get { return Element<Set>(); }
  23.             set { Replace(value); }
  24.         }
  25.  
  26.         public IEnumerable<Chat> Chat
  27.         {
  28.             get
  29.             {
  30.                 return Elements<Chat>();
  31.             }
  32.         }
  33.     }
  34.  
  35.     public class Chat : XmppXElement
  36.     {
  37.  
  38.         public Chat()
  39.             : base("urn:xmpp:archive", "chat")
  40.         {
  41.         }
  42.  
  43.         public string With
  44.         {
  45.             get { return GetTag("with"); }
  46.             set { SetTag("with", value); }
  47.         }
  48.  
  49.         public string Start
  50.         {
  51.             get { return GetTag("start"); }
  52.             set { SetTag("start", value); }
  53.         }
  54.  
  55.     }
This post was edited on 2014-08-12, 20:10 by Alex.
Avatar
Alex #10
Member since Feb 2003 · 4327 posts · Location: Germany
Group memberships: Administrators, Members
Show profile · Link to this post
namespaces get inherited to children in Xml. Which means the 'urn:xmpp:archive' namespace must be applied to the Chat class. But thats correct in your code blow.
Have you registered the Chat class in the Factory with the correct namespace and tagname?

If yes then please post the code where you register in the Factory and the complete Xml logs.

Alex
Avatar
Lightbarrier #11
Member since Jul 2014 · 52 posts
Group memberships: Members
Show profile · Link to this post
Okay, so I guess I was being a idiot and forgot to register the elements in the factory, I can now deserialize the list just find to get the element for the list. However, it seems that the Chat object isn't having the "start" and "with" variables assigned to their appropriate elements, upon using the following below despite creating the object. I'm not sure why this is, the Chat class is still the same as above any ideas.



  1. var list = iq.Element<List>();
  2. var chats = list.Elements<Chat>();
Avatar
Alex #12
Member since Feb 2003 · 4327 posts · Location: Germany
Group memberships: Administrators, Members
Show profile · Link to this post
those are Xml Attributes, but in your object class you have tags.

check GetTag/SetTag vs GetAttribute/SetAttribute
Avatar
Lightbarrier #13
Member since Jul 2014 · 52 posts
Group memberships: Members
Show profile · Link to this post
Subject: Current Situation
Hmmm, it's the same as what I showed you before, and it seems to match the xml.


Retrieved XML:
  1. <chat with="hotel.agent1@ajksdfjasfsja" start="2014-08-07T18:38:39.157Z" xmlns="urn:xmpp:archive" />

Chat Class:
  1.         public Chat()
  2.             : base("urn:xmpp:archive", "chat")
  3.         {
  4.         }
  5.  
  6.         public string With
  7.         {
  8.             get { return GetTag("with"); }
  9.             set { SetTag("with", value); }
  10.         }
  11.  
  12.  
  13.         public string Start
  14.         {
  15.             get { return GetTag("start"); }
  16.             set { SetTag("start", value); }
  17.         }

How I'm Retrieving:
  1.         private static void RegisterCustomElements()
  2.         {
  3.             Factory.RegisterElement<List>("urn:xmpp:archive", "list");
  4.             Factory.RegisterElement<Chat>("urn:xmpp:archive", "chat");
  5.         }
  6.  
  7.         var list = iq.Element<List>();
  8.         var chats = list.Elements<Chat>();
  9.         foreach (Chat temp in chats)
  10.         {
  11.               System.Diagnostics.Debug.WriteLine(temp);
  12.          }

I could retrieve the data doing something like this, but that seems to destroy the point.

  1.       foreach (Chat temp in chats)
  2.        {
  3.             string address = temp.FirstAttribute.Value;
  4.             string date = temp.FirstAttribute.NextAttribute.Value;
  5.        }
Avatar
Alex #14
Member since Feb 2003 · 4327 posts · Location: Germany
Group memberships: Administrators, Members
Show profile · Link to this post
Your Xml is:

  1. <chat with="hotel.agent1@ajksdfjasfsja" start="2014-08-07T18:38:39.157Z" xmlns="urn:xmpp:archive" />

  • with="hotel.agent1@ajksdfjasfsja"
  • start="2014-08-07T18:38:39.157Z"

are Attributes

in your code you have definded them as Tags:

  1. public string With
  2. {
  3.     get { return GetTag("with"); }
  4.     set { SetTag("with", value); }
  5. }
  6.  
  7.  
  8. public string Start
  9. {
  10.     get { return GetTag("start"); }
  11.     set { SetTag("start", value); }
  12. }

change this to:

  1. public string With
  2. {
  3.     get { return GetAttribute("with"); }
  4.     set { SetAttribute("with", value); }
  5. }
  6.  
  7.  
  8. public string Start
  9. {
  10.     get { return GetAttribute("start"); }
  11.     set { SetAttribute("start", value); }
  12. }

and it should work.

The serialize need only the constructor. It does not call your properties. This is why it serializes the Xml correct, even with your wrong code.

Alex
Avatar
Lightbarrier #15
Member since Jul 2014 · 52 posts
Group memberships: Members
Show profile · Link to this post
Subject: Thank you
Works great thanks Alex, I guess I misunderstood since I was looking at your example with the setTag. Hopefully that should be the last question. Thanks for helping me through this process for setting up a new Iq, I really do appreciate it.
Close Smaller – Larger + Reply to this post:
Verification code: VeriCode Please enter the word from the image into the text field below. (Type the letters only, lower case is okay.)
Smileys: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Special characters:
Page:  1  2  next
Forum: MatriX RSS