typing indication in xmpp chat in iphone - iphone

I am developing chat application using XMPP. Here my problem is, I want to send chat notifications .I tried the fallowing way but not getting correctly.
- (void)sendMessage:(id)sender
{
NSString *messageStr =messageField.text;
if([messageStr length] > 0)
{
NSXMLElement *body = [NSXMLElement elementWithName:#"body"];
NSXMLElement *chatStatus=[NSXMLElement elementWithName:#"composing" xmlns:xmlns_chatstates];
[body setStringValue:messageStr];
NSXMLElement *message = [NSXMLElement elementWithName:#"message"];
[message addAttributeWithName:#"type" stringValue:#"chat"];
[message addAttributeWithName:#"to" stringValue:jidString];
[message addChild:chatStatus];
[message addChild:body];
[[self xmppStream] sendElement:message];
}
}
I am using above method for sending a message.But it always shows typing notification even i am not typing .can any one help to me.
thanks in advance

According to XEP-0085: Chat State Notifications, you should send another notification saying you've stopped typing, for example <active/> or <paused/>.

Related

XMPP push notifications causing problems (delay + duplications) in messages

XMPP push notifications causing problems (delay + duplications) in messages.
I have successfully created a chat application using XMPP + Ejabberd.
Without Push Notifications:
Both single and group chat messages are working perfectly.
With Push Notifications:
Sometimes everything works perfectly.Notifications are triggered and messages are received with out any delay or duplications.
Sometimes no notifications are triggered (while app in background) but messages are received perfectly.
Sometimes notifications are triggered but messages are received with delay and duplications.
Everything on the sever side is configured correctly.They advised to fix your issues by making sure each session connects with one persistent resource, making connection stable using whitespace keep alive and when connection is lost just rebinding with same resource.
I have stream management,xmppStream.enableBackgroundingOnSocket and App provides Voice over IP services background mode enabled.
When user logs out or app is terminated i teardown the stream and send an unavailable presence.
Below is my code for xmpp stream push notifications and connect/disconnect.
I am pulling out my hair over this.if you guys have any idea please let me know.
Thanks.
#pragma mark - Connect/Disconnect
- (BOOL)connect {
if (!_xmppStream) {
NSLog(#"Setting up Stream");
[self setupStream];
}
if (![_xmppStream isDisconnected]) {
return YES;
}
NSString *jabberID = [[NSUserDefaults standardUserDefaults] stringForKey:#"userID"];
NSString *myPassword = [[NSUserDefaults standardUserDefaults] stringForKey:#"userPassword"];
if (jabberID == nil || myPassword == nil) {
return NO;
}
[_xmppStream setMyJID:[XMPPJID jidWithString:jabberID]];
_password = myPassword;
NSError *error = nil;
if (![_xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:&error]){
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:[NSString stringWithFormat:#"Can't connect to server! %#", [error localizedDescription]] delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
return NO;
}
return YES;
}
- (void)disconnect {
[self goOffline];
[self teardownStream];
}
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
[self goOnline];
//Stream Management
NSXMLElement *enable = [NSXMLElement elementWithName:#"enable" xmlns:#"urn:xmpp:sm:3"];
[enable addAttributeWithName:#"resume" stringValue:#"true"];
[_xsm.xmppStream sendElement:enable];
//Push
[self configurePushNotifications];
//
}
-(void)configurePushNotifications{
NSString *jabberID = [[NSUserDefaults standardUserDefaults] stringForKey:#"userID"];
NSXMLElement *iq = [NSXMLElement elementWithName:#"iq"];
[iq addAttributeWithName:#"type" stringValue:#"set"];
[iq addAttributeWithName:#"id" stringValue:idString];
NSXMLElement *push = [NSXMLElement elementWithName:#"push" xmlns:#"p1:push"];
NSXMLElement *keepalive = [NSXMLElement elementWithName:#"keepalive"];
[keepalive addAttributeWithName:#"max" integerValue:30];
NSXMLElement *session = [NSXMLElement elementWithName:#"session"];
[session addAttributeWithName:#"duration" integerValue:60];
NSXMLElement *body = [NSXMLElement elementWithName:#"body"];
[body addAttributeWithName:#"send" stringValue:#"all"];
[body addAttributeWithName:#"groupchat" stringValue:#"true"];
[body addAttributeWithName:#"from" stringValue:jabberID];
NSXMLElement *status = [NSXMLElement elementWithName:#"status"];
[status addAttributeWithName:#"type" stringValue:[NSString stringWithFormat:#"New message from %#",jabberID]];
NSXMLElement *offline = [NSXMLElement elementWithName:#"offline" stringValue:#"true"];
[push addChild:keepalive];
[push addChild:session];
[push addChild:body];
[push addChild:status];
[push addChild:offline];
NSXMLElement *notification = [NSXMLElement elementWithName:#"notification"];
[notification addChild:[NSXMLElement elementWithName:#"type" stringValue:#"applepush"]];
[notification addChild:[NSXMLElement elementWithName:#"id" stringValue:_userDeviceToken]];
[push addChild:notification];
NSXMLElement *appid = [NSXMLElement elementWithName:#"appid" stringValue:#"appid"];
[push addChild:appid];
[iq addChild:push];
[[self xmppStream] sendElement:iq];
}
- (void)setupStream {
_xmppStream = [[XMPPStream alloc] init];
_xmppStream.hostName = kHostName;
_xmppStream.hostPort = kHostPort;
_xmppStream.enableBackgroundingOnSocket = YES;
[_xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
//XMPPReconnect
_xmppReconnect = [[XMPPReconnect alloc] init];
[_xmppReconnect activate:_xmppStream];
//Stream Management
_xsm = [[XMPPStreamManagement alloc] init];
[_xsm enableStreamManagementWithResumption:YES maxTimeout:0];
[_xsm activate:_xmppStream];
//Last Activity
_xmppLastActivity = [[XMPPLastActivity alloc] initWithDispatchQueue:dispatch_get_main_queue()];
[_xmppLastActivity addDelegate:self delegateQueue:dispatch_get_main_queue()];
[_xmppLastActivity activate:_xmppStream];
}
- (void)goOnline {
XMPPPresence *presence = [XMPPPresence presence];
[[self xmppStream] sendElement:presence];
}
- (void)goOffline {
XMPPPresence *presence = [XMPPPresence presenceWithType:#"unavailable"];
[[self xmppStream] sendElement:presence];
}
- (void)teardownStream {
[_xmppStream disconnect];
[_xmppStream removeDelegate:self];
[_xmppReconnect removeDelegate:self];
[_xmppLastActivity removeDelegate:self];
[_xmppReconnect deactivate];
_xmppStream = nil;
_xmppReconnect = nil;
_xmppLastActivity = nil;
}
You need to make sure that you are passing the resource when you connect to ejabberd. The resource should be randomly generated on first app install and on subsequent login, you should always use the same resource. Otherwise you are created a new long running detached session on each new login on the server and causing messages to be routed to all pending sessions. When those expires they are routed again etc.
In XMPP, the resource is the identifier of the device basically. You need to generate the JID for login with a string of form "user#domain/resource"
you should notify stream management to disconnect your session and
call this method for disconnect in tearDown :
[self.stream disconnectAfterSending];

IOS Chat application using XMPP Protocol (ejabberd) Room chat issue

I am developing an IOS Chat application using XMPP Protocol(ejabberd). My chat room is created at my server, it return roomID to me.
I am facing an issue in room/group chat. When i am sending a single message it is repeating more than once like 3 to 4 times.How to fix this. My code is here
XMPPJID *roomJID = [XMPPJID jidWithString:[roomDict objectForKey:KEY_group_id]];
XMPPRoom *xmppRoom = [[XMPPRoom alloc] initWithRoomStorage:xmppRoomCoreDataStorage jid:roomJID dispatchQueue:dispatch_get_main_queue()];
[xmppRoom activate:[ChatHandler sharedInstance].xmppStream];
[xmppRoom addDelegate:self
delegateQueue:dispatch_get_main_queue()];
[self insertRoomObjectWithDictionary:roomDict];
[xmppRoom joinRoomUsingNickname:[[ChatHandler sharedInstance] xmppStream].myJID.user
history:nil
password:#""];
[xmppRoom fetchConfigurationForm];
return xmppRoom;
Following code snippet worked for me.. Try it for your code...
I have sent uuid of my device as child while sending message and checked the same uuid at the time of incoming message :
-(void)sendMessageWithBody:(NSString *)messageBody
{
if ([messageBody length] == 0) return;
NSXMLElement *body = [NSXMLElement elementWithName:#"body" stringValue:messageBody];
XMPPMessage *message = [XMPPMessage message];
[message addChild:body];
NSString *uuidString=[UIDevice currentDevice].identifierForVendor.UUIDString;
NSXMLElement *myMsgLogic=[NSXMLElement elementWithName:#"myMsgLogic" stringValue:uuidString];
[message addChild:myMsgLogic];
[self sendMessage:message];
}
-(void)xmppRoom:(XMPPRoom *)sender didReceiveMessage:(XMPPMessage *)message fromOccupant:(XMPPJID *)occupantJID;
{
[self handleIncomingMessage:message room:xmppRoom];
}
-(void)handleIncomingMessage:(XMPPMessage *)message room:(XMPPRoom *)room
{
NSString *uuidString=[UIDevice currentDevice].identifierForVendor.UUIDString;
NSString *messageLogic= [[message elementsForName:#"myMsgLogic"].firstObject stringValue];
if ([uuidString isEqualToString:messageLogic]) {
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:#"handleIncomingMessage" message:[message body] delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
}
}
I have the same chat application using xmpp ejabbered. I was also facing the same problem. In my case on xmpp server they have set offline message storage to 100. If in offline mode the message limit crossed 100 then from 101th message I will get bounce back that message. So as a solution we changed the offline message limit to 500.
{mod_offline_odbc, [
{user_max_messages, 500}
]}

XMPPFarmework How to obtain XMPP chat room list in iOS?

XMPPFarmework us openfire
How to obtain XMPP chat room list in iOS ?
Anyone please show me a way to solve out this.Thanks!
Below code works for us when connected to an ejabberd server on Amazon EC2 and hope it should work for Openfire too.
- (void) getChatRooms:(XMPPStream *)stream
{
NSString* server = #"conference.myserver.com";
XMPPJID *servrJID = [XMPPJID jidWithString:server];
XMPPIQ *iq = [XMPPIQ iqWithType:#"get" to:servrJID];
[iq addAttributeWithName:#"id" stringValue:#"chatroom_list"];
[iq addAttributeWithName:#"from" stringValue:[stream myJID].full];
NSXMLElement *query = [NSXMLElement elementWithName:#"query"];
[query addAttributeWithName:#"xmlns" stringValue:#"http://jabber.org/protocol/disco#items"];
[iq addChild:query];
[firstStream sendElement:iq];
}
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
DDLogVerbose(#"%#", [iq description]);
}

how can i send message from different accounts in xmpp

I am developing chat application using xmpp client. I can send and receive message when I login with one account. My problem is when i login with two different account i cannot send message using First login account. For sending message i tried the fallowing code:
- (void)sendMessage:(id)sender
{
xmppStream=[[self appDelegate] xmppStream];
NSString *messageStr =messageField.text;
if([messageStr length] > 0)
{
NSXMLElement *body = [NSXMLElement elementWithName:#"body"];
[body setStringValue:messageStr];
NSXMLElement *message = [NSXMLElement elementWithName:#"message"];
[message addAttributeWithName:#"type" stringValue:#"chat"];
[message addAttributeWithName:#"to" stringValue:jidStr];
[message addChild:body];
NSLog(#"%#",message);
}
}
In this delegate method, i create stream object like fallowing
-(void)setUpStream
{
XMPPStream *xmppStream=[XMPPStream alloc] init]
}
when i second time login with another account then xmppStream object is associated with second account but not for First account.
so i can't send message using first account.can any one solve my problem plz and how to create two xmppStream objects for two accounts;
The easiest way to do this is to create to xmppStream objects in your AppDelegate.
Call one xmppStreamOne and xmppStreamTwo.
You could even create an NSMutableArray of xmppStreams if you intent to log into many different different servers.
When you retrieve the xmppStream from the AppDelegate make sure to grab the right one.

XMPP 1 to 1 chat query?

I am developing a chat project using Openfire.
I have done with group chatting.
But confusion is in 1 to 1 chat.
I am using:
<message from='user2#server/user2' to='user1#server/user1' type='chat'>
<body>TEST< /body>
</message>
but it does not send it.
Thanks in advance.
Assuming that the spaces after the < characters shouldn't be there, it looks correct.
You can even do without the from attribute, since it'll be added by the server.
- (AppDelegate *)appDelegate
{
return (AppDelegate *)[[UIApplication sharedApplication] delegate];
}
- (XMPPStream *)xmppStream
{
return [[self appDelegate] xmppStream];
}
- (void)sendMessage:(id)sender
{
NSString *messageStr =messageField.text;
if([messageStr length] > 0)
{
NSXMLElement *body = [NSXMLElement elementWithName:#"body"];
[body setStringValue:messageStr];
NSXMLElement *message = [NSXMLElement elementWithName:#"message"];
[message addAttributeWithName:#"type" stringValue:#"chat"];
[message addAttributeWithName:#"to" stringValue:#"destination email address"];
[message addChild:body];
NSLog(#"%#",message);
[[self xmppStream] sendElement:message];
}
}
when you click on send button this method will be called and it shows log message as
<message type="chat" to="destination email address"><body>messageStr</body></message>
After fixing the syntax issues, removing the from address, and removing the doubtfully-correct resource from the to address, you're left with:
<message to='user1#server' type='chat'>
<body>TEST</body>
</message>
The resource on the to address is like the issue. Read XEP-0296 for how to deal with resources correctly when doing XMPP IM.