I am writing an iOS chat application using XMPPFramework, and I am wondering what's the best way to create a new message so I can map the XMPPMessage that gets returned in one of the delegate methods back to the original message that is sent. I want to do this so I can tell when sending a message is successful or unsuccessful (so I can cache and resend it).
Upon the user hitting the send key on the client, the following code is called to create and send the message:
NSXMLElement *body = [NSXMLElement elementWithName:#"body"];
[body setStringValue:messageText];
NSXMLElement *message = [NSXMLElement elementWithName:#"message"];
[message addAttributeWithName:#"type" stringValue:#"chat"];
[message addAttributeWithName:#"to" stringValue:recipientJID];
[message addChild:body];
[[self xmppStream] sendElement:message];
Then I store the contents, recipient, timestamp, etc. into a custom object (basically everything in message) in an array.
I want to be able to match an object in the array to the XMPPMessage object returned in either of these delegate methods:
- (void)xmppStream:(XMPPStream *)sender didFailToSendMessage:(XMPPMessage *)message error:(NSError *)error
{
}
- (void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message
{
}
Is there an attribute that I can add some kind of unique identifier to in the message variable that I send via XMPPStream that will then show up within the XMPPMessage passed to those delegate methods?
Why don't you send a XMPPMessage instead of a NSXMLElement? That way the object passed in didFailToSendMessage and didSendMessage will match the one you send. Besides, you can set elementId to identify stanzas (Messages, IQs or Presence)
XMPPMessage *message = [XMPPMessage messageWithType:#"chat"
to:someJid
elementID:elementId];
[[self xmppStream] sendElement:message];
I'm working on an iOS app with XMPPFramework and Openfire Server. I work with a book to implement it, but there are some parts I don't understand because the book makes references to Google Talk and I can't figure out what to do in those methods:
The first one is about presence, here is the code that is implemented in the book:
-(void)goOnline
{
XMPPPresence *presence = [XMPPPresence presence];
NSString *domain = [self.xmppStream.myJID domain];
// Google set their presence priority to 24, so we do the same to be compatible.
if ([domain isEqualToString:#"gmail.com"] || [domain isEqualToString:#"gtalk.com"])
{
NSXMLElement *priority = [NSXMLElement elementWithName:#"priority" stringValue:#"24"];
[presence addChild:priority];
}
[[self xmppStream] sendElement:presence];
[self.rootViewController updateStatus:#"online"];
}
As I'm working on localhost with my own server name, I don't know exactly what to do with presence or if Openfire have a value for the presence priority.
For changing my logged status I used the following code:
XMPPPresence *presence = [XMPPPresence presenceWithType:#"away"];
[[self xmppStream] sendElement:presence];
But I am not getting the reference of [self xmppStream]. So I changed to the following code:
XMPPPresence *presence = [XMPPPresence presence];
NSXMLElement *status = [NSXMLElement elementWithName:#"status"];
[status setStringValue:#"away"];
[presence addChild:status];
NSError *error = nil;
xmppStream = [[XMPPStream alloc] init];
[xmppStream disconnect];
NSString *myJID = [NSString stringWithFormat:#"%#", appDelegate.jid];
XMPPJID *JID;
JID = [XMPPJID jidWithString:myJID];
NSLog(#"%#",JID);
[xmppStream setMyJID:JID];
xmppStream.hostName=#"talk.google.com";
[xmppStream connect:&error];
[xmppStream sendElement:presence];
Still not getting the changed status. Please share your ideas. Thanks in advance.
You can change your status immediately after you're logged in via goOnline method as it is called after xmppStreamDidAuthenticate.
- (void)goOnline
{
// Initialize XMPPPresence variable
XMPPPresence *presence = [XMPPPresence presence];
// Initialize XML element <show/> for specifying your status
NSXMLElement *show = [NSXMLElement elementWithName:#"show"];
// Initialize XML element <status/> for describing your status
NSXMLElement *status = [NSXMLElement elementWithName:#"status"];
// If you want your user status to be shown as "Available"
[show setStringValue:#"chat"];
[status setStringValue:#"Available"];
// If you want your user status to be shown as "Busy"
[show setStringValue:#"dnd"];
[status setStringValue:#"Busy"];
// If you want your user status to be shown as "Away"
[show setStringValue:#"away"];
[status setStringValue:#"Away"];
// If you want your user status to be shown as "Off-day"
[show setStringValue:#"xa"];
[status setStringValue:#"Off-day"];
// Add the XML elements to XMPPPresence
[presence addChild:show];
[presence addChild:status];
// Update new presence to server
[xmppStream sendElement:presence];
}
For more information and an explanation to my code above, visit Change XMPPPresence to Away/Busy/Invisible.
You have to wait until after you're connected to send stanzas, by listening for xmppStreamDidAuthenticate on the delegate.
Also, don't bother to set the to or from JID when broadcasting your presence.
I am developing an iOS XMPP chat app that utilizes Robbie Hanson's XMPPFramework.
The most important functionalities have been implemented - sending and receiving messages. Basically, I've built a basic functional chat app already, with a little eye candy of course.
Now, the problem I have is regarding MUC. The codes I saw from other websites show that there is a method initWithRoomName in XMPPRoom. However, this method is absent in the git repo I cloned. So, what is the alternative to this? Or, if there is none, how do I go about creating rooms using XMPPFramework?
Thanks.
Below is how I got my own problem solved. Note that this solution does not involve XMPPRoom at all. First, I created a method that, depending on the situation, either creates or enters a room. (Per XMPP documentation, the XML request for creating is the same is the same as the one you would send to enter a room; that is, if the room has does not exist yet when you enter it, the service will create it for you.)
Here we go. This is the method that creates/enters a room. What this method does is send a presence to the room which you intend to create/enter. If you are the first to enter a room and the room has not been created yet, you automatically become its owner and moderator.
- (void)createOrEnterRoom:(NSString *)roomName
{
//here we enter a room, or if the room does not yet exist, this method creates it
//per XMPP documentation: "If the room does not yet exist, the service SHOULD create the room"
//this method accepts an argument which is what you would baptize the room you wish created
NSXMLElement *presence = [NSXMLElement elementWithName:#"presence"];
NSString *room = [roomName stringByAppendingString:#"#conference.jabber.com/iMac"];
[presence addAttributeWithName:#"to" stringValue:room];
NSXMLElement *x = [NSXMLElement elementWithName:#"x" xmlns:#"http://jabber.org/protocol/muc"];
NSXMLElement *history = [NSXMLElement elementWithName:#"history"];
[history addAttributeWithName:#"maxstanzas" stringValue:#"50"];
[x addChild:history];
[presence addChild:x];
[[self xmppStream] sendElement:presence];
}
Next, in the AppDelegate where XMPPStream methods are declared we filter the XML response we receive in the didReceivePresence method by checking the status code sent by the server. If the status code is 201, bingo! The room creation went just fine. Status codes other than 201 mean different things, but let's focus on 201 for our purpose.
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
{
NSXMLElement *x = [presence elementForName:#"x" xmlns:#"http://jabber.org/protocol/muc#user"];
for (NSXMLElement *status in [x elementsForName:#"status"])
{
switch ([status attributeIntValueForName:#"code"])
{
case 201: [self notifyRoomCreationOk:room];
}
}
}
Then, we tell the server that what we are creating a room of the type "instant," which means that we will send an IQ element telling it room defaults. notifyRoomCreationOk is a delegate method called in a different view when the room creation succeeds, after all I have to record the room in a text file to make it persistent so that the next time I open the app the room I created before will be visible. In my notifyRoomCreationOk method, I have sendDefaultRoomConfig which, basically, describes what is stated in the first sentence of this paragraph.
-(void)sendDefaultRoomConfig:(NSString *)room
{
NSXMLElement *x = [NSXMLElement elementWithName:#"x" xmlns:#"jabber:x:data"];
[x addAttributeWithName:#"type" stringValue:#"submit"];
NSXMLElement *query = [NSXMLElement elementWithName:#"query" xmlns:#"http://jabber.org/protocol/muc#owner"];
[query addChild:x];
XMPPIQ *iq = [XMPPIQ iq];
[iq addAttributeWithName:#"id" stringValue:[NSString stringWithFormat:#"inroom-cr%#", room]];
[iq addAttributeWithName:#"to" stringValue:room];
[iq addAttributeWithName:#"type" stringValue:#"set"];
[iq addChild:query];
[[self xmppStream ] sendElement:iq];
}
Make sure that you have XMPPStream enabled on the views that call the above methods, otherwise, these won't work. That's all there is to it. Have fun XMPP-ing!
XMPPRoom *room = [[XMPPRoom alloc] initWithRoomName:#"user101#conference.jabber.org/room" nickName:#"room"];
[room createOrJoinRoom];
[room sendInstantRoomConfig];
[room setInvitedUser:#"ABC#jabber.org"];
[room activate:[self xmppStream]];
[room inviteUser:jid1 withMessage:#"hello please join."];
[room sendMessage:#"HELLO"];
the user ABC#jabber.org should receive the invite message
Your post is old, however now I would do it like this:
- (void)createRoomWithJid:(XMPPJID*)roomJID
{
XMPPRoom *xmppRoom = [[XMPPRoom alloc] initWithRoomStorage:self.xmppRoomHybridStorage
jid:roomJID
dispatchQueue:dispatch_get_main_queue()];
[xmppRoom addDelegate:self delegateQueue:dispatch_get_main_queue()];
[xmppRoom activate:self.xmppStream];
[xmppRoom joinRoomUsingNickname:self.xmppStream.myJID.user
history:nil
password:nil];
}
Create chat room by given below code using XMPPFRAMWORK.
let roomStorage: XMPPRoomMemoryStorage = XMPPRoomMemoryStorage()
/**
* Remember to add 'conference' in your JID like this:
* e.g. uniqueRoomJID#conference.yourserverdomain
*/
let roomJID: XMPPJID = XMPPJID.jidWithString("chatRoom_name#conference.myhostname")
let xmppRoom: XMPPRoom = XMPPRoom(roomStorage: roomStorage,
jid: roomJID,
dispatchQueue: dispatch_get_main_queue())
xmppRoom.activate(SKxmpp.manager().xmppStream)
xmppRoom.addDelegate(self, delegateQueue: dispatch_get_main_queue())
xmppRoom.joinRoomUsingNickname(SKxmpp.manager().xmppStream.myJID.user, history: nil, password: nil)
xmppRoom.fetchConfigurationForm()
I'm trying to set the users presence to away (or anything at the moment). I'm using the following code but it doesn't seem to do anything.
XMPPPresence *presence = [XMPPPresence presence];
NSXMLElement *show = [NSXMLElement elementWithName:#"show" stringValue:#"away"];
NSXMLElement *status = [NSXMLElement elementWithName:#"status" stringValue:#"away"];
[presence addChild:show];
[presence addChild:status];
[[self xmppStream] sendElement:presence];
I've used iChat to make sure all the presence subscriptions on my Ejabberd server are correct and working. This is driving me crazy, am I missing something?
I figured it out, turns out the presence wasn't being sent out by the app as I'd missed this out:
- (MMApplication *)appDelegate {
return (MMApplication *)[[UIApplication sharedApplication] delegate];
}
- (XMPPStream *)xmppStream {
return [[self appDelegate] xmppStream];
}
Works perfectly now