Buddy list issue in XMPP Server for iPhone - iphone

I'm able to connect to the local server, and also the google talk and display the buddies and chat on the iphone chat client but when I try to get Buddy list of my local server, it return 0.
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence {
// a buddy went offline/online
NSString *presenceType = [presence type]; // online/offline
NSString *myUsername = [[sender myJID] user];
NSString *presenceFromUser = [[presence from] user];
if (![presenceFromUser isEqualToString:myUsername])
{
if ([presenceType isEqualToString:#"available"]) {
[_chatDelegate newBuddyOnline:[NSString stringWithFormat:#"%##%#", presenceFromUser, #"ip address"]];
} else if ([presenceType isEqualToString:#"unavailable"]) {
[_chatDelegate buddyWentOffline:[NSString stringWithFormat:#"%##%#", presenceFromUser, #"ip address"]];
}
}
}
Here ip address means my server name
Please help!
Please help me!!!

It only tells you when some one comes online or goes offline, according to this code, when any buddy will be online delegate method 'newBuddyOnline' will be fired and when someone will go offline delegate method 'buddyWentOffline' will be fired.
You can get list of all buddies by adding buddies to array when they come online after connecting to xmpp stream

Related

Can't connect to [QBChat Instance] connect with User, in Quickblox

I am using Quickblox Api, for chat and video chat. iOS. And I am using the latest version of the API
When I try to Make a video call,
most of the times i don't get video, only audio.
i get video on both ends 1 out of 15 times.
3 out of 10 times video on one end.
very weird. I have good internet connection. connecting to chat users are receiving the call. Can seem to find out the issue.
After spending sometime to find the issue, I received and help from Quickblox Help Center.
If your face such Behavior on the API
1.Make Sure that you set Delegate Methods in viewDidLod, not view did appear or etc. For Ex:
- (void)viewDidLoad {
[super viewDidLoad];
[[QBChat instance] addDelegate:self];
[QBRTCClient.instance addDelegate:self];
[QBSettings setCarbonsEnabled:YES];
}
Use Breakpoints to find out if they are getting called, once you make or receive calls.
2.Make Sure that your Calling methods are correct. An array containing Users must not equal to currentUser.ID.
NSInteger currentUserID = [QBSession currentSession].currentUser.ID;
int count = 0;
NSNumber *currentUserIndex = nil;
for (NSNumber *opponentID in opponentsIDs) {
if ([opponentID integerValue] == currentUserID) {
currentUserIndex = #(count);
break;
}
count++;
}
if (currentUserIndex) [opponentsIDs removeObjectAtIndex:[currentUserIndex intValue]];
QBRTCSession *session = [QBRTCClient.instance createNewSessionWithOpponents:opponentsIDs
withConferenceType:QBRTCConferenceTypeVideo];
NSDictionary *userInfo = #{ #"key" : #"value" };
[session startCall:userInfo];
if (session) {
self.currentSession = session;
[self performSegueWithIdentifier:#"openDialogSeg" sender:self];
}
else {
[SVProgressHUD showErrorWithStatus:#"You should login to use chat API. Session hasn’t been created. Please try to relogin the chat."];
}
}
Check View Layout, size and width. make sure they are set correctly.

Multipeer Connectivity - State Not Changing

I'm working on an app the uses the Multipeer Conectivity Framework. So far everything is going great, I've implemented programmatic browsing and invitations.
My issue is when the user accepts the invitation the Browser is not receiving the state change - thereby not creating the session.
This is the advertiser did receive invitation method i have created using an action sheet integrated with blocks.
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser
didReceiveInvitationFromPeer:(MCPeerID *)peerID
withContext:(NSData *)context
invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler
{
[UIActionSheet showInView:self.view
withTitle:[[NSString alloc]initWithFormat:#"%# would like to share %# information with you.",peerID.displayName, (NSString *)context]
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:#"Deny"
otherButtonTitles:#[#"Accept"]
tapBlock:^(UIActionSheet *actionSheet, NSInteger buttonIndex) {
NSLog(#"%i",buttonIndex==1?true:false);
MCSession *newSession=[[MCSession alloc]initWithPeer:[[MCPeerID alloc] initWithDisplayName:#"CRAP23456"]];
[newSession setDelegate: self];
NSLog(#"button index %i ",buttonIndex==1?true:false);
invitationHandler(buttonIndex==1?YES:NO,newSession);
}];
}
The above method is being called and the invitation handler is returning the correct value.
My implementation from the browser side is very simple - and this is the method that should be called when the user either accepts/declines the method. However, it's only being called when the user declines the invite:
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state
{
NSLog(#"%d",state);
NSLog(#"%ld",(long)MCSessionStateConnected);
}
Thanks in advance.
James.
I hope one of these will help:
Implement session:didReceiveCertificate:fromPeer:certificateHandler:
I read here that this is necessary.
Keep browsing and advertising between two peers a one-way deal; that is, don't accept invitations on both ends if both are browsing as well (at least don't accept an invitation and pass same session you're browsing with in invitationHandler()).
Wrap your code in the didChangeState in a block like this:
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"%d",state);
NSLog(#"%ld",(long)MCSessionStateConnected);
});
I ran into this issue too. My code on the browser side looked like this:
MCSession *session = [[MCSession alloc] initWithPeer:[self peerID]];
session.delegate = self;
[browser invitePeer:peerID toSession:session withContext:nil timeout:30.0f];
The issue with this is that the browser does not retain a reference to the session and so ARC comes around and cleans it up before the other end had the opportunity to accept.
Changing it to the following fixed the issue:
_session = [[MCSession alloc] initWithPeer:[self peerID]];
_session.delegate = self;
[browser invitePeer:peerID toSession:_session withContext:nil timeout:30.0f];
.. where _session is an ivar on my class.
HTH

XMPPFramework on iOS -xmppRoomDidDestroy: not getting called

I'm developing an iPhone app using the XMPP framework for iOS/OSX and I'm using the XEP-0045 extension (multi-user chat). I've got the room creating and configuring successfully and I am able to invite other users and chat with them. The problem arises when I go to destroy the room I've created. I've followed the code-path that gets executed inside the framework and I've figured out why the framework isn't firing the method, but I'm not sure how it would ever fire the method given the behavior I'm seeing.
That behavior is as follows:
1) I request that the room be destroyed by calling [room destroyRoom]
2) I then see that the XMPPRoom class sets up its XMPPIDResponse tracker to watch for the "result" iq stanza that the server will send back saying it's successfully deleted the room.
3) (Here is where the problem arises) I receive a presence stanza from the room saying it's now unavailable (since I, too, am an occupant of the room) and the framework then clears the response tracker and calls -xmppRoomDidLeave:.
4) The server then sends back the "result" iq stanza saying that the room was successfully deleted, but no one is listening anymore. This results in the call to xmppRoomDidDestroy being missed.
This behavior is consistent with what I've read in the XEP-0045 definition and, given that, I'm not sure how the -xmppRoomDidDestroy: delegate would ever get called. Am I doing something wrong here?
I had the same problem and this is my solution:
In XMPPRoom method
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
replace
[responseTracker removeAllIDs];
with:
if ([x elementForName:#"destroy"]) {
NSArray *allKeys = [responseTracker allIDs];
for (NSString *key in allKeys) {
SEL aSel = [responseTracker selectorForElementID:key];
if (aSel != #selector(handleDestroyRoomResponse:withInfo:)) {
[responseTracker removeID:key];
}
}
} else {
[responseTracker removeAllIDs];
}
In XMPPIDTracker.h add declaration for new public methods
- (NSArray *)allIDs;
- (SEL)selectorForElementID:(NSString *)elementID;
Also in XMPPBasicTrackingInfo interface add
#property (nonatomic, readonly) SEL selector;
In XMPPIDTracker.m add two public methods
- (NSArray *)allIDs {
return [dict allKeys];
}
- (SEL)selectorForElementID:(NSString *)elementID {
id <XMPPTrackingInfo> info = [dict objectForKey:elementID];
if ([info isKindOfClass:[XMPPBasicTrackingInfo class]]) {
return [(XMPPBasicTrackingInfo *)info selector];
}
return nil;
}
At the end in the #implementation XMPPBasicTrackingInfo add
#synthesize selector;
Basicaly this code removes all response trackers except handleDestroyRoomResponse:withInfo: because we need this hander to respond on IQ destroy stanza.
I hope this will help.
Same issue with lastest XMPPFramework 3.6.6.
Here is the solution:
Still use destroyRoom function, xmppStream:didReceivePresence: and xmppRoomDidLeave: will be called, test by add NSLog inside both delegate, then i use Spark(Windows version) to destory a room, the Xcode console print the following text:
<presence xmlns="jabber:client" type="unavailable" from="wei#conference.10.50.200.94/admin" to="admin#10.50.200.94/iOS">
<x xmlns="http://jabber.org/protocol/muc#user">
<item affiliation="none" role="none"></item>
<destroy>
<reason>destroy room</reason>
</destroy>
</x>
</presence>
I use the <destroy> element to determine the destroyRoom action.
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
{
/*
<presence xmlns="jabber:client" type="unavailable" from="wei#conference.10.50.200.94/admin" to="admin#10.50.200.94/iOS"><x xmlns="http://jabber.org/protocol/muc#user"><item affiliation="none" role="none"></item><destroy><reason>destroy room</reason></destroy></x></presence>
*/
// NSLog(#"%s %#", __FUNCTION__, presence);
if ([presence.fromStr containsString:#"conference"]) {
NSXMLElement *x = [presence elementForName:#"x"];
if (x) {
NSXMLElement *destroy = [x elementForName:#"destroy"];
if (destroy) {
XMPPJID *roomJID = presence.from.bareJID;
// TODO: do something with the roomJID
}
}
}
}
But XMPPFramework send a empty <destory/> element, i guess the openfire server simply ignore the <destroy/> and response <presence>..</presence> without <destroy>.
Modify the destroyRoom function in XMPPFramework or implement the following delegate to add a destroy reason.
- (XMPPIQ *)xmppStream:(XMPPStream *)sender willSendIQ:(XMPPIQ *)iq
{
/*
<iq type="set" to="weixin#conference.10.50.200.94" id="BCF55C6A-9C5E-4740-BE6A-63E17B5C58F6"><query xmlns="http://jabber.org/protocol/muc#owner"><destroy></destroy></query></iq>
*/
if ([iq isSetIQ]) {
NSXMLElement *query = [iq elementForName:#"query" xmlns:XMPPMUCOwnerNamespace];
if (query) {
NSXMLElement *destroy = [query elementForName:#"destroy"];
if (destroy) {
NSXMLElement *reason = [destroy elementForName:#"reason"];
if (!reason) {
reason = [NSXMLElement elementWithName:#"reason" stringValue:#"destroy reason"];
[destroy addChild:reason];
}
}
}
}
return iq;
}

How to check if sim card is installed or not

I am developing an app which has call and message functionality , i want to check if sim card is installed or not coz i am facing problem with messaging as it gives alerts for " Message Sent Successful"
Please help me out.
There might be different ways but one way is by using MFMessageComposeViewController class to see if you can send the text message. If you can then sim is available otherwise not.
if ([MFMessageComposeViewController canSendText]) {
NSLog(#"SIM Available");
} else {
NSLog(#"no SIM card installed");
}
In cases you have iMessage available then this might return you true, you could also check if you can make a call, you might want to use CTTelephonyNetworkInfo for that purpose.
You can also check using like this.... First read this doc
http://developer.apple.com/library/ios/#DOCUMENTATION/NetworkingInternet/Reference/CTCarrier/Reference/Reference.html#//apple_ref/doc/uid/TP40009596-CH1-SW1
NSString *_code = [[[CTCarrier alloc] init] mobileCountryCode];
The value for this property is nil if any of the following apply:
The device is in Airplane mode.
There is no SIM card in the device.
The device is outside of cellular service range.
First you have to be sure that device is iPhone (not iPod or iPad) then check if device can make call or not, just like this............
if([[UIDevice currentDevice].model isEqualToString:#"iPhone"])
{
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:#"tel:123456"]])
{
NSLog(#"Device can make call or send message");
}
else
{
NSLog(#"Device can not make call or send message");
}
}
else
{
NSLog(#"Device can not make call or send message");
}
Hope it will help you........

How to tell when we are disconnected from GameCenter GKMatch session?

I'm wondering how do I get the disconnect message for local player when the game session is in progress and we're unable to communicate our data to other players. As there is nothing in documentation that says "this method will inform you whenever your connection fails", I'm at a bit of a loss.
I was trying to use this chunk of code in hopes that it would work, but it's futile. The "We're disconnected." message is never triggered.
- (void)match:(GKMatch *)theMatch player:(NSString *)playerID didChangeState:(GKPlayerConnectionState)state {
if (self.match != theMatch) return;
switch (state) {
case GKPlayerStateDisconnected:
//disconnected
NSLog(#"player status changed: disconnected");
matchStarted = NO;
GKLocalPlayer *player = [GKLocalPlayer localPlayer];
if ([playerID isEqualToString:player.playerID]) {
// We have been disconnected
NSLog(#"We're disconnected.");
}
if ([delegate respondsToSelector:#selector(matchEnded)]) {
[delegate matchEnded];
}
break;
}
}
The only other line that I found might tell us that we're unable to communicate is when we actually send data like this:
- (void)sendRandomMatchData:(NSData *)data {
GKMatch *match = [GCHelper sharedInstance].match;
BOOL success = [match sendDataToAllPlayers:data
withDataMode:GKMatchSendDataReliable
error:nil];
if (!success) {
[self matchEnded];
}
}
But I assume that "success" will also be false if the opponent has disconnected and we're unable to send messages to them.
I have a pretty strict game logics, if someone has been disconnected I need to inform them that they are unable to continue playing the match and that they have lost.
Any help is highly appreciated.
There are 2 places you can do this, both are in the GKMatchDelegate protocol.
The first is implementing:
- (void)match:(GKMatch *)match player:(NSString *)playerID
didChangeState:(GKPlayerConnectionState)state
{
}
And if it's a 2 player match, the second place you can catch the disconnect is:
- (BOOL)match:(GKMatch *)theMatch shouldReinvitePlayer:(NSString *)playerID
{
}
Both those events fire reliably when the GKMatch is terminated. If Stan's answer answered your question, then I would highly recommend getting in the practice of catching NSError wherever they are available! Can save you lots of time.
So to send data and catch the error:
NSError* nsErr ;
int result = [theMatch sendData:nsd toPlayers:theMatch.playerIDs
withDataMode:GKMatchSendDataReliable error:&nsErr] ;
if( !result ) { // NO if the match was unable to queue the data.
error( nsErr, "Failed to sendRoundtripPing" ) ;
}
What about examining the error after the following code line:
BOOL success = [match sendDataToAllPlayers:data
withDataMode:GKMatchSendDataReliable
error:nil]; //replace nil with NSError variable
Maybe error will give you extra info u need.
Another idea is to create NSTimer and set some certain time for making moves/turns. If some player didn't make it for a certain time then assume this player is disconnected. Also you could check your Internet connection state to determine you have a connection cuz maybe you just lost it and that's the reason you can't send/receive any data.
Also you could check every player periodically by sending them some short amount of data using GC just to make them answer you. This way you could ensure all players are "alive" or detect some "zombie".
Remember if player moves the game to background using Home button you won't detect it anyhow cuz code in your game wont execute. And this situation doesn't mean that player is "zombie". Player could be busy by a call or something else like another app. Player could temporary loose Internet connection. This means that he/she could return to game soon...