5

Spent hours trying to solve this problem and I'm stumped!

Trying to grab the Chat History between 2 users on my OpenFire server and I read that I plugin was needed to do this.

So, I installed the 'Open Archive' plugin on my OpenFire server and send the following XML (as per the XMPP-0136 protocol documentation):

<iq type="get" id="page1">
   <retrieve xmlns="urn:xmpp:archive" with="username@server.com" start="1469-07-21T02:56:15Z">
      <set xmlns="http://jabber.org/protocol/rsm">
         <max>100</max>
      </set>
   </retrieve>
</iq>

In code, this is achieved via the following:

NSXMLElement *iQ = [NSXMLElement elementWithName:@"iq"];
[iQ addAttributeWithName:@"type" stringValue:@"get"];
[iQ addAttributeWithName:@"id" stringValue:@"page1"];

NSXMLElement *retrieve = [NSXMLElement elementWithName:@"retrieve"];
[retrieve addAttributeWithName:@"xmlns" stringValue:@"urn:xmpp:archive"];
[retrieve addAttributeWithName:@"with" stringValue:@"username@server.com"];
[retrieve addAttributeWithName:@"start" stringValue:@"1469-07-21T02:56:15Z"];

NSXMLElement *set = [NSXMLElement elementWithName:@"set"];
[set addAttributeWithName:@"xmlns" stringValue:@"http://jabber.org/protocol/rsm"];
NSXMLElement *max = [NSXMLElement elementWithName:@"max"];
max.stringValue = @"100";
[set addChild:max];

[retrieve addChild:set];
[iQ addChild:retrieve];

[[[self appDelegate] xmppStream] sendElement:iQ];

Which returns the following error:

<iq xmlns="jabber:client" type="error" id="page1" to="username@server.com">
   <error code="404" type="cancel">
      <item-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
   </error>
</iq>

My Xcode project can successfully send/receive messages to the user I'm trying to receive chat history from so I really don't know what I'm doing wrong. Also the Plugin enables me to search through Chat Messages (via OpenFire admin) with successful results so it seems to be working and storing the messages.

Any help would be appreciated. Thanks!

Keith OYS
  • 2,285
  • 5
  • 32
  • 38
user1168056
  • 401
  • 8
  • 19
  • Here is the solution. http://stackoverflow.com/questions/11397172/xmpp-retrieve-archive-messages-from-openfire-server – Karun Mar 13 '14 at 12:55

4 Answers4

7

If you are looking for a chat history, I think you have to save the messages to core data and retrieve them from there. For saving data using the XMPPFramework inbuilt functionality, you have to use this code:

XMPPMessageArchivingCoreDataStorage *storage = [XMPPMessageArchivingCoreDataStorage   sharedInstance];
NSManagedObjectContext *moc = [storage mainThreadManagedObjectContext];

xmppMessageArchivingStorage = [XMPPMessageArchivingCoreDataStorage sharedInstance];
xmppMessageArchivingModule = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:xmppMessageArchivingStorage];
[xmppMessageArchivingModule activate:xmppStream];
[xmppMessageArchivingModule  addDelegate:self delegateQueue:dispatch_get_main_queue()];

Now you have to retrieve that messages from core data by this:

-(void)loadarchivemsg
{  
    XMPPMessageArchivingCoreDataStorage *storage = [XMPPMessageArchivingCoreDataStorage sharedInstance];
    NSManagedObjectContext *moc = [storage mainThreadManagedObjectContext];
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"XMPPMessageArchiving_Message_CoreDataObject"
                                                      inManagedObjectContext:moc];
    NSFetchRequest *request = [[NSFetchRequest alloc]init];

    NSString *predicateFrmt = @"bareJidStr like %@ ";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateFrmt, chatWithUser];
    request.predicate = predicate;
    NSLog(@"%@",[[NSUserDefaults standardUserDefaults] stringForKey:@"kXMPPmyJID"]);
    [request setEntity:entityDescription];
    NSError *error;
    NSArray *messages_arc = [moc executeFetchRequest:request error:&error];

    [self print:[[NSMutableArray alloc]initWithArray:messages_arc]];
}

-(void)print:(NSMutableArray*)messages_arc{
    @autoreleasepool {
        for (XMPPMessageArchiving_Message_CoreDataObject *message in messages_arc) {
            NSXMLElement *element = [[NSXMLElement alloc] initWithXMLString:message.messageStr error:nil];
            NSLog(@"to param is %@",[element attributeStringValueForName:@"to"]);

            NSMutableDictionary *m = [[NSMutableDictionary alloc] init];
            [m setObject:message.body forKey:@"msg"];

            if ([[element attributeStringValueForName:@"to"] isEqualToString:chatWithUser]) {               
                [m setObject:@"you" forKey:@"sender"];
            }
            else {
                [m setObject:chatWithUser forKey:@"sender"];
            }

            [messages addObject:m];

            NSLog(@"bareJid param is %@",message.bareJid);
            NSLog(@"bareJidStr param is %@",message.bareJidStr);
            NSLog(@"body param is %@",message.body);
            NSLog(@"timestamp param is %@",message.timestamp);
            NSLog(@"outgoing param is %d",[message.outgoing intValue]);
            NSLog(@"***************************************************");
        }
    }
}
honk
  • 9,137
  • 11
  • 75
  • 83
Mitul Bhadeshiya
  • 1,280
  • 1
  • 12
  • 32
  • I not getting one point where should we have to give the other user JID.Can you show the particular place with comment. – Romance Dec 16 '13 at 05:17
  • [NSPredicate predicateWithFormat:predicateFrmt, chatWithUser]; here chatWithUser is other user JID you can set there other user JID – Mitul Bhadeshiya Dec 16 '13 at 05:36
  • yes i got it, I am facing some other issue,i am using your code but while i am reterving the code iam getting last two messages of the chat history and i am not getting full history.Plz giveme sol. – Romance Dec 16 '13 at 06:47
  • @Romance i am using the same code and i get all messages of between to JID , check twice (check you sqlite data also and compare both) it's working perfect. – Mitul Bhadeshiya Dec 16 '13 at 07:10
  • i was not using any sqlite i want to reterive whole information from xmpp so can i able do that , and that too while sending the message you have kept one code in the answer, xmppMessageArchivingStorage = [XMPPMessageArchivingCoreDataStorage sharedInstance]; xmppMessageArchivingModule = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:xmppMessageArchivingStorage]; [xmppMessageArchivingModule activate:xmppStream]; [xmppMessageArchivingModule addDelegate:self delegateQueue:dispatch_get_main_queue()];.Can i know when it usefull.what will it perform. – Romance Dec 16 '13 at 07:15
  • that code is put when you are create xmppstream connection. that is enable you to create codedata XMPPMessageArchivingCoreDataStorage is for send receive message storage (exmpp not maintain any message history ) – Mitul Bhadeshiya Dec 16 '13 at 07:29
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/43233/discussion-between-romance-and-mits-bhadeshiya) – Romance Dec 16 '13 at 07:30
  • @MitsBhadeshiya What if I get a message when I am not there in online... means how can we retrieve off line messages..... – AMohan Jan 23 '14 at 10:43
  • 2
    @Mohan if user is offline that all messages stored in server when user online that all messages are send to the user as a delay messages. so that you have to handle that messages... i hope you are understand – Mitul Bhadeshiya Jan 23 '14 at 12:42
  • @Mohan can you please give up Mark if you are getting your solution .. :) – Mitul Bhadeshiya Jan 24 '14 at 06:30
  • This is the process for client side archiving. could you please share the retrieval of messages from openfire server? – Karun Mar 10 '14 at 11:39
  • hi ... in this method i am getting the actual message ...- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message... where i need to write the code for to save the message in the database – MANCHIKANTI KRISHNAKISHORE Sep 09 '14 at 08:58
  • Hi @MitulBhadeshiya I have implemented XMPP with openfire and trying to get offline messages. I have initialized XMPPMessageArchiving and also added delegate. But still I am not getting offline message. Have you done any additional setup to get offline messages? – Jayeshkumar Sojitra Mar 20 '15 at 06:28
  • Its working fine but I tried to get all messages after deleting application or by login to another device, in both of this case this solution failed. Any idea for this type of requirement? – cjd Mar 21 '15 at 09:42
  • Helllo .... I am facing a issue friends. Unable to archive messages, it gives error here - (id)initWithMessageArchivingStorage:(id )storage dispatchQueue:(dispatch_queue_t)queue in XMPPMessageArchiving.m – Moin Shirazi Jun 23 '16 at 08:19
4

Please have a detailed Stanza detail at : https://stackoverflow.com/a/29097289/2225439

It is Platform independent just you need to understand the structure of Stanza and can be created as per the libraries that you are using.

This is the Series of Stanza that you will need to send to get Archived Messages. For more detail you can checkout XEP 0136 (http://xmpp.org/extensions/xep-0136.html#manual)

REQ

<iq type='get' id='mrug_sender@staging.openfire.com'>
       <list xmlns='urn:xmpp:archive'
               with='mrug_target_155@staging.openfire.com'>
        <set xmlns='http://jabber.org/protocol/rsm'>
            <max>6900</max>
        </set>
      </list>
   </iq>

RES

<iq type="result" id="mrug_sender@staging.openfire.com" to="mrug_sender@staging.openfire.com/Psi">
<list xmlns="urn:xmpp:archive">
<chat with="mrug_target_155@staging.openfire.com" start="2014-06-07T06:52:26.041Z"/>
<chat with="mrug_target_155@staging.openfire.com" start="2014-06-07T07:06:53.372Z"/>
<set xmlns="http://jabber.org/protocol/rsm">
<first index="0">866</first>
<last>867</last>
<count>2</count>
</set>
</list>
</iq>

REQ

<iq type='get' id='mrug_sender@staging.openfire.com'>
    <retrieve xmlns='urn:xmpp:archive'  with='mrug_target_155@staging.openfire.com'  start='2014-06-07T06:52:26.041Z'>
     <set xmlns='http://jabber.org/protocol/rsm'>
       <max>8000</max>
     </set>
    </retrieve>
 </iq>

RES

<iq type="result" id="mrug_sender@staging.openfire.com" to="mrug_sender@staging.openfire.com/Psi">
<chat xmlns="urn:xmpp:archive" with="mrug_target_155@staging.openfire.com" start="2014-06-07T06:52:26.041Z">
<from secs="0" jid="mrug_target_155@staging.openfire.com">
<body>Hello This is Cool</body>
</from>
<set xmlns="http://jabber.org/protocol/rsm">
<first index="0">0</first>
<last>0</last>
<count>1</count>
</set>
</chat>
</iq>

To Fetch List of all Conversations

<iq type='get' id='mrug_sender@staging.openfire.com'>
       <list xmlns='urn:xmpp:archive'>
        <set xmlns='http://jabber.org/protocol/rsm'>
            <max>6900</max>
        </set>
      </list>
</iq>
Community
  • 1
  • 1
Mrug
  • 4,963
  • 2
  • 31
  • 53
1

When you mention start tag in the request then it matches with the chat having the exact time stamp that's why it returns error code '404' or '500'. I ommited start tag from my request and wrote following code which returns whole chat history with the user.

NSXMLElement *iq1 = [NSXMLElement elementWithName:@"iq"];
[iq1 addAttributeWithName:@"type" stringValue:@"get"];
[iq1 addAttributeWithName:@"id" stringValue:@"pk1"];

NSXMLElement *retrieve = [NSXMLElement elementWithName:@"retrieve" xmlns:@"urn:xmpp:archive"];

[retrieve addAttributeWithName:@"with" stringValue:@"rahul@vishals-mac-pro.local"];
NSXMLElement *set = [NSXMLElement elementWithName:@"set" xmlns:@"http://jabber.org/protocol/rsm"];
NSXMLElement *max = [NSXMLElement elementWithName:@"max" stringValue:@"100"];

[iq1 addChild:retrieve];
[retrieve addChild:set];
[set addChild:max];
[[[self appDelegate] xmppStream] sendElement:iq1]; 

Here this will return whole chat history in XML response between user Rahul and the user currently logged in.

For more detailed info please refer this blog http://question.ikende.com/question/363439343236313430

sajgan2015
  • 305
  • 3
  • 10
0

XMPPFramework implements XEP-0136. Have you tried using XMPPMessageArchiving to set preferences or synchronize the server's archive to the client?

paulmelnikow
  • 16,895
  • 8
  • 63
  • 114
  • 1
    Hi @noa! Could you please share an example of how to set preferences for archiving and synchronizing the server's archive to the client. – Karun Mar 10 '14 at 08:04