I am implementing XMPPStreamManagement XEP-198 but my last message repeated multiple time
_xmppStreamManagement = [[XMPPStreamManagement alloc] initWithStorage:[XMPPStreamManagementMemoryStorage new]];
// And then configured however you like.
// This is just an example:
_xmppStreamManagement.autoResume = YES;
_xmppStreamManagement.ackResponseDelay = 0.2;
[_xmppStreamManagement requestAck];
[_xmppStreamManagement automaticallyRequestAcksAfterStanzaCount:3 orTimeout:0.4];
[_xmppStreamManagement automaticallySendAcksAfterStanzaCount:10 orTimeout:5.0];
[_xmppStreamManagement addDelegate:self delegateQueue:dispatch_get_main_queue()];
[_xmppStreamManagement activate:self.xmppStream];
After that i enable stream on xmpp Stream Did Authenticate delegate methods
// Check to see we resumed a previous session
NSArray *stanzaIds = nil;
if ([_xmppStreamManagement didResumeWithAckedStanzaIds:&stanzaIds serverResponse:NULL]){
// Situation A
}else {
// Situation B
//[self goOnline];
[self.xmppStream sendElement:[XMPPPresence presence]]; // send available presence
if ([sender supportsStreamManagement]) {
[_xmppStreamManagement enableStreamManagementWithResumption:YES maxTimeout:0];
}
}
Please suggest me where & how, i resolve duplicate message repetition and also not call XMPPStreamManagement delegate Method's
To avoid message duplication, you should add uniqueness check on your end on message id. As every message packet contains unique id, so you should check that id to avoid duplicate messages.
<message from='userA#yourdomain.io' to='userB#yourdomain.io' id='msg_1'>
<body>Shall we meet?</body>
</message>
Related
I am trying to retrieve vCards for few JIDs, including the current user. I initialized and activated XMPPvCardTempModule using following code -
_xmppvCardStorage = [XMPPvCardCoreDataStorage sharedInstance];
_xmppvCardTempModule = [[XMPPvCardTempModule alloc] initWithvCardStorage:self.xmppvCardStorage];
_xmppvCardAvatarModule = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:self.xmppvCardTempModule];
[self.xmppvCardTempModule activate:self.xmppStream];
[self.xmppvCardAvatarModule activate:self.xmppStream];
[self.xmppvCardAvatarModule addDelegate:self delegateQueue:dispatch_get_main_queue()];
[self.xmppvCardTempModule addDelegate:self delegateQueue:dispatch_get_main_queue()];
And then I implemented the following delegate methods -
- (void)xmppvCardTempModule:(XMPPvCardTempModule *)vCardTempModule
didReceivevCardTemp:(XMPPvCardTemp *)vCardTemp
forJID:(XMPPJID *)jid{
DDLogDebug(#"Received vCard for %# \n vCard:%#",jid.full,vCardTemp.XMLString);
ContactCore* contact = [appDelegate.coreDataController findContact:jid.user];
contact.vCard = vCardTemp;
[appDelegate.dataController postContactUpdateNotification:contact];
}
- (void)xmppvCardTempModuleDidUpdateMyvCard:(XMPPvCardTempModule *)vCardTempModule{
[self.selfContact setVCard:vCardTempModule.myvCardTemp];
}
- (void)xmppvCardTempModule:(XMPPvCardTempModule *)vCardTempModule failedToUpdateMyvCard:(DDXMLElement *)error{
DDLogDebug(#"failedToUpdateMyvCard Error: %#",error.XMLString);
}
-(void)xmppvCardAvatarModule:(XMPPvCardAvatarModule *)vCardTempModule didReceivePhoto:(UIImage *)photo forJID:(XMPPJID *)jid{
ContactCore* contact = [appDelegate.coreDataController findContact:jid.user];
}
The problem is that none of these delegate methods ever gets called. I can see the vCard output in the Log data which means that the vCards are getting fetched properly. So I implemented didReceiveIQ to get the vCards directly from the source, using the following code -
- (BOOL)xmppStream:(XMPPStream*)sender didReceiveIQ:(XMPPIQ *)iq{
XMPPvCardTemp *vCard = [XMPPvCardTemp vCardTempSubElementFromIQ:iq];
if(vCard){
ContactCore* contact = [appDelegate.coreDataController findContact:iq.from.user];
contact.vCard = vCard;
}
return NO;
}
But the vCard never gets initialized. I checked the IQs and I was receiving them properly. Then I checked the whole XML properly and found out that the vCard tag was absent and it was replaced with the actual name of the contact. For example this is what I was getting for one of the contact -
<iq
xmlns="jabber:client" from="xxx#xxx.com" to="xxx#xxx.com/xxx" id="12345" type="result">
<Abhi
xmlns="vcard-temp" prodid="-//HandGen//NONSGML vGen v1.0//EN" version="2.0">
<PHOTO>
<TYPE>image/jpeg</TYPE>
<BINVAL><!--A long Base64 code--></BINVAL>
</PHOTO>
</Abhi>
</iq>
The tag <Abhi> should be <vCard> for the vCardTempSubElementFromIQ method to identify it as a vCard. I want to know if it's a normal behavior or is there something I am doing wrong here? If it's something I am doing wrong, what should be the correct way to do it?
While saving a vCard I was using name property of the vCard to set name of the contact. This property actually changes the tag name, not the contact name. I started using nickname property after realizing my mistake.
Trying to create a very simple proof of concept iOS xmpp app with the robbiehanson xmpp frame work, just need to be able to send and receive messages and roster data. I can authenticate and send messages successfully, but when users attempt to respond to my messages I do not receive them. I have implemented the didReceiveMessage delegate method as follows:
-(void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {
NSLog(#"incoming message: %#", message);
}
but I never receive this log. If I log in with the existing web app or android app that communicates with this xmpp server I receive these messages, so I'm inclined to believe they are formatted properly. Is there a module I need to add to the XMPPStream for receiving messages? I'm setting up the stream like this (some of the string values have been changed for security and what not):
stream = [[XMPPStream alloc] init];
stream.enableBackgroundingOnSocket = YES;
stream.hostName = #"hostname.com";
stream.hostPort = 5222;
XMPPRosterCoreDataStorage* xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] initWithInMemoryStore];
XMPPRoster* xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:xmppRosterStorage];
xmppRoster.autoFetchRoster = YES;
xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = YES;
[stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
XMPPJID* jid = [XMPPJID jidWithUser:#"username" domain:#"domain.com" resource:#"iOS"];
[stream setMyJID:jid];
[xmppRoster activate:stream];
[stream connectWithTimeout:XMPPStreamTimeoutNone error:&error]
and then in the xmppStreamDidConnect method I do this to authenticate
NSString *myPassword = #"password";
NSError *error = nil;
[stream authenticateWithPassword:myPassword error:&error]
When I am sending a message out I use this snippet:
MPPJID* recipient = [XMPPJID jidWithString:#"user#domain.com"];
XMPPMessage* message = [[XMPPMessage alloc] initWithType:#"chat" to:recipient];
[message addBody:#"hello world"];
[stream sendElement: message];
I'm thinking there is something simple I am missing that someone who has used this before will be able to point out to me right away. I'm ready to supply other info if necessary for solving this issue.
I simply needed to broadcast my presence, then I was able to receive messages.
I added these lines to the streamDidAuthenticate method
XMPPPresence *presence = [XMPPPresence presence];
[sender sendElement:presence];
In my delegate.m
- (void)setupStream
{
NSAssert(xmppStream == nil, #"Method setupStream invoked multiple times");
customCertEvaluation = YES;
// allowSelfSignedCertificates = YES;
// allowSSLHostNameMismatch = NO; // Setup xmpp stream
//
// The XMPPStream is the base class for all activity.
// Everything else plugs into the xmppStream, such as modules/extensions and delegates.
xmppStream = [[XMPPStream alloc] init];
[xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
#if !TARGET_IPHONE_SIMULATOR
{
// Want xmpp to run in the background?
//
// P.S. - The simulator doesn't support backgrounding yet.
// When you try to set the associated property on the simulator, it simply fails.
// And when you background an app on the simulator,
// it just queues network traffic til the app is foregrounded again.
// We are patiently waiting for a fix from Apple.
// If you do enableBackgroundingOnSocket on the simulator,
// you will simply see an error message from the xmpp stack when it fails to set the property.
xmppStream.enableBackgroundingOnSocket = YES;
}
#endif
// Setup reconnect
//
// The XMPPReconnect module monitors for "accidental disconnections" and
// automatically reconnects the stream for you.
// There's a bunch more information in the XMPPReconnect header file.
xmppReconnect = [[XMPPReconnect alloc] init];
// XMPPAutoPing *xmppAutoPing = [[XMPPAutoPing alloc] initWithDispatchQueue:dispatch_get_main_queue()];
//xmppAutoPing.pingInterval = 25.f; // default is 60
//xmppAutoPing.pingTimeout = 10.f; // default is 10
//[xmppAutoPing addDelegate:self delegateQueue:dispatch_get_main_queue()];
//[xmppAutoPing activate:self.xmppStream];
// Setup roster
//
// The XMPPRoster handles the xmpp protocol stuff related to the roster.
// The storage for the roster is abstracted.
// So you can use any storage mechanism you want.
// You can store it all in memory, or use core data and store it on disk, or use core data with an in-memory store,
// or setup your own using raw SQLite, or create your own storage mechanism.
// You can do it however you like! It's your application.
// But you do need to provide the roster with some storage facility.
xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] init];
xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] initWithInMemoryStore];
xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:xmppRosterStorage];
xmppRoster.autoFetchRoster = YES;
xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = YES;
// Setup vCard support
//
// The vCard Avatar module works in conjuction with the standard vCard Temp module to download user avatars.
// The XMPPRoster will automatically integrate with XMPPvCardAvatarModule to cache roster photos in the roster.
xmppvCardStorage = [XMPPvCardCoreDataStorage sharedInstance];
xmppvCardTempModule = [[XMPPvCardTempModule alloc] initWithvCardStorage:xmppvCardStorage];
xmppvCardAvatarModule = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:xmppvCardTempModule];
// Setup capabilities
//
// The XMPPCapabilities module handles all the complex hashing of the caps protocol (XEP-0115).
// Basically, when other clients broadcast their presence on the network
// they include information about what capabilities their client supports (audio, video, file transfer, etc).
// But as you can imagine, this list starts to get pretty big.
// This is where the hashing stuff comes into play.
// Most people running the same version of the same client are going to have the same list of capabilities.
// So the protocol defines a standardized way to hash the list of capabilities.
// Clients then broadcast the tiny hash instead of the big list.
// The XMPPCapabilities protocol automatically handles figuring out what these hashes mean,
// and also persistently storing the hashes so lookups aren't needed in the future.
//
// Similarly to the roster, the storage of the module is abstracted.
// You are strongly encouraged to persist caps information across sessions.
//
// The XMPPCapabilitiesCoreDataStorage is an ideal solution.
// It can also be shared amongst multiple streams to further reduce hash lookups.
xmppCapabilitiesStorage = [XMPPCapabilitiesCoreDataStorage sharedInstance];
xmppCapabilities = [[XMPPCapabilities alloc] initWithCapabilitiesStorage:xmppCapabilitiesStorage];
xmppCapabilities.autoFetchHashedCapabilities = YES;
xmppCapabilities.autoFetchNonHashedCapabilities = NO;
// Activate xmpp modules
[xmppReconnect activate:xmppStream];
[xmppRoster activate:xmppStream];
[xmppvCardTempModule activate:xmppStream];
[xmppvCardAvatarModule activate:xmppStream];
[xmppCapabilities activate:xmppStream];
// Add ourself as a delegate to anything we may be interested in
[xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
[xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
// Optional:
//
// Replace me with the proper domain and port.
// The example below is setup for a typical google talk account.
//
// If you don't supply a hostName, then it will be automatically resolved using the JID (below).
// For example, if you supply a JID like 'user#quack.com/rsrc'
// then the xmpp framework will follow the xmpp specification, and do a SRV lookup for quack.com.
//
// If you don't specify a hostPort, then the default (5222) will be used.
[xmppStream setHostName:#"10.10.1.77"];
[xmppStream setHostPort:5222];
// You may need to alter these settings depending on the server you're connecting to
// allowSelfSignedCertificates = YES;
// allowSSLHostNameMismatch = NO;
customCertEvaluation = YES;
}
and also
- (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
NSString *expectedCertName = [xmppStream.myJID domain];
if (expectedCertName)
{
[settings setObject:expectedCertName forKey:(NSString *)kCFStreamSSLPeerName];
}
if (customCertEvaluation)
[settings setObject:#(YES) forKey:GCDAsyncSocketManuallyEvaluateTrust];
}
- (void)xmppStream:(XMPPStream *)sender didReceiveTrust:(SecTrustRef)trust
completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler
{
/*DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
// The delegate method should likely have code similar to this,
// but will presumably perform some extra security code stuff.
// For example, allowing a specific self-signed certificate that is known to the app.
allowSelfSignedCertificates = YES;
allowSSLHostNameMismatch = NO;
dispatch_queue_t bgQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(bgQueue, ^{
SecTrustResultType result = kSecTrustResultDeny;
OSStatus status = SecTrustEvaluate(trust, &result);
if (status == noErr && (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified)) {
completionHandler(YES);
}
else {
completionHandler(NO);
}
});
*/
completionHandler(YES);
}
I have done everything that was suggested in code but still connecting to server using SSL port gives error
2014-07-18 18:08:14:724 iPhoneXMPP[20593:60b] iPhoneXMPPAppDelegate: xmppStream:socketDidConnect:
2014-07-18 18:08:14:724 iPhoneXMPP[20593:60b] iPhoneXMPPAppDelegate: xmppStream:socketDidConnect:
2014-07-18 18:08:14:925 iPhoneXMPP[20593:60b] iPhoneXMPPAppDelegate: xmppStreamDidDisconnect:withError:
2014-07-18 18:08:14.925 iPhoneXMPP[20593:60b] Unable to connect to server
2014-07-18 18:08:14:926 iPhoneXMPP[20593:60b] Unable to connect to server. Check xmppStream.hostName
How am i supposed to solve to this error; Connection to normal port is fine though.Connection to SSL port is the only problem.
I finally can use SSL in 5223 port. I have to force use startTLS on didConnectToHost on XMPPStream.m. I don't know why isSecure always says NO.
Use the following method to enable the SSL/TLS. However this method is not defined theXMPPStream.h class, you need to define it here and access it from appdelegate or inside setupsteam method.
-(void)setIsSecure:(BOOL)flag
I can't receive this IQ packet sent from server.
How can I listen to Custom IQ Packets in XMPPFramework?
This method didn't work:
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
I am using XMPPFramework.
<iq id="pvrequest" type="get">
<pvcommand xmlns='detayopenfireplugin:iq:customiq'>
<sendClassName>MainScreenController</sendClassName>
<sendMethodName>getMainUsersInfo</sendMethodName>
<spvcommand>eyJtbmFtZSI6ImdldE1haW5Vc2Vyc0luZm9Gb3JXZWIiLCJjbGlkIjoiMTAwIiwiY25hbWUiOiJvcmcuZGV0YXlzb2Z0LmF0b21pYy5kZXRheW9wZW5maXJlcGx1Z2luLnByb2Nlc3Nvci5leHRlcm5hbHByb2Nlc3Nvci5zdWJwcm9jZXNzb3IuQnVzaW5lc3MiLCJ1c2lkIjoiUDA0MDUifQ==</spvcommand>
</pvcommand>
</iq>
Have you assign delegate for xmpp in your view controller.
(void)setupStream
{
NSAssert(xmppStream == nil, #"Method setupStream invoked multiple times");
// Setup xmpp stream
//
// The XMPPStream is the base class for all activity.
// Everything else plugs into the xmppStream, such as modules/extensions and delegates.
xmppStream = [[XMPPStream alloc] init];
#if !TARGET_IPHONE_SIMULATOR
{
// Want xmpp to run in the background?
//
// P.S. - The simulator doesn't support backgrounding yet.
// When you try to set the associated property on the simulator, it simply fails.
// And when you background an app on the simulator,
// it just queues network traffic til the app is foregrounded again.
// We are patiently waiting for a fix from Apple.
// If you do enableBackgroundingOnSocket on the simulator,
// you will simply see an error message from the xmpp stack when it fails to set the property.
xmppStream.enableBackgroundingOnSocket = YES;
}
#endif
// Setup reconnect
//
// The XMPPReconnect module monitors for "accidental disconnections" and
// automatically reconnects the stream for you.
// There's a bunch more information in the XMPPReconnect header file.
xmppReconnect = [[XMPPReconnect alloc] init];
// Setup roster
//
// The XMPPRoster handles the xmpp protocol stuff related to the roster.
// The storage for the roster is abstracted.
// So you can use any storage mechanism you want.
// You can store it all in memory, or use core data and store it on disk, or use core data with an in-memory store,
// or setup your own using raw SQLite, or create your own storage mechanism.
// You can do it however you like! It's your application.
// But you do need to provide the roster with some storage facility.
xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] init];
// xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] initWithInMemoryStore];
xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:xmppRosterStorage];
xmppRoster.autoFetchRoster = YES;
xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = YES;
// Setup vCard support
//
// The vCard Avatar module works in conjuction with the standard vCard Temp module to download user avatars.
// The XMPPRoster will automatically integrate with XMPPvCardAvatarModule to cache roster photos in the roster.
xmppvCardStorage = [XMPPvCardCoreDataStorage sharedInstance];
xmppvCardTempModule = [[XMPPvCardTempModule alloc] initWithvCardStorage:xmppvCardStorage];
xmppvCardAvatarModule = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:xmppvCardTempModule];
// Setup capabilities
//
// The XMPPCapabilities module handles all the complex hashing of the caps protocol (XEP-0115).
// Basically, when other clients broadcast their presence on the network
// they include information about what capabilities their client supports (audio, video, file transfer, etc).
// But as you can imagine, this list starts to get pretty big.
// This is where the hashing stuff comes into play.
// Most people running the same version of the same client are going to have the same list of capabilities.
// So the protocol defines a standardized way to hash the list of capabilities.
// Clients then broadcast the tiny hash instead of the big list.
// The XMPPCapabilities protocol automatically handles figuring out what these hashes mean,
// and also persistently storing the hashes so lookups aren't needed in the future.
//
// Similarly to the roster, the storage of the module is abstracted.
// You are strongly encouraged to persist caps information across sessions.
//
// The XMPPCapabilitiesCoreDataStorage is an ideal solution.
// It can also be shared amongst multiple streams to further reduce hash lookups.
xmppCapabilitiesStorage = [XMPPCapabilitiesCoreDataStorage sharedInstance];
xmppCapabilities = [[XMPPCapabilities alloc] initWithCapabilitiesStorage:xmppCapabilitiesStorage];
xmppCapabilities.autoFetchHashedCapabilities = YES;
xmppCapabilities.autoFetchNonHashedCapabilities = NO;
// Activate xmpp modules
[xmppReconnect activate:xmppStream];
[xmppRoster activate:xmppStream];
[xmppvCardTempModule activate:xmppStream];
[xmppvCardAvatarModule activate:xmppStream];
[xmppCapabilities activate:xmppStream];
// Add ourself as a delegate to anything we may be interested in
[xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
[xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
// Optional:
//
// Replace me with the proper domain and port.
// The example below is setup for a typical google talk account.
//
// If you don't supply a hostName, then it will be automatically resolved using the JID (below).
// For example, if you supply a JID like 'user#quack.com/rsrc'
// then the xmpp framework will follow the xmpp specification, and do a SRV lookup for quack.com.
//
// If you don't specify a hostPort, then the default (5222) will be used.
// [xmppStream setHostName:#"talk.google.com"];
// [xmppStream setHostPort:5222];
// You may need to alter these settings depending on the server you're connecting to
allowSelfSignedCertificates = NO;
allowSSLHostNameMismatch = NO;
}
I am developing a chat application in iOS using XMPP. I have so far successfully implemented and tested a single user chat scenario, i.e. sending, receiving, saving and retrieving messages.
The problem now em facing is that now when handling Multi User Chat scenarios em receiving it but not able to save them using XMPP MessageArchiving hence cant retrieve them either.
Anyone who has gone through this process/problem?
Thank you in advance
Messages with groupchat type may be saved within XMPPRoom.xcdatamodel, you need to initialize the XMPPRoomCoreDataStorage in your xmpp setup like:
XMPPRoomCoreDataStorage *xmppRoomStorage = [[XMPPRoomCoreDataStorage alloc] init];
So, this class implements a method to insert all the messages ROOM within the correct data model (in our case, all the outgoing and incoming messages are saved in XMPPRoom.xcdatamodel).
- (void)insertMessage:(XMPPMessage *)message
outgoing:(BOOL)isOutgoing
forRoom:(XMPPRoom *)room
stream:(XMPPStream *)xmppStream
More XEP-0045 info http://xmpp.org/extensions/xep-0045.html
You can use this code for a saving room messages
NSString *xmppRoomJIDString = [NSString stringWithFormat:#"%##conference.your_host", #"your_room_name"];
XMPPJID *roomJID = [XMPPJID jidWithString:xmppRoomJIDString];
XMPPRoomCoreDataStorage *roomCoreDataStorage = [XMPPRoomCoreDataStorage sharedInstance];
XMPPRoom *xmppRoom = [[XMPPRoom alloc]
initWithRoomStorage:roomCoreDataStorage
jid:roomJID
dispatchQueue:dispatch_get_main_queue()];
[xmppRoom activate:xmppStream];
[xmppRoom addDelegate:self delegateQueue:dispatch_get_main_queue()];
[xmppRoom joinRoomUsingNickname:#"your_nicke_name" history:nil];
[xmppRoom fetchConfigurationForm];