Im developing an app for iPhone, in wich one of the functionalities is an instant message system, using XMPPFramework. By now, im testing it with Google Talk. The delegate is the same class that manages the User Interface. So, I got this code:
In viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
[self setupStream];
}
The setupStream method:
- (void) setupStream
{
NSLog(#"Inside setupStream");
xmppStream = [[XMPPStream alloc] init];
[xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
[self connect];
}
The connect method:
- (BOOL) connect
{
NSLog(#"Inside connect method");
General *general = [General sharedManager];//this is a singleton to manage settings for every user
NSString *chatid;
NSString *chatpass;
//chatid=[general user];
chatid=#"somegmailaccount#gmail.com";
xmppStream.myJID=[XMPPJID jidWithString:chatid];
if (![xmppStream isDisconnected]) {
return YES;
}
NSError *error = nil;
if (![xmppStream connect:&error])
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:[NSString stringWithFormat:#"Can't connect to server %#", [error localizedDescription]]
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
return NO;
}
return YES;
}
In xmppStreamDidConnect method:
- (void) xmppStreamDidConnect:(XMPPStream *)sender
{
[xmppStream authenticateWithPassword:#"password" error:NULL];
[self goOnline];
}
And goOnline method:
- (void) goOnline
{
XMPPPresence *presence = [XMPPPresence presence];
[[self xmppStream] sendElement:presence];
NSLog(#"Presence sent");
}
With this, the presence is not sent. I have another google account that I try for testing (say, testing#gmail.com) and in this account the presence of somegmailaccount.gmail.com is not seen. Both accounts are connected and know each other, since I used this same accounts to develop the Android app.
Any idea about what i´m doing wrong? Any help is appreciated.
Thank you very much.
I found it! The presence is not sent this way:
XMPPPresence *presence = [XMPPPresence presence];
[[self xmppStream] sendElement:presence];
Insted, i have done it this way:
NSXMLElement *presence = [NSXMLElement elementWithName:#"presence"];
[xmppStream sendElement:presence];
This way, the presence is sent without any problem :)
With this code, i implement method xmppStreamDidAuthenticate:(XMPPStream *)sender
and the program DO enter that method without any call from my code. But if i put
[xmppStream setHostName:#"talk.google.com"];
[xmppStream setHostPort:5222];
... in method connect, the program DO NOT enter that method, nor xmppStreamDidConnect.
Im getting mad.
Related
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}
]}
i try to access a protected webfolder with the webview. with "hard coded" user and pass it works, but my plan is to pop up an alertview to enter user and pass. here is the part of code:
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge{
NSLog(#"Need Authentication");
UIAlertView *webLogin = [[UIAlertView alloc] initWithTitle:#"Authentication"
message:#"Enter User and Pass"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK"
, nil];
webLogin.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
[webLogin show];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
user = [[alertView textFieldAtIndex:0]text];
pass = [[alertView textFieldAtIndex:1]text];
NSLog(#"user is %# and pass is %#",user,pass);
if (buttonIndex == [alertView cancelButtonIndex]) {
[self dismissModalViewControllerAnimated:YES];
}
else if (buttonIndex != [alertView cancelButtonIndex]) {
NSLog(#"OK Pressed");
[self handleAuthentificationOKForChallenge:nil withUser:user password:pass];
}
}
- (void)handleAuthentificationOKForChallenge:(NSURLAuthenticationChallenge *)aChallenge withUser:(NSString *)userName password:(NSString *)password {
NSURLCredential *credential = [[NSURLCredential alloc]
initWithUser:userName password:password
persistence:NSURLCredentialPersistenceForSession];
[[aChallenge sender] useCredential:credential forAuthenticationChallenge:aChallenge];
}
can anybody tell me how to call the handleAuthenticationOKForChallenge
i´m a little bit confused with the NSURLAuthenticationChallenge....
First things first, you shouldn't use two if statements one after the other if they're comparing the same variable. Your second if statement should be an else if statement.
It looks like your handleAuthentificationOKForChallenge method wants to accept an instance of NSURLAuthenticationChallenge, but you're currently just passing it nil.
Why don't you declare an instance of NSURLAuthenticationChallenge in your header file (let's call it myChallenge), and in your first method, allocate and initialize it with challenge. You could also just set it equal to challenge (might work, if you feel like trying this first), but you may lose the pointer at some point.
Then you would change your line in your second method to:
[self handleAuthentificationOKForChallenge:myChallenge withUser:user password:pass];
Let me know if this works...
In application, invitationDidFail is being called, some time it connects properly, but sometime it doesn't...
what can be possible reasons of denying the connection?
// Display an alert sheet indicating a failure to connect to the peer.
- (void) invitationDidFail:(SessionManager *)session fromPeer:(NSString *)participantID
{
NSString *str;
if (alertView.visible) {
// Peer cancelled invitation before it could be accepted/rejected
// Close the invitation dialog before opening an error dialog
[alertView dismissWithClickedButtonIndex:0 animated:NO];
[alertView release];
str = [NSString stringWithFormat:#"%# is busy.\nPlease again", participantID];
//[peerList removeAllObjects];
[self peerListDidChange:nil];
[self.tableData reloadData];
//[self TwoPlayer:self];
} else {
// Peer rejected invitation or exited app.
str = [NSString stringWithFormat:#"%# is busy.\nPlease try again", participantID];
//[peerList removeAllObjects];
[self peerListDidChange:nil];
[self.tableData reloadData];
//[self TwoPlayer:self];
}
}
Even it doesn't call this method, It is sure that device is not paired to any other device, then what are reasons that sometime it do accept and call didReceivedInvitation method, or some time it does deny by calling invitationDidFail.
// Invitation dialog due to peer attempting to connect.
- (void) didReceiveInvitation:(SessionManager *)session fromPeer:(NSString *)participantID;
{
[alertView dismissWithClickedButtonIndex:1 animated:NO];
NSString *str = [NSString stringWithFormat:#"Incoming Invite from %#", participantID];
if (alertView.visible) {
[alertView dismissWithClickedButtonIndex:0 animated:NO];
[alertView release];
}
alertView = [[UIAlertView alloc]
initWithTitle:str
message:#"Do you wish to accept?"
delegate:self
cancelButtonTitle:#"Decline"
otherButtonTitles:nil];
[alertView addButtonWithTitle:#"Accept"];
[alertView show];
}
When I was recently writing an application using connections, I used GKSession. I spent weeks trying to debug connection issues with it and in the end I gave up and stopped using it. There seems to be a number of issues with GKSession when connecting especially if you disconnect and then attempt to reconnect within a short time (a short time could be 1 minute or more). It seems that the connection doesn't properly get dropped and then it doesn't recreate the connection properly.
In the end I took out all the GKSession code and used this instead. Worked a treat - no more connection issues.
GCD Async Socket
I was hoping someone could help me with this problem. I am trying to access a Picasa Web Album from my iphone application. I have used GData previously with Google Calendar and getting events and the data related to them before, so I set up my methods in a similar fashion. I however am getting an error that is telling me the following
serviceBase:<GDataServiceGooglePhotos: 0x4d4e6d0> objectFetcher:<GDataHTTPFetcher: 0xbaa35c0> failedWithStatus:400 data:Too many results requested
I am think that I have narrowed down the problem that I am having has something to do with the ticket that I am using, in the following line
ticket = [service fetchFeedWithURL:[NSURL URLWithString:kGDataGooglePhotosAllFeed]
delegate:self
didFinishSelector:#selector(photosListTicket:finishedWithFeed:error:)];
I however am unable to get past this problem. Does anyone have a suggestion to get past this problem. Am I doing something wrong?
My full code for the retrieval of the pictures is shown below. Anywhere that says picAlbum, that is a predefined NSArray to hold the information.
- (GDataServiceGooglePhotos *)photoService {
static GDataServiceGooglePhotos* service = nil;
if (!service) {
service = [[GDataServiceGooglePhotos alloc] init];
[service setShouldCacheDatedData:YES];
[service setServiceShouldFollowNextLinks:YES];
}
[service setUserCredentialsWithUsername:#"username"
password:#"password"];
return service;
}
-(void)loadGooglePhotos {
[self fetchAllPhotos];
}
-(void)fetchAllPhotos {
NSLog(#"In fetchAllPhotos");
GDataServiceGooglePhotos *service = [self photoService];
GDataServiceTicket *ticket;
ticket = [service fetchFeedWithURL:[NSURL URLWithString:kGDataGooglePhotosKindAlbum]
delegate:self
didFinishSelector:#selector(photosListTicket:finishedWithFeed:error:)];
}
- (void)photosListTicket:(GDataServiceTicket *)ticket finishedWithFeed:(GDataFeedPhotoAlbum *)feed error:(NSError *)error {
NSLog(#"In photosListTicket");
NSArray *photos = [feed entries];
if ([photos count] != 0){
self.picAlbum = [photos objectAtIndex:0];
NSLog(#"fetching photos");
[self fetchPhotos];
}
else {
NSLog(#"User has no photos...");
}
}
- (void)fetchPhotos {
NSLog(#"In fetchPhotos");
if (self.picAlbum) {
NSURL *feedURL = [[self.picAlbum alternateLink] URL];
if (feedURL) {
NSLog(feedURL);
GDataQueryGooglePhotos *query = [GDataQueryGooglePhotos photoQueryWithFeedURL:feedURL];
[query setMaxResults:1000];
GDataServiceGooglePhotos *service = [self photoService];
GDataServiceTicket *ticket;
ticket = [service fetchFeedWithQuery:query delegate:self didFinishSelector:#selector(photosEventsTicket:finishedWithFeed:error:)];
}
}
}
- (void)photosEventsTicket:(GDataServiceTicket *)ticket finishedWithFeed:(GDataFeedPhotoAlbum *)feed error:(NSError *)error {
NSLog(#"In photosEventsTicket");
NSArray *photos = [feed entries];
NSLog([NSString stringWithFormat:#"%i",[photos count]]);
}
Thanks in advance for any information or help that you can provide.
If the server says "Too many results requested" that's a clue that the max results query parameter is too big.
The fetches in the code snippet do not appear functional. Neither kGDataGooglePhotosKindAlbum nor an album's alternateLink would be URLs for feeds.
So I've got NSTask to run a script which generates a list of something, into a txt, which I read from. But if I use my current code (below), the alert pops up before the NSTask is finished, thus resulting in a blank alert. I've tried waitUntilExit but that makes the button that invokes this action freeze, but the UI doesn't lock up itself.
- (void) runSupported {
stask = [[NSTask alloc] init];
[stask setLaunchPath:#"/bin/bash"];
NSString *script;
script = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:#"/apps.sh"];
NSArray *sargs = [NSArray arrayWithObjects:script, #"-txt", nil];
[stask setArguments: sargs];
[stask launch];
NSString *apps;
apps = [NSString stringWithContentsOfFile:#"/var/mobile/supported.txt" encoding:NSUTF8StringEncoding error:nil];
NSFileManager *fm = [NSFileManager defaultManager];
if ([fm fileExistsAtPath:apps]) {
UIAlertView *supported = [[UIAlertView alloc] initWithTitle:#"App List" message:apps delegate:self cancelButtonTitle:#"Ok!" otherButtonTitles:nil];
[supported show];
[supported release];
} else {
UIAlertView *supported = [[UIAlertView alloc] initWithTitle:#"App List" message:#"Error generating list." delegate:self cancelButtonTitle:#"Ok!" otherButtonTitles:nil];
[supported show];
[supported release];
}
}
Any idea how I'd have the NSTask finish before invoking the alert? Thanks.
Edit: Code with NSNotification:
-(IBAction) supported {
stask = [[NSTask alloc] init];
[stask setLaunchPath:#"/bin/bash"];
NSString *script;
script = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:#"/apps.sh"];
NSArray *sargs = [NSArray arrayWithObjects:script, #"-txt", nil];
[stask setArguments: sargs];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(taskEnded:)
name: NSTaskDidTerminateNotification
object: nil];
[stask launch];
}
- (void)taskEnded:(NSNotification *)notification {
if (stask == [[notification object] terminationStatus]) {
NSString *apps;
apps = [NSString stringWithContentsOfFile:#"/var/mobile/supported.txt" encoding:NSUTF8StringEncoding error:nil];
NSFileManager *fm = [NSFileManager defaultManager];
if ([fm fileExistsAtPath:apps]) {
UIAlertView *supported = [[UIAlertView alloc] initWithTitle:#"Apps" message:apps delegate:self cancelButtonTitle:#"Ok!" otherButtonTitles:nil];
[supported show];
[supported release];
} else {
UIAlertView *supported = [[UIAlertView alloc] initWithTitle:#"Apps" message:#"Error generating list." delegate:self cancelButtonTitle:#"Ok!" otherButtonTitles:nil];
[supported show];
[supported release];
}
} else {
NSLog(#"Task failed.");
}
}
Don't use waitUntilExit.
The problem is how to do something after the task finishes without blocking the UI (or freezing that one button). The solution, as for all similar problems, is to be notified when the task finishes, and proceed further (show the alert) in response to that notification.
The notification, in this case, is an NSNotification named NSTaskDidTerminateNotification. When the task exits, for any reason, the NSTask object will post this notification on the default NSNotificationCenter. You can ask the task what its termination status was to determine whether it succeeded, failed, or crashed.
See also: Notification Programming Topics.
Have a look at AMShellWrapper which is based on Apple's Moriarity sample code.
"Connect your own methods to stdout and stderr, get notified on process termination and more."
See: http://www.cocoadev.com/index.pl?NSTask
Don't use waitUntilExit on your main thread. That will block your UI, and freeze your app.
You need to subscribe to the notification NSTaskDidTerminateNotification, which is posted when the task has stopped execution:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(taskDidTerminate:)
name:NSTaskDidTerminateNotification
object:nil];
Note that the notification can be posted if the task completed normally, or as the result of a terminate message:
- (void) taskDidTerminate:(NSNotification *)notification {
if (YOUR_TASK_SUCCESS_VALUE == [[notification object] terminationStatus]) {
NSLog(#"Task succeeded.");
// Here you can add your checks on the creation on the files and user alerts confirmation
} else {
NSLog(#"Task failed.");
}
}
Don't forget to unsubscribe to the notification ; depending on where you subscribe to the notification, a good place would be in your dealloc method:
[[NSNotificationCenter defaultCenter] removeObserver:self];
Update: You expect something that is documented on Mac to work the same on iOS, where it is not documented. Not really surprised it doesn't work.
Have you tried to execute the task - and use the waitUntilExit method - in a background thread?
If you are lucky and it works, don't forget to switch back to the main thread when showing your UIAlert.