//
// ChatConnection.h
// ChatModule
//
// Created by Gaurav & Piyush on 27/06/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
// Ref: http://wiki.xmpp.org/web/Programming_XMPP_Clients
// http://xmpp.org/xmpp-protocols/xmpp-extensions/
// http://gauravds.blogspot.in/2012/06/nsstring-str-xmlnsjabberclient.html
#import <Foundation/Foundation.h>
#pragma mark - Chat Delegate Protocol
// a protocol
@protocol ChatDelegate <NSObject>
typedef enum ConnectionResponse{
kConnected,
kNotConnected
}ConnectionResponse;
@optional
- (void)chatConnectionResponse:(ConnectionResponse)connectionResponse;
typedef enum LoginResponse{
kLoginSuccess,
kLoginFail
}LoginResponse;
@optional
- (void)chatLoginResponse:(LoginResponse)loginResponse;
typedef enum MUCResponse{
kMUCJoinSuccess,
kMUCJoinFail,
kMUCLeaveSuccess,
kMUCLeaveFail,
kMUCMessageSendSuccess,
kMUCMessageSendFail
}MUCResponse;
@optional
- (void)chatMUCResponse:(MUCResponse)MUC_Response;
@optional
- (void)chatMUCMessageReceiveResponse:(NSDictionary*)receiveResponse;
@end
#pragma mark - Chat Connection Class
// class declaration
@interface ChatConnection : NSObject <NSStreamDelegate>
{
NSMutableData *data;
NSInputStream *inputStream;
NSOutputStream *outputStream;
CFReadStreamRef readStream ;
CFWriteStreamRef writeStream;
}
@property (nonatomic, strong) id<ChatDelegate> delegate;
@property (nonatomic, readonly) BOOL isChatConnectionAvailable;
#pragma mark connection methods
// --- singleton refernce
+ (ChatConnection*)sharedChatConnection;
// --- some connection methods
- (void)connectToServerUsingStream:(NSString *)urlStr
portNo:(uint)portNo;
- (void)disconnect;
- (void)writeToServer:(NSString*)stringXML;
- (void)stream:(NSStream *)stream
handleEvent:(NSStreamEvent)eventCode;
#pragma mark login signup chagne password methods
// --- some user Need methods
- (void)signUpWithUserName:(NSString*)userName
andPassword:(NSString*)password;
- (void)loginWithUserName:(NSString*)userName
andPassword:(NSString*)password;
- (void)changePasswordWithUserName:(NSString*)userName
andPassword:(NSString*)password;
#pragma mark Multi User Chat
// --- Multi user Chat methods
- (void)MUC_createOrJoinRoom:(NSString*)chatRoomName
andUsername:(NSString*)userName;
- (void)MUC_unlockRoomAndConfig:(NSDictionary*)dict;
- (void)MUC_leaveChatRoomName:(NSString*)chatRoomName
andUsername:(NSString*)userName;
- (void)MUC_chatOnChatRoomName:(NSString*)chatRoomName
andMessage:(NSString*)messageStr;
#pragma mark Single User Chat
// --- Single user chat methods
- (void)SUC_chatWithMessage:(NSString*)messageStr
toUser:(NSString*)toUser;
@end
--------------------------------------------------------------------------------------------
//
// ChatConnection.m
// ChatModule
//
// Created by Gaurav & Piyush on 27/06/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "ChatConnection.h"
#import "AppDelegate.h"
#import "XMLReader.h"
#define STREAM_START @"<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>"
#define STREAM_END @"</stream:stream>"
#define SERVER_NAME @"openfire"
#define RESOURCE_NAME @"iphone"
// private methods
@interface ChatConnection (privateMethods)
+ (BOOL)isNotNull:(NSString*)aString;
- (void)alertTitle:(NSString*)title withMessage:(NSString*)message;
- (void)alertTitle:(NSString*)title withMessage:(NSString*)message andDelegate:(id)delegateAlert;
- (void)sendPingResponse:(NSDictionary*)dict;
- (void)readServerResponse:(NSData*)dataXML;
- (void)responseLoginHandle:(NSDictionary*)dict;
- (void)responseChangePasswordHandle:(NSDictionary*)dict;
- (void)responseMUCHandle:(NSDictionary*)dict;
@end
// class defination
@implementation ChatConnection
@synthesize delegate;
@synthesize isChatConnectionAvailable;
NSString *usernameStr, *passwordStr;
BOOL isStreamAvailable = NO;
#pragma mark - helper methods
+ (BOOL)isNotNull:(NSString*)aString{
if ([[aString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isEqualToString:@""]
|| aString == nil || [aString length] == 0 ) {
return NO;
}
return YES;
}
#pragma mark Alert
- (void)alertTitle:(NSString*)title withMessage:(NSString*)message{
[[[UIAlertView alloc] initWithTitle:title
message:message
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles: nil] show];
}
- (void)alertTitle:(NSString*)title withMessage:(NSString*)message andDelegate:(id)delegateAlert{
[[[UIAlertView alloc] initWithTitle:title
message:message
delegate:delegateAlert
cancelButtonTitle:@"OK"
otherButtonTitles: nil] show];
}
#pragma mark - Connection Methods
+ (ChatConnection*)sharedChatConnection{
return (ChatConnection*)[(AppDelegate*)[[UIApplication sharedApplication] delegate] chatConnection];
}
- (void)connectToServerUsingStream:(NSString *)urlStr
portNo:(uint)portNo{
NSLog(@"ChatConnection:Method - (void)connectToServerUsingStream:(NSString *)urlStr portNo:(uint)portNo");
CFReadStreamRef readStream1;
CFWriteStreamRef writeStream1;
// __bridge used to convert Non ARC class to ARC class typecast
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)urlStr, portNo, &readStream1, &writeStream1);
assert(urlStr != nil);
assert( (portNo > 0) && (portNo < 65536) );
// __bridge used to convert Non ARC class to ARC class typecast
inputStream = (__bridge NSInputStream *)readStream1;
outputStream = (__bridge NSOutputStream *)writeStream1;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
if (inputStream && outputStream){
isChatConnectionAvailable = YES;
}
if (delegate && [delegate respondsToSelector:@selector(chatConnectionResponse:)]) {
[delegate chatConnectionResponse:isChatConnectionAvailable ? kConnected : kNotConnected];
}
}
- (void)disconnect{
NSLog(@"ChatConnection:Method - disconnect");
[inputStream close];
[outputStream close];
inputStream = nil;
outputStream = nil;
usernameStr = nil;
if (!inputStream && !outputStream) {
isChatConnectionAvailable = NO;
}
if (delegate && [delegate respondsToSelector:@selector(chatConnectionResponse:)]) {
[delegate chatConnectionResponse:isChatConnectionAvailable ? kConnected : kNotConnected];
}
}
- (void)writeToServer:(NSString*)stringXML{
NSLog(@"ChatConnection:Method - (void)writeToServer:(NSString*)stringXML");
NSLog(@"stringXML %@",[XMLReader dictionaryForXMLString:stringXML error:nil]);
if(outputStream) {
if(![outputStream hasSpaceAvailable]) return;
NSData *_data=[stringXML dataUsingEncoding:NSUTF8StringEncoding];
int data_len = [_data length];
uint8_t *readBytes = (uint8_t *)[_data bytes];
int byteIndex=0;
unsigned int len=0;
while (TRUE) {
len = ((data_len - byteIndex >= 40960) ? 40960 : (data_len-byteIndex));
if(len==0)
break;
uint8_t buf[len]; (void)memcpy(buf, readBytes, len);
len = [outputStream write:(const uint8_t *)buf maxLength:len];
byteIndex += len;
readBytes += len;
}
NSLog(@"ChatConnection: Sent data----------------------%@",stringXML);
}
}
#pragma mark - Server Response Understand (NSStreamDelegate)
- (void)stream:(NSStream *)stream
handleEvent:(NSStreamEvent)eventCode{
NSLog(@"ChatConnection:Method - (void)stream:(NSStream *)stream"
"handleEvent:(NSStreamEvent)eventCode");
switch(eventCode) {
case NSStreamEventHasBytesAvailable:
{
if (data == nil) {
data = [[NSMutableData alloc] init];
}
uint8_t buf[1024];
unsigned int len = 0;
len = [(NSInputStream *)stream read:buf maxLength:1024];
if(len) {
[data appendBytes:(const void *)buf length:len];
int bytesRead;
bytesRead += len;
} else {
NSLog(@"ChatConnection:No data.");
}
NSString *str = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(@"ChatConnection response: str :%@",str);
[self readServerResponse:data];
data = nil;
} break;
case NSStreamEventErrorOccurred:
{
NSLog(@"ChatConnection:An error has occurred on the stream. ");
}
break;
case NSStreamEventEndEncountered:
{
NSLog(@"ChatConnection:The end of the stream has been reached. ");
}
break;
case NSStreamEventNone:
{
NSLog(@"ChatConnection:No events occured");
}
break;
case NSStreamEventOpenCompleted :
{
NSLog(@"ChatConnection:The open has completed successfully. ");
}
break;
case NSStreamEventHasSpaceAvailable:
{
NSLog(@"ChatConnection:The stream can accept bytes for writing.");
}
break;
}
}
// --- private method
- (void)readServerResponse:(NSData*)dataXML{
NSLog(@"ChatConnection:Method - (void)readServerResponse:(NSData*)dataXML");
XMLReader *reader = [[XMLReader alloc] init];
NSDictionary *dict = [reader objectWithData:data];
NSLog(@"dict print %@",dict);
NSString *idStr = [[dict objectForKey:@"iq"] objectForKey:@"@id"];
NSLog(@"idStr %@",idStr);
//- stream handler
if ([dict objectForKey:@"stream:stream"]) {
isStreamAvailable = YES;
[self loginWithUserName:usernameStr andPassword:passwordStr];
}
//- ping handler
else if ([[dict objectForKey:@"iq"] objectForKey:@"ping"]) {
[self sendPingResponse:dict];
}
//- login handle
else if (idStr && [idStr isEqualToString:@"login_request"]) {
NSString *toServerStr = [NSString stringWithFormat:@"<iq type='set' xmlns='jabber:client' id='login'>"
"<query xmlns='jabber:iq:auth'>"
"<username>%@</username>"
"<password>%@</password>"
"<resource>iphone</resource>"
"</query></iq>"
"<presence><show>chat</show></presence>",usernameStr,passwordStr];
/**
presence http://xmpp.org/rfcs/rfc3921.html
away -- The entity or resource is temporarily away. (idle - yellow)
chat -- The entity or resource is actively interested in chatting. (available - green)
dnd -- The entity or resource is busy (dnd = "Do Not Disturb"). (busy - red)
xa -- The entity or resource is away for an extended period (xa = "eXtended Away").(idle - yellow)
demo : <presence><show>dnd</show></presence>
<presence><show>chat</show></presence> and <presence><show/></presence> are same
*/
[self writeToServer:toServerStr];
}
else if (idStr && [idStr isEqualToString:@"login"]) {
[self responseLoginHandle:dict];
}
//- change password handler
else if (idStr && [idStr isEqualToString:@"change_password"]) {
[self responseChangePasswordHandle:dict];
}
//* MUC_unlockRoomAndConfig
else if ([[[dict objectForKey:@"presence"] objectForKey:@"@id"] isEqualToString:@"MUC_create_join"]){
[self MUC_unlockRoomAndConfig:dict];
}
// MUC chat reply message handler
else if ([[[dict objectForKey:@"message"] objectForKey:@"@type"] isEqualToString:@"groupchat"]) {
[self responseMUCHandle:dict];
}
}
#pragma mark - Ping Handler
// http://xmpp.org/extensions/xep-0199.html#usecases-changepw
- (void)sendPingResponse:(NSDictionary*)dict{
[self writeToServer:[NSString stringWithFormat:@"<iq from='%@' to='%@' id='%@' type='result'/>",
[[dict objectForKey:@"iq"] objectForKey:@"@to"],
[[dict objectForKey:@"iq"] objectForKey:@"@from"],
[[dict objectForKey:@"iq"] objectForKey:@"@id"]]];
}
#pragma mark - signup
- (void)signUpWithUserName:(NSString*)userName
andPassword:(NSString*)password{
/**
http://wiki.xmpp.org/web/Programming_XMPP_Clients
* sign up : create a a/c
C: <iq type='get' id='signup_request'>
<query xmlns='jabber:iq:register'/>
</iq>
S: <iq type='result' id='signup_request'>
<query xmlns='jabber:iq:register'>
<username/>
<password/>
</query>
</iq>
C: <iq type='set' id='signup'>
<query xmlns='jabber:iq:register'>
<username>abc</username>
<password>123456</password>
</query>
</iq>
* response :
S: <iq type='result' id='signup'>
<query xmlns='jabber:iq:register'/>
</iq>
S: <iq type='error' id='signup'>
<query xmlns='jabber:iq:register'>
<username>abc</username><password>123456</password>
</query>
<error code='409'>
Username Not Available
</error>
</iq>
* using
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='signup_request'>
<iq type='get' xmlns='jabber:client'>
<query xmlns='jabber:iq:register'/> </iq>
<iq type='set' xmlns='jabber:client' id='signup'>
<query xmlns='jabber:iq:register'>
<username>abc</username>
<password>123456</password>
</query>
</iq></stream:stream>
*/
NSLog(@"ChatConnection:Method - signup ...");
// --- ERROR 409 not Handle only create here(signUp)
if ([ChatConnection isNotNull:userName] && [ChatConnection isNotNull:password]) {
NSString *toServerStr = [NSString stringWithFormat:@"%@<iq type='get' xmlns='jabber:client' id='signup_request'>"
"<query xmlns='jabber:iq:register'/> </iq>"
"<iq type='set' xmlns='jabber:client' id='signup'>"
"<query xmlns='jabber:iq:register'>"
"<username>%@</username>"
"<password>%@</password>"
"</query>"
"</iq>%@",STREAM_START,userName,password,STREAM_END];
[self writeToServer:toServerStr];
} else {
NSLog(@"ChatConnection: signUp : uName or pwd empty");
}
}
#pragma mark - Login
/**
http://wiki.xmpp.org/web/Programming_XMPP_Clients
// check that user available : login_request then login
C: <iq type='get' to='shakespeare.lit' id='login_request'>
<query xmlns='jabber:iq:auth'>
<username>abc</username>
</query>
</iq>
S: <iq type='result' id='login_request'>
<query xmlns='jabber:iq:auth'>
<username/>
<password/>
<digest/>
<resource/>
</query>
</iq>
C: <iq type='set' id='login'>
<query xmlns='jabber:iq:auth'>
<username>abc</username>
<password>123456</password>
<resource>iPhone</resource>
</query>
</iq>
* response
S: <iq type='result' id='login'/>
S: <iq type='error' id='login'>
<error code='401' type='auth'>
<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
S: <iq type='error' id='login'>
<error code='406' type='modify'>
<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
S: <iq type='error' id='login'>
<error code='409' type='cancel'>
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
* using
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>"
<iq type='get' xmlns='jabber:client' id='login_request'>
<query xmlns='jabber:iq:auth'>
<username>abc</username>
</query></iq>
<iq type='set' xmlns='jabber:client' id='login'>
<query xmlns='jabber:iq:auth'>
<username>abc</username>
<password>123456</password>
<resource>iphone</resource>
</query>
</iq>
<presence><show>chat</show></presence>
*/
- (void)loginWithUserName:(NSString*)userName
andPassword:(NSString*)password{
NSLog(@"ChatConnection:Method - login check ... :");
NSLog(@"- (void)loginWithUserName:(NSString*)uName andPassword:(NSString*)pwd");
if ([ChatConnection isNotNull:userName] && [ChatConnection isNotNull:password]) {
usernameStr = userName;
passwordStr = password;
if (!isStreamAvailable){
[self writeToServer:STREAM_START];
return;
}
NSString *toServerStr = [NSString stringWithFormat:@"<iq type='get' xmlns='jabber:client' id='login_request'>"
"<query xmlns='jabber:iq:auth'>"
"<username>%@</username>"
"</query></iq>",userName];
// "<iq type='set' xmlns='jabber:client' id='login'>"
// "<query xmlns='jabber:iq:auth'>"
// "<username>%@</username>"
// "<password>%@</password>"
// "<resource>iphone</resource>"
// "</query></iq>"
// "<presence><show>chat</show></presence>",STREAM_START,userName, userName,password];
/**
presence http://xmpp.org/rfcs/rfc3921.html
away -- The entity or resource is temporarily away. (idle - yellow)
chat -- The entity or resource is actively interested in chatting. (available - green)
dnd -- The entity or resource is busy (dnd = "Do Not Disturb"). (busy - red)
xa -- The entity or resource is away for an extended period (xa = "eXtended Away").(idle - yellow)
demo : <presence><show>dnd</show></presence>
<presence><show>chat</show></presence> and <presence><show/></presence> are same
*/
[self writeToServer:toServerStr];
} else {
NSLog(@"ChatConnection: login : uName or pwd empty");
}
}
// --- private method
- (void)responseLoginHandle:(NSDictionary*)dict{
NSLog(@"ChatConnection:Method - (void)responseLoginHandle:(NSDictionary*)dict");
if ([[[dict objectForKey:@"iq"] objectForKey:@"@type"] isEqualToString:@"error"])
{
int errorResponseCode = [[[[dict objectForKey:@"iq"] objectForKey:@"error"] objectForKey:@"@code"] intValue];
switch (errorResponseCode) {
case 401: // not-authorized
{
[self alertTitle:@"Error !" withMessage:@"Username/password Incorrect"];
}
break;
case 406: // not-acceptable
{
[self alertTitle:@"Error !" withMessage:@"not-acceptable"];
}
break;
case 409: // conflict
{
[self alertTitle:@"Error !" withMessage:@"conflict"];
}
break;
default:
NSLog(@"not recognized error, error code:%d",errorResponseCode);
break;
}
usernameStr = nil;
if (delegate && [delegate respondsToSelector:@selector(chatLoginResponse:)]) {
[delegate chatLoginResponse:kLoginFail];
}
}
else
{
NSLog(@"successfull login");
if (delegate && [delegate respondsToSelector:@selector(chatLoginResponse:)]) {
[delegate chatLoginResponse:kLoginSuccess];
}
}
}
#pragma mark - change password
/**
http://xmpp.org/extensions/xep-0077.html#usecases-changepw
// chance password
C: <iq type='set' to='shakespeare.lit' id='change_password'>
<query xmlns='jabber:iq:register'>
<username>abc</username>
<password>newpass</password>
</query>
</iq>
* response
S: <iq type='result' id='change_password'/>
S: <iq type='error' from='shakespeare.lit' to='bill@shakespeare.lit/globe' id='change_password'>
<error code='400' type='modify'>
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
S: <iq type='error' from='shakespeare.lit' to='bill@shakespeare.lit/globe' id='change_password'>
<error code='401' type='modify'>
<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
S: <iq type='error' from='shakespeare.lit' to='bill@shakespeare.lit/globe' id='change_password'>
<error code='405' type='cancel'>
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
* using
<iq type='set' xmlns='jabber:client' id='change_password'>
<query xmlns='jabber:iq:register'>
<username>abc</username>
<password>newPassword</password>
</query></iq>
*/
- (void)changePasswordWithUserName:(NSString*)userName
andPassword:(NSString*)password{
NSLog(@"ChatConnection:Method - change password:");
NSLog(@"- (void)changePasswordWithUserName:(NSString*)uName andPassword:(NSString*)pwd");
if (!userName) {
userName = usernameStr;
}
if ([ChatConnection isNotNull:userName] && [ChatConnection isNotNull:password]) {
NSString *toServerStr = [NSString stringWithFormat:@"<iq type='set' xmlns='jabber:client' id='change_password'>"
"<query xmlns='jabber:iq:register'>"
"<username>%@</username>"
"<password>%@</password>"
"</query></iq>",userName,password];
[self writeToServer:toServerStr];
} else {
NSLog(@"ChatConnection: changePassword : uName or pwd empty");
}
}
// --- private method
- (void)responseChangePasswordHandle:(NSDictionary*)dict{
NSLog(@"ChatConnection:Method - (void)responseChangePasswordHandle:(NSDictionary*)dict");
if ([[[dict objectForKey:@"iq"] objectForKey:@"@type"] isEqualToString:@"error"])
{
int errorResponseCode = [[[[dict objectForKey:@"iq"] objectForKey:@"error"] objectForKey:@"@code"] intValue];
switch (errorResponseCode) {
case 400:// bad-request
{
[self alertTitle:@"Error !" withMessage:@"bad-request"];
}
break;
case 401: // not-authorized
{
[self alertTitle:@"Error !" withMessage:@"Username Incorrect"];
}
break;
case 405: // not-allowed
{
[self alertTitle:@"Error !" withMessage:@"not-allowed"];
}
break;
default:
NSLog(@"not recognized error, error code:%d",errorResponseCode);
break;
}
}
else
{
NSLog(@"successfull password change");
}
}
#pragma mark - Multi User Chat Room
/**
// http://xmpp.org/extensions/xep-0045.html
// --- Create or Join a room
<presence to='roomName@conference.gauravs-mac.local/abc'>
<x xmlns='http://jabber.org/protocol/muc'/>
</presence>
// --- Unlock room and set set configuration file
<iq type='set' from='abc@gauravs-mac.local/iphone' id='muc_config' to='roomName@conference.gauravs-mac.local'>
<query xmlns='http://jabber.org/protocol/muc#owner'>
<feature var="http://jabber.org/protocol/muc"/>
<feature var="muc_public"/>
<feature var="muc_persistent"/>
<feature var="muc_open"/>
<x xmlns='jabber:x:data' type='submit'/>
</query></iq>
// --- leave room
<presence type='unavailable' to='darkcave@chat.shakespeare.lit/thirdwitch'/>
// --- Send message on room
<message from='abc@gauravs-mac.local/iphone' id='msgID' to='roomName@conference.gauravs-mac.local' type='groupchat'>
<body>Message write here.</body></message>
*/
- (void)MUC_createOrJoinRoom:(NSString*)chatRoomName
andUsername:(NSString*)userName{
NSLog(@"ChatConnection:Method -");
NSLog(@"- (void)MUC_createOrJoinRoom:(NSString*)chatRoomName andUsername:(NSString*)userName");
if (!userName) {
userName = usernameStr;
}
if ([ChatConnection isNotNull:chatRoomName] && [ChatConnection isNotNull:userName]) {
chatRoomName = [chatRoomName stringByReplacingOccurrencesOfString:@" " withString:@"_"];
NSString *toServerStr = [NSString stringWithFormat:@"<presence to='%@@conference.%@/%@' id='MUC_create_join'>"
"<x xmlns='http://jabber.org/protocol/muc'/></presence>",
chatRoomName,SERVER_NAME,userName];
[self writeToServer:toServerStr];
} else {
NSLog(@"ChatConnection: MUC_createOrJoinRoom:andUsername: chatRoomName or userName empty");
}
}
- (void)MUC_unlockRoomAndConfig:(NSDictionary*)dict{
NSLog(@"ChatConnection:Method - ");
NSLog(@"- (void)MUC_unlockRoomAndConfig");
if (dict) {
NSLog(@"dict %@",dict);
NSString *toServerStr = [NSString stringWithFormat:@"<iq type='set' from='%@' to='%@' id='muc_config'>"
"<query xmlns='http://jabber.org/protocol/muc#owner'>"
// "<feature var='http://jabber.org/protocol/muc' />"
// "<feature var='muc_public' />"
// "<feature var='muc_persistent' />"
// "<feature var='muc_open' />"
"<x xmlns='jabber:x:data' type='submit'/></query></iq>",
[[dict objectForKey:@"presence"] objectForKey:@"@to"],
[[dict objectForKey:@"presence"] objectForKey:@"@from"]];
[self writeToServer:toServerStr];
} else {
NSLog(@"ChatConnection: MUC_unlockRoomAndConfig : dict empty");
}
}
- (void)MUC_leaveChatRoomName:(NSString*)chatRoomName
andUsername:(NSString*)userName{
NSLog(@"ChatConnection:Method - ");
NSLog(@"- (void)MUC_leaveChatRoomName:(NSString*)chatRoomName andUsername:(NSString*)userName");
if (!userName) {
userName = usernameStr;
}
if ([ChatConnection isNotNull:chatRoomName] && [ChatConnection isNotNull:userName]) {
chatRoomName = [chatRoomName stringByReplacingOccurrencesOfString:@" " withString:@"_"];
NSString *toServerStr = [NSString stringWithFormat:@"<presence type='unavailable' to='%@@conference.%@/%@'/>",
chatRoomName,SERVER_NAME,userName];
[self writeToServer:toServerStr];
} else {
NSLog(@"ChatConnection: MUC_leaveChatRoomName:andUsername: chatRoomName or userName empty");
}
}
- (void)MUC_chatOnChatRoomName:(NSString*)chatRoomName
andMessage:(NSString*)messageStr{
NSLog(@"ChatConnection:Method -");
NSLog(@"- (void)MUC_chatOnChatRoomName:(NSString*)chatRoomName andMessage:(NSString*)messageStr");
if ([ChatConnection isNotNull:chatRoomName] && [ChatConnection isNotNull:messageStr]) {
chatRoomName = [chatRoomName stringByReplacingOccurrencesOfString:@" " withString:@"_"];
NSString *toServerStr = [NSString stringWithFormat:@"<message id='MUC_chat' to='%@@conference.%@' type='groupchat'>"
"<body>%@</body></message>",chatRoomName,SERVER_NAME,messageStr];
[self writeToServer:toServerStr];
} else {
NSLog(@"ChatConnection: MUC_chatOnChatRoomName:andMessage: chatRoomName or messageStr empty");
}
}
- (void)responseMUCHandle:(NSDictionary*)dict{
// XMPP server response understand and then repond to delegate
NSLog(@"ChatConnection :: - (void)responseMUCHandle:(NSDictionary*)dict");
if (dict) {
if ([dict objectForKey:@"message"]) {
NSDictionary *dictMsg = [dict objectForKey:@"message"];
NSString *from = [dictMsg objectForKey:@"@from"] ;
from = [[from substringFromIndex:([from rangeOfString:@"/"
options:NSBackwardsSearch].location)+1]
stringByRemovingNewLinesAndWhitespace];
NSString *body = [dictMsg objectForKey:@"body"];
if (from && body){
NSDictionary *dictResponse = [[NSDictionary alloc] initWithObjectsAndKeys:from,@"from",body,@"message", nil];
if (delegate && [delegate respondsToSelector:@selector(chatMUCMessageReceiveResponse:)]) {
[delegate chatMUCMessageReceiveResponse:dictResponse];
}
else {
NSLog(@"delegate is empty or not response to selector");
}
}
else{
NSLog(@"from name or body empty response");
}
}
}
else{
NSLog(@"dict empty");
}
}
#pragma mark - Single User Chat
//<message type="chat" to="gaurav@gauravs-mac.local/spark"><body>hello gaurav</body></message>
- (void)SUC_chatWithMessage:(NSString*)messageStr
toUser:(NSString*)toUser{
NSLog(@"ChatConnection:Method -");
NSLog(@"- (void)SUC_chatWithMessage:fromUser:toUser:");
if ([ChatConnection isNotNull:messageStr] &&
[ChatConnection isNotNull:toUser]
) {
NSString *toServerStr = [NSString stringWithFormat:@"<message type='chat' to='%@@%@/iphone'><body>%@</body></message>",toUser,SERVER_NAME,messageStr];
[self writeToServer:toServerStr];
} else {
NSLog(@"ChatConnection: MUC_chatOnChatRoomName:andMessage: chatRoomName or messageStr empty");
}
}
@end
// ChatConnection.h
// ChatModule
//
// Created by Gaurav & Piyush on 27/06/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
// Ref: http://wiki.xmpp.org/web/Programming_XMPP_Clients
// http://xmpp.org/xmpp-protocols/xmpp-extensions/
// http://gauravds.blogspot.in/2012/06/nsstring-str-xmlnsjabberclient.html
#import <Foundation/Foundation.h>
#pragma mark - Chat Delegate Protocol
// a protocol
@protocol ChatDelegate <NSObject>
typedef enum ConnectionResponse{
kConnected,
kNotConnected
}ConnectionResponse;
@optional
- (void)chatConnectionResponse:(ConnectionResponse)connectionResponse;
typedef enum LoginResponse{
kLoginSuccess,
kLoginFail
}LoginResponse;
@optional
- (void)chatLoginResponse:(LoginResponse)loginResponse;
typedef enum MUCResponse{
kMUCJoinSuccess,
kMUCJoinFail,
kMUCLeaveSuccess,
kMUCLeaveFail,
kMUCMessageSendSuccess,
kMUCMessageSendFail
}MUCResponse;
@optional
- (void)chatMUCResponse:(MUCResponse)MUC_Response;
@optional
- (void)chatMUCMessageReceiveResponse:(NSDictionary*)receiveResponse;
@end
#pragma mark - Chat Connection Class
// class declaration
@interface ChatConnection : NSObject <NSStreamDelegate>
{
NSMutableData *data;
NSInputStream *inputStream;
NSOutputStream *outputStream;
CFReadStreamRef readStream ;
CFWriteStreamRef writeStream;
}
@property (nonatomic, strong) id<ChatDelegate> delegate;
@property (nonatomic, readonly) BOOL isChatConnectionAvailable;
#pragma mark connection methods
// --- singleton refernce
+ (ChatConnection*)sharedChatConnection;
// --- some connection methods
- (void)connectToServerUsingStream:(NSString *)urlStr
portNo:(uint)portNo;
- (void)disconnect;
- (void)writeToServer:(NSString*)stringXML;
- (void)stream:(NSStream *)stream
handleEvent:(NSStreamEvent)eventCode;
#pragma mark login signup chagne password methods
// --- some user Need methods
- (void)signUpWithUserName:(NSString*)userName
andPassword:(NSString*)password;
- (void)loginWithUserName:(NSString*)userName
andPassword:(NSString*)password;
- (void)changePasswordWithUserName:(NSString*)userName
andPassword:(NSString*)password;
#pragma mark Multi User Chat
// --- Multi user Chat methods
- (void)MUC_createOrJoinRoom:(NSString*)chatRoomName
andUsername:(NSString*)userName;
- (void)MUC_unlockRoomAndConfig:(NSDictionary*)dict;
- (void)MUC_leaveChatRoomName:(NSString*)chatRoomName
andUsername:(NSString*)userName;
- (void)MUC_chatOnChatRoomName:(NSString*)chatRoomName
andMessage:(NSString*)messageStr;
#pragma mark Single User Chat
// --- Single user chat methods
- (void)SUC_chatWithMessage:(NSString*)messageStr
toUser:(NSString*)toUser;
@end
--------------------------------------------------------------------------------------------
//
// ChatConnection.m
// ChatModule
//
// Created by Gaurav & Piyush on 27/06/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "ChatConnection.h"
#import "AppDelegate.h"
#import "XMLReader.h"
#define STREAM_START @"<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>"
#define STREAM_END @"</stream:stream>"
#define SERVER_NAME @"openfire"
#define RESOURCE_NAME @"iphone"
// private methods
@interface ChatConnection (privateMethods)
+ (BOOL)isNotNull:(NSString*)aString;
- (void)alertTitle:(NSString*)title withMessage:(NSString*)message;
- (void)alertTitle:(NSString*)title withMessage:(NSString*)message andDelegate:(id)delegateAlert;
- (void)sendPingResponse:(NSDictionary*)dict;
- (void)readServerResponse:(NSData*)dataXML;
- (void)responseLoginHandle:(NSDictionary*)dict;
- (void)responseChangePasswordHandle:(NSDictionary*)dict;
- (void)responseMUCHandle:(NSDictionary*)dict;
@end
// class defination
@implementation ChatConnection
@synthesize delegate;
@synthesize isChatConnectionAvailable;
NSString *usernameStr, *passwordStr;
BOOL isStreamAvailable = NO;
#pragma mark - helper methods
+ (BOOL)isNotNull:(NSString*)aString{
if ([[aString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isEqualToString:@""]
|| aString == nil || [aString length] == 0 ) {
return NO;
}
return YES;
}
#pragma mark Alert
- (void)alertTitle:(NSString*)title withMessage:(NSString*)message{
[[[UIAlertView alloc] initWithTitle:title
message:message
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles: nil] show];
}
- (void)alertTitle:(NSString*)title withMessage:(NSString*)message andDelegate:(id)delegateAlert{
[[[UIAlertView alloc] initWithTitle:title
message:message
delegate:delegateAlert
cancelButtonTitle:@"OK"
otherButtonTitles: nil] show];
}
#pragma mark - Connection Methods
+ (ChatConnection*)sharedChatConnection{
return (ChatConnection*)[(AppDelegate*)[[UIApplication sharedApplication] delegate] chatConnection];
}
- (void)connectToServerUsingStream:(NSString *)urlStr
portNo:(uint)portNo{
NSLog(@"ChatConnection:Method - (void)connectToServerUsingStream:(NSString *)urlStr portNo:(uint)portNo");
CFReadStreamRef readStream1;
CFWriteStreamRef writeStream1;
// __bridge used to convert Non ARC class to ARC class typecast
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)urlStr, portNo, &readStream1, &writeStream1);
assert(urlStr != nil);
assert( (portNo > 0) && (portNo < 65536) );
// __bridge used to convert Non ARC class to ARC class typecast
inputStream = (__bridge NSInputStream *)readStream1;
outputStream = (__bridge NSOutputStream *)writeStream1;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
if (inputStream && outputStream){
isChatConnectionAvailable = YES;
}
if (delegate && [delegate respondsToSelector:@selector(chatConnectionResponse:)]) {
[delegate chatConnectionResponse:isChatConnectionAvailable ? kConnected : kNotConnected];
}
}
- (void)disconnect{
NSLog(@"ChatConnection:Method - disconnect");
[inputStream close];
[outputStream close];
inputStream = nil;
outputStream = nil;
usernameStr = nil;
if (!inputStream && !outputStream) {
isChatConnectionAvailable = NO;
}
if (delegate && [delegate respondsToSelector:@selector(chatConnectionResponse:)]) {
[delegate chatConnectionResponse:isChatConnectionAvailable ? kConnected : kNotConnected];
}
}
- (void)writeToServer:(NSString*)stringXML{
NSLog(@"ChatConnection:Method - (void)writeToServer:(NSString*)stringXML");
NSLog(@"stringXML %@",[XMLReader dictionaryForXMLString:stringXML error:nil]);
if(outputStream) {
if(![outputStream hasSpaceAvailable]) return;
NSData *_data=[stringXML dataUsingEncoding:NSUTF8StringEncoding];
int data_len = [_data length];
uint8_t *readBytes = (uint8_t *)[_data bytes];
int byteIndex=0;
unsigned int len=0;
while (TRUE) {
len = ((data_len - byteIndex >= 40960) ? 40960 : (data_len-byteIndex));
if(len==0)
break;
uint8_t buf[len]; (void)memcpy(buf, readBytes, len);
len = [outputStream write:(const uint8_t *)buf maxLength:len];
byteIndex += len;
readBytes += len;
}
NSLog(@"ChatConnection: Sent data----------------------%@",stringXML);
}
}
#pragma mark - Server Response Understand (NSStreamDelegate)
- (void)stream:(NSStream *)stream
handleEvent:(NSStreamEvent)eventCode{
NSLog(@"ChatConnection:Method - (void)stream:(NSStream *)stream"
"handleEvent:(NSStreamEvent)eventCode");
switch(eventCode) {
case NSStreamEventHasBytesAvailable:
{
if (data == nil) {
data = [[NSMutableData alloc] init];
}
uint8_t buf[1024];
unsigned int len = 0;
len = [(NSInputStream *)stream read:buf maxLength:1024];
if(len) {
[data appendBytes:(const void *)buf length:len];
int bytesRead;
bytesRead += len;
} else {
NSLog(@"ChatConnection:No data.");
}
NSString *str = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(@"ChatConnection response: str :%@",str);
[self readServerResponse:data];
data = nil;
} break;
case NSStreamEventErrorOccurred:
{
NSLog(@"ChatConnection:An error has occurred on the stream. ");
}
break;
case NSStreamEventEndEncountered:
{
NSLog(@"ChatConnection:The end of the stream has been reached. ");
}
break;
case NSStreamEventNone:
{
NSLog(@"ChatConnection:No events occured");
}
break;
case NSStreamEventOpenCompleted :
{
NSLog(@"ChatConnection:The open has completed successfully. ");
}
break;
case NSStreamEventHasSpaceAvailable:
{
NSLog(@"ChatConnection:The stream can accept bytes for writing.");
}
break;
}
}
// --- private method
- (void)readServerResponse:(NSData*)dataXML{
NSLog(@"ChatConnection:Method - (void)readServerResponse:(NSData*)dataXML");
XMLReader *reader = [[XMLReader alloc] init];
NSDictionary *dict = [reader objectWithData:data];
NSLog(@"dict print %@",dict);
NSString *idStr = [[dict objectForKey:@"iq"] objectForKey:@"@id"];
NSLog(@"idStr %@",idStr);
//- stream handler
if ([dict objectForKey:@"stream:stream"]) {
isStreamAvailable = YES;
[self loginWithUserName:usernameStr andPassword:passwordStr];
}
//- ping handler
else if ([[dict objectForKey:@"iq"] objectForKey:@"ping"]) {
[self sendPingResponse:dict];
}
//- login handle
else if (idStr && [idStr isEqualToString:@"login_request"]) {
NSString *toServerStr = [NSString stringWithFormat:@"<iq type='set' xmlns='jabber:client' id='login'>"
"<query xmlns='jabber:iq:auth'>"
"<username>%@</username>"
"<password>%@</password>"
"<resource>iphone</resource>"
"</query></iq>"
"<presence><show>chat</show></presence>",usernameStr,passwordStr];
/**
presence http://xmpp.org/rfcs/rfc3921.html
away -- The entity or resource is temporarily away. (idle - yellow)
chat -- The entity or resource is actively interested in chatting. (available - green)
dnd -- The entity or resource is busy (dnd = "Do Not Disturb"). (busy - red)
xa -- The entity or resource is away for an extended period (xa = "eXtended Away").(idle - yellow)
demo : <presence><show>dnd</show></presence>
<presence><show>chat</show></presence> and <presence><show/></presence> are same
*/
[self writeToServer:toServerStr];
}
else if (idStr && [idStr isEqualToString:@"login"]) {
[self responseLoginHandle:dict];
}
//- change password handler
else if (idStr && [idStr isEqualToString:@"change_password"]) {
[self responseChangePasswordHandle:dict];
}
//* MUC_unlockRoomAndConfig
else if ([[[dict objectForKey:@"presence"] objectForKey:@"@id"] isEqualToString:@"MUC_create_join"]){
[self MUC_unlockRoomAndConfig:dict];
}
// MUC chat reply message handler
else if ([[[dict objectForKey:@"message"] objectForKey:@"@type"] isEqualToString:@"groupchat"]) {
[self responseMUCHandle:dict];
}
}
#pragma mark - Ping Handler
// http://xmpp.org/extensions/xep-0199.html#usecases-changepw
- (void)sendPingResponse:(NSDictionary*)dict{
[self writeToServer:[NSString stringWithFormat:@"<iq from='%@' to='%@' id='%@' type='result'/>",
[[dict objectForKey:@"iq"] objectForKey:@"@to"],
[[dict objectForKey:@"iq"] objectForKey:@"@from"],
[[dict objectForKey:@"iq"] objectForKey:@"@id"]]];
}
#pragma mark - signup
- (void)signUpWithUserName:(NSString*)userName
andPassword:(NSString*)password{
/**
http://wiki.xmpp.org/web/Programming_XMPP_Clients
* sign up : create a a/c
C: <iq type='get' id='signup_request'>
<query xmlns='jabber:iq:register'/>
</iq>
S: <iq type='result' id='signup_request'>
<query xmlns='jabber:iq:register'>
<username/>
<password/>
</query>
</iq>
C: <iq type='set' id='signup'>
<query xmlns='jabber:iq:register'>
<username>abc</username>
<password>123456</password>
</query>
</iq>
* response :
S: <iq type='result' id='signup'>
<query xmlns='jabber:iq:register'/>
</iq>
S: <iq type='error' id='signup'>
<query xmlns='jabber:iq:register'>
<username>abc</username><password>123456</password>
</query>
<error code='409'>
Username Not Available
</error>
</iq>
* using
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='signup_request'>
<iq type='get' xmlns='jabber:client'>
<query xmlns='jabber:iq:register'/> </iq>
<iq type='set' xmlns='jabber:client' id='signup'>
<query xmlns='jabber:iq:register'>
<username>abc</username>
<password>123456</password>
</query>
</iq></stream:stream>
*/
NSLog(@"ChatConnection:Method - signup ...");
// --- ERROR 409 not Handle only create here(signUp)
if ([ChatConnection isNotNull:userName] && [ChatConnection isNotNull:password]) {
NSString *toServerStr = [NSString stringWithFormat:@"%@<iq type='get' xmlns='jabber:client' id='signup_request'>"
"<query xmlns='jabber:iq:register'/> </iq>"
"<iq type='set' xmlns='jabber:client' id='signup'>"
"<query xmlns='jabber:iq:register'>"
"<username>%@</username>"
"<password>%@</password>"
"</query>"
"</iq>%@",STREAM_START,userName,password,STREAM_END];
[self writeToServer:toServerStr];
} else {
NSLog(@"ChatConnection: signUp : uName or pwd empty");
}
}
#pragma mark - Login
/**
http://wiki.xmpp.org/web/Programming_XMPP_Clients
// check that user available : login_request then login
C: <iq type='get' to='shakespeare.lit' id='login_request'>
<query xmlns='jabber:iq:auth'>
<username>abc</username>
</query>
</iq>
S: <iq type='result' id='login_request'>
<query xmlns='jabber:iq:auth'>
<username/>
<password/>
<digest/>
<resource/>
</query>
</iq>
C: <iq type='set' id='login'>
<query xmlns='jabber:iq:auth'>
<username>abc</username>
<password>123456</password>
<resource>iPhone</resource>
</query>
</iq>
* response
S: <iq type='result' id='login'/>
S: <iq type='error' id='login'>
<error code='401' type='auth'>
<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
S: <iq type='error' id='login'>
<error code='406' type='modify'>
<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
S: <iq type='error' id='login'>
<error code='409' type='cancel'>
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
* using
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>"
<iq type='get' xmlns='jabber:client' id='login_request'>
<query xmlns='jabber:iq:auth'>
<username>abc</username>
</query></iq>
<iq type='set' xmlns='jabber:client' id='login'>
<query xmlns='jabber:iq:auth'>
<username>abc</username>
<password>123456</password>
<resource>iphone</resource>
</query>
</iq>
<presence><show>chat</show></presence>
*/
- (void)loginWithUserName:(NSString*)userName
andPassword:(NSString*)password{
NSLog(@"ChatConnection:Method - login check ... :");
NSLog(@"- (void)loginWithUserName:(NSString*)uName andPassword:(NSString*)pwd");
if ([ChatConnection isNotNull:userName] && [ChatConnection isNotNull:password]) {
usernameStr = userName;
passwordStr = password;
if (!isStreamAvailable){
[self writeToServer:STREAM_START];
return;
}
NSString *toServerStr = [NSString stringWithFormat:@"<iq type='get' xmlns='jabber:client' id='login_request'>"
"<query xmlns='jabber:iq:auth'>"
"<username>%@</username>"
"</query></iq>",userName];
// "<iq type='set' xmlns='jabber:client' id='login'>"
// "<query xmlns='jabber:iq:auth'>"
// "<username>%@</username>"
// "<password>%@</password>"
// "<resource>iphone</resource>"
// "</query></iq>"
// "<presence><show>chat</show></presence>",STREAM_START,userName, userName,password];
/**
presence http://xmpp.org/rfcs/rfc3921.html
away -- The entity or resource is temporarily away. (idle - yellow)
chat -- The entity or resource is actively interested in chatting. (available - green)
dnd -- The entity or resource is busy (dnd = "Do Not Disturb"). (busy - red)
xa -- The entity or resource is away for an extended period (xa = "eXtended Away").(idle - yellow)
demo : <presence><show>dnd</show></presence>
<presence><show>chat</show></presence> and <presence><show/></presence> are same
*/
[self writeToServer:toServerStr];
} else {
NSLog(@"ChatConnection: login : uName or pwd empty");
}
}
// --- private method
- (void)responseLoginHandle:(NSDictionary*)dict{
NSLog(@"ChatConnection:Method - (void)responseLoginHandle:(NSDictionary*)dict");
if ([[[dict objectForKey:@"iq"] objectForKey:@"@type"] isEqualToString:@"error"])
{
int errorResponseCode = [[[[dict objectForKey:@"iq"] objectForKey:@"error"] objectForKey:@"@code"] intValue];
switch (errorResponseCode) {
case 401: // not-authorized
{
[self alertTitle:@"Error !" withMessage:@"Username/password Incorrect"];
}
break;
case 406: // not-acceptable
{
[self alertTitle:@"Error !" withMessage:@"not-acceptable"];
}
break;
case 409: // conflict
{
[self alertTitle:@"Error !" withMessage:@"conflict"];
}
break;
default:
NSLog(@"not recognized error, error code:%d",errorResponseCode);
break;
}
usernameStr = nil;
if (delegate && [delegate respondsToSelector:@selector(chatLoginResponse:)]) {
[delegate chatLoginResponse:kLoginFail];
}
}
else
{
NSLog(@"successfull login");
if (delegate && [delegate respondsToSelector:@selector(chatLoginResponse:)]) {
[delegate chatLoginResponse:kLoginSuccess];
}
}
}
#pragma mark - change password
/**
http://xmpp.org/extensions/xep-0077.html#usecases-changepw
// chance password
C: <iq type='set' to='shakespeare.lit' id='change_password'>
<query xmlns='jabber:iq:register'>
<username>abc</username>
<password>newpass</password>
</query>
</iq>
* response
S: <iq type='result' id='change_password'/>
S: <iq type='error' from='shakespeare.lit' to='bill@shakespeare.lit/globe' id='change_password'>
<error code='400' type='modify'>
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
S: <iq type='error' from='shakespeare.lit' to='bill@shakespeare.lit/globe' id='change_password'>
<error code='401' type='modify'>
<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
S: <iq type='error' from='shakespeare.lit' to='bill@shakespeare.lit/globe' id='change_password'>
<error code='405' type='cancel'>
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
* using
<iq type='set' xmlns='jabber:client' id='change_password'>
<query xmlns='jabber:iq:register'>
<username>abc</username>
<password>newPassword</password>
</query></iq>
*/
- (void)changePasswordWithUserName:(NSString*)userName
andPassword:(NSString*)password{
NSLog(@"ChatConnection:Method - change password:");
NSLog(@"- (void)changePasswordWithUserName:(NSString*)uName andPassword:(NSString*)pwd");
if (!userName) {
userName = usernameStr;
}
if ([ChatConnection isNotNull:userName] && [ChatConnection isNotNull:password]) {
NSString *toServerStr = [NSString stringWithFormat:@"<iq type='set' xmlns='jabber:client' id='change_password'>"
"<query xmlns='jabber:iq:register'>"
"<username>%@</username>"
"<password>%@</password>"
"</query></iq>",userName,password];
[self writeToServer:toServerStr];
} else {
NSLog(@"ChatConnection: changePassword : uName or pwd empty");
}
}
// --- private method
- (void)responseChangePasswordHandle:(NSDictionary*)dict{
NSLog(@"ChatConnection:Method - (void)responseChangePasswordHandle:(NSDictionary*)dict");
if ([[[dict objectForKey:@"iq"] objectForKey:@"@type"] isEqualToString:@"error"])
{
int errorResponseCode = [[[[dict objectForKey:@"iq"] objectForKey:@"error"] objectForKey:@"@code"] intValue];
switch (errorResponseCode) {
case 400:// bad-request
{
[self alertTitle:@"Error !" withMessage:@"bad-request"];
}
break;
case 401: // not-authorized
{
[self alertTitle:@"Error !" withMessage:@"Username Incorrect"];
}
break;
case 405: // not-allowed
{
[self alertTitle:@"Error !" withMessage:@"not-allowed"];
}
break;
default:
NSLog(@"not recognized error, error code:%d",errorResponseCode);
break;
}
}
else
{
NSLog(@"successfull password change");
}
}
#pragma mark - Multi User Chat Room
/**
// http://xmpp.org/extensions/xep-0045.html
// --- Create or Join a room
<presence to='roomName@conference.gauravs-mac.local/abc'>
<x xmlns='http://jabber.org/protocol/muc'/>
</presence>
// --- Unlock room and set set configuration file
<iq type='set' from='abc@gauravs-mac.local/iphone' id='muc_config' to='roomName@conference.gauravs-mac.local'>
<query xmlns='http://jabber.org/protocol/muc#owner'>
<feature var="http://jabber.org/protocol/muc"/>
<feature var="muc_public"/>
<feature var="muc_persistent"/>
<feature var="muc_open"/>
<x xmlns='jabber:x:data' type='submit'/>
</query></iq>
// --- leave room
<presence type='unavailable' to='darkcave@chat.shakespeare.lit/thirdwitch'/>
// --- Send message on room
<message from='abc@gauravs-mac.local/iphone' id='msgID' to='roomName@conference.gauravs-mac.local' type='groupchat'>
<body>Message write here.</body></message>
*/
- (void)MUC_createOrJoinRoom:(NSString*)chatRoomName
andUsername:(NSString*)userName{
NSLog(@"ChatConnection:Method -");
NSLog(@"- (void)MUC_createOrJoinRoom:(NSString*)chatRoomName andUsername:(NSString*)userName");
if (!userName) {
userName = usernameStr;
}
if ([ChatConnection isNotNull:chatRoomName] && [ChatConnection isNotNull:userName]) {
chatRoomName = [chatRoomName stringByReplacingOccurrencesOfString:@" " withString:@"_"];
NSString *toServerStr = [NSString stringWithFormat:@"<presence to='%@@conference.%@/%@' id='MUC_create_join'>"
"<x xmlns='http://jabber.org/protocol/muc'/></presence>",
chatRoomName,SERVER_NAME,userName];
[self writeToServer:toServerStr];
} else {
NSLog(@"ChatConnection: MUC_createOrJoinRoom:andUsername: chatRoomName or userName empty");
}
}
- (void)MUC_unlockRoomAndConfig:(NSDictionary*)dict{
NSLog(@"ChatConnection:Method - ");
NSLog(@"- (void)MUC_unlockRoomAndConfig");
if (dict) {
NSLog(@"dict %@",dict);
NSString *toServerStr = [NSString stringWithFormat:@"<iq type='set' from='%@' to='%@' id='muc_config'>"
"<query xmlns='http://jabber.org/protocol/muc#owner'>"
// "<feature var='http://jabber.org/protocol/muc' />"
// "<feature var='muc_public' />"
// "<feature var='muc_persistent' />"
// "<feature var='muc_open' />"
"<x xmlns='jabber:x:data' type='submit'/></query></iq>",
[[dict objectForKey:@"presence"] objectForKey:@"@to"],
[[dict objectForKey:@"presence"] objectForKey:@"@from"]];
[self writeToServer:toServerStr];
} else {
NSLog(@"ChatConnection: MUC_unlockRoomAndConfig : dict empty");
}
}
- (void)MUC_leaveChatRoomName:(NSString*)chatRoomName
andUsername:(NSString*)userName{
NSLog(@"ChatConnection:Method - ");
NSLog(@"- (void)MUC_leaveChatRoomName:(NSString*)chatRoomName andUsername:(NSString*)userName");
if (!userName) {
userName = usernameStr;
}
if ([ChatConnection isNotNull:chatRoomName] && [ChatConnection isNotNull:userName]) {
chatRoomName = [chatRoomName stringByReplacingOccurrencesOfString:@" " withString:@"_"];
NSString *toServerStr = [NSString stringWithFormat:@"<presence type='unavailable' to='%@@conference.%@/%@'/>",
chatRoomName,SERVER_NAME,userName];
[self writeToServer:toServerStr];
} else {
NSLog(@"ChatConnection: MUC_leaveChatRoomName:andUsername: chatRoomName or userName empty");
}
}
- (void)MUC_chatOnChatRoomName:(NSString*)chatRoomName
andMessage:(NSString*)messageStr{
NSLog(@"ChatConnection:Method -");
NSLog(@"- (void)MUC_chatOnChatRoomName:(NSString*)chatRoomName andMessage:(NSString*)messageStr");
if ([ChatConnection isNotNull:chatRoomName] && [ChatConnection isNotNull:messageStr]) {
chatRoomName = [chatRoomName stringByReplacingOccurrencesOfString:@" " withString:@"_"];
NSString *toServerStr = [NSString stringWithFormat:@"<message id='MUC_chat' to='%@@conference.%@' type='groupchat'>"
"<body>%@</body></message>",chatRoomName,SERVER_NAME,messageStr];
[self writeToServer:toServerStr];
} else {
NSLog(@"ChatConnection: MUC_chatOnChatRoomName:andMessage: chatRoomName or messageStr empty");
}
}
- (void)responseMUCHandle:(NSDictionary*)dict{
// XMPP server response understand and then repond to delegate
NSLog(@"ChatConnection :: - (void)responseMUCHandle:(NSDictionary*)dict");
if (dict) {
if ([dict objectForKey:@"message"]) {
NSDictionary *dictMsg = [dict objectForKey:@"message"];
NSString *from = [dictMsg objectForKey:@"@from"] ;
from = [[from substringFromIndex:([from rangeOfString:@"/"
options:NSBackwardsSearch].location)+1]
stringByRemovingNewLinesAndWhitespace];
NSString *body = [dictMsg objectForKey:@"body"];
if (from && body){
NSDictionary *dictResponse = [[NSDictionary alloc] initWithObjectsAndKeys:from,@"from",body,@"message", nil];
if (delegate && [delegate respondsToSelector:@selector(chatMUCMessageReceiveResponse:)]) {
[delegate chatMUCMessageReceiveResponse:dictResponse];
}
else {
NSLog(@"delegate is empty or not response to selector");
}
}
else{
NSLog(@"from name or body empty response");
}
}
}
else{
NSLog(@"dict empty");
}
}
#pragma mark - Single User Chat
//<message type="chat" to="gaurav@gauravs-mac.local/spark"><body>hello gaurav</body></message>
- (void)SUC_chatWithMessage:(NSString*)messageStr
toUser:(NSString*)toUser{
NSLog(@"ChatConnection:Method -");
NSLog(@"- (void)SUC_chatWithMessage:fromUser:toUser:");
if ([ChatConnection isNotNull:messageStr] &&
[ChatConnection isNotNull:toUser]
) {
NSString *toServerStr = [NSString stringWithFormat:@"<message type='chat' to='%@@%@/iphone'><body>%@</body></message>",toUser,SERVER_NAME,messageStr];
[self writeToServer:toServerStr];
} else {
NSLog(@"ChatConnection: MUC_chatOnChatRoomName:andMessage: chatRoomName or messageStr empty");
}
}
@end
No comments:
Post a Comment