XMPPFramework - Auto Accept of Presence Subscription Requests - ios

I think the title is illustrating enough, but here's the story:
I'm new to XMPPFramework for iOS, and I want to set my client to automatically accept any subscription request it receives. So that other clients can see this client's presence status, when they request it.
According to developer comments In XMPPRoster.h file, there's this method which is called when a subscription request is received:
/**
* Sent when a presence subscription request is received.
* That is, another user has added you to their roster,
* and is requesting permission to receive presence broadcasts that you send.
*
* The entire presence packet is provided for proper extensibility.
* You can use [presence from] to get the JID of the user who sent the request.
*
* The methods acceptPresenceSubscriptionRequestFrom: and rejectPresenceSubscriptionRequestFrom: can
* be used to respond to the request.
**/
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence;
But it is not implemented in XMPPRoster.m. So I implemented it as following :
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence
{
[self acceptPresenceSubscriptionRequestFrom:[presence from] andAddToRoster:YES];
}
Since I'm new to XMPPFramework I dunno if I have done anything wrong, but I still cannot get this client's presence in other clients.
I also have seen similar topics like Accept buddy request in xmpp client iphone or Xmpp Accepting buddy request but the solution does not seem to be even related !
Any suggestions is really appreciated.
Thanks.

You did it wrong. You do not have to implement something in XMPPRoster.m or other library files.
This function
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence;
is a callback fired when your xmpp client receives presence subscription request. If you want to execute some code when this callback fired you have to implement a protocol called XMPPRosterDelegate. Protocol is a feature like interface in Java and C# or like abstract class in C++. You have to have a class that inherits from this XMPPRosterDelegate and finally implements this function (and other functions if you want so).
If you want to autoaccept all requests you have to implement your protocol function implementation like this:
-(void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence{
[sender acceptPresenceSubscriptionRequestFrom:[presence from] andAddToRoster:YES];
}
Also roster object got to know who is its delegate (an object who implements XMPPRosterDelegate), cause if you want to send someone a message you have to know two things: target and selector. Selector is specified in protocol. Target is a delegate property. You have to set roster's delegate during its initialization. In my code I added line
[xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
before line
[xmppRoster activate:xmppStream];
Of course self implements XMPPRosterDelegate and especially has this piece of code
-(void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence{
[sender acceptPresenceSubscriptionRequestFrom:[presence from] andAddToRoster:YES];
}
Good luck and sorry for long post.

Related

The right approach to keep users sessions

I’m developing an app that uses external API and requires authentication through oauth2. In the response from api I get access token, refresh token and time in which token will expire. Everything is just fine until the time expire. So far before sending a request i check whether access token is valid:
if ([[AppCredentials sharedCredentials]tokenIsValid]) {
BackEnd *backendPUT = [[BackEnd alloc]init];
[backendPUT setDelegate:self];
[backendPUT updateMenuInDiary:menuDietyDoUpdate forDate:[[DziennikDietaModel sharedDziennikDietaModel]getwybranaDate] mealID:[menuDietyDoUpdate objectForKey:#"id"]];
monitor = [[UICustomLoadingMonitor alloc]initWithDefaultOptionsInView:[self view]];
[monitor start];
}else{
[[AppCredentials sharedCredentials] getAppTokenFromRefreshedToken];
}
when getAppTokenFromRefreshedToken is finished, method userTokenDownloaded is called using delegate.
The question is: how can I go back to that certain code which could not be executed in the first part of the if statement? Everything is asynchronous that is why i’ve got a problem.
In my view controller there are couple of methods that sends different requests to api and I need to differentiate which one needs to be called again.
What would be the right approach to this? closures ?
ok. solved it with blocks :) in the case someone was looking for an answer that is how i've done it:
BackEnd *backEnd = [[BackEnd alloc]init];
[backEnd setDelegate:self];
if ([[AppCredentials sharedCredentials]tokenIsValid]) {
NSLog(#"TOKEN VALID NO BLOCKS");
[backEnd updateMenuInDiary:menuDietyDoUpdate];
}else{
NSLog(#"USING BLOCKS");
[backEnd getAppTokenFromRefreshToken:refreshedToken withCompletionBlock:^{
NSLog(#"ponowna proba z bloku");
[backEnd updateMenuInDiary:menuDietyDoUpdate];
}];
}
works great :)

Best way to check if sharing via SLComposeViewController is successful with a limited (or no) Internet connection

Apple's documentation is clear on using SLComposeViewController to provide sharing capabilites with other social networks such as Twitter and Facebook.
Typical code will use isAvailableForServiceType to verify if a particular service is available and then add a completion handler to the view controller where an SLComposeViewControllerResult can be checked for either SLComposeViewControllerResultCancelled or SLComposeViewControllerResultDone, which check if the user tapped on the 'Post' button or on the 'Cancel' button after the sharing view has been displayed.
The issue here is that if you use SLComposeViewControllerResultDone to validate that the user made the request, you don't actually check if it was successful such as when the user has limited or no connectivity.
I have tried with one of my apps to test this and have noticed that the SLComposeViewControllerResultDone constant is still valid even if airplane mode is turned on such that a request is not possible. What this means is that the user fills out the sharing view fields and taps on 'Post' and my success code executes even though I should really be checking to make sure that the post was indeed successful.
Currently, I figure that the best option is to check for an Internet connection using the standard Reachability options (as recommended here) and disable the sharing button if a connection is not available, but I'm not sure if this is the best solution as it doesn't account for a limited connection where the user can tap on 'Post' but the actual request is unsuccessful.
My question is what is the best method of detecting if a sharing request has successfully completed?
then you need to make sure that you do not write below line in didSelectPost
[self.extensionContext completeRequestReturningItems:nil completionHandler:nil];
and once you get success or fail based on that in the your request handler you can write above line, so your didSelectPost should be like :
- (void)didSelectPost {
NSExtensionItem *inputItem = self.extensionContext.inputItems.firstObject;
NSItemProvider *attachment = inputItem.attachments.firstObject;
if ([attachment hasItemConformingToTypeIdentifier:#"public.url"])
{
//NSString *strLink = [attachement loadItemForTypeIdentifier:#"public.url" options:nil completionHandler:nil];
[attachment loadItemForTypeIdentifier: #"public.url"
options: nil
// make your request here
}];
}
}

Authenticating with ReactiveCocoa

I'm building an app on top of ReactiveCocoa and Octokit.objC (github library). As part of my effort I'm using Octokits ReactiveCocoa signals to access resources that require authentication. A previous question 'Retrying an asynchronous operation using ReactiveCocoa' does a nice job covering the case where the user wants to 'retry an asynchronous operation' once. I'm trying to figure out how to handle the case where you might want to retry several times.
In my specific case if authentication fails I want to go ask the user for their credentials. I'll either ask the user for their credentials a few times (2 or 3) and then halt if they fail or I'll just keep asking them for their credentials until they succeed.
Any help would be appreciated. Thanks - AYAL
There is an operator called -retry: which accepts a count parameter. If you apply this operator to a signal, and that signal returns an error, it will re-subscribe to the signal (up to the specified number of times) when the error is received. So what you need is a signal that, when subscribed to, prompts the user for credentials.
#weakify(self);
RACSignal *requestCredentials = [RACSignal defer:^{
#strongify(self);
// (Prompt the user for credentials.)
if (successful)
{
self.cachedCredentials = credentials;
return [self authenticate:credentials];
}
else
{
return [RACSignal error:[[MyError alloc] init]];
}
}];
// We try to authenticate using the cached credentials (the
// `-authenticate:` method returns a signal that attempts
// authentication when it is subscribed to). If the initial
// attempt to authenticate fails, we try 3 times to get the
// user to enter the correct credentials.
return [[self authenticate:self.cachedCredentials]
catchTo:[requestCredentials retry:3]];

iOS XMPP Framework, how to handle wrong credential?

All the codes I use are from https://github.com/robbiehanson/XMPPFramework. Inside the sample code.
In my iOS7 messaging app, I invoke the "connect" function inside XMPP Framework after the user has entered their login credential and clicked the "login" button. The connect function works fine if they entered the correct credentials the first time, but would not work if the user entered the wrong credential. Because this very first line inside connect would simply return TRUE:
if (![_xmppStream isDisconnected]) {
return YES;
}
Which means any further presses on the login button would do nothing.
Should I manually invoke authenticateWithPassword? Is this the right practice assuming a connection between the client and the server has been setup?
Thank you.
You need to use the methods in the delegate to handle authentication. First you need to connect to the server if it's not already connected:
[_xmppStream connectWithTimeout:10 error:&error];
Once the stream is connected to the server the delegate method will be invoked:
- (void)xmppStreamDidConnect:(XMPPStream *)sender;
Inside that method, you can call authenticateWithPassword. If the stream was previously connected (would be the else part of the if you posted) you can just call authenticateWithPassword.
If authentication fails, the following delegate method is called:
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error;
There you can decide to show a message to the user and start over. If authentication succeeds, the following method is called:
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender;

Switch between different API hosts

I'm working on an app which primarily works with an API that will be installed in an internal system. The API is also accessible via the public internet. The client wants to allow users to enter both an internal and external (public internet) URL that the app will then connect to depending on availability of the internal and external URLs.
The app is basically done with the exception that it currently connects to the internal URL only for all it's API calls. I'm using AFNetworking with block-based completion/failure invocations for each API call.
Based on the logic that we have designed, the app will always check for the API's availability by querying for the server's current time. This is done by calling http://internal_url/api/time. If this API fails to return an appropriate respond, we'll switch to the external URL http://external_url/api/time and call the same API on that URL. If both fails, the app will inform the user accordingly and not perform any other queries to the API.
Without revealing too much, here's some code on how I the API calls are currently setup:
- (void)someAPIMethodCall:(NSDictionary *)parameters completionBlock:block failure:block {
// query /api/time and return the URL (internal/external) that is currently up
AFHTTPClient *client = [AFHTTPClient clientWithBaseURL:<url returned from above query>];
[client operationWithSuccess:block failure:block];
}
So my question would be: what is the best way to get the query /api/time method above to work? Obviously, this method needs to complete and return either the internal/external URL so that the subsequent actual API query could use. AFAIK, AFNetworking calls are block-based so it will return before the above /api/time returns. I've also thought of a separate class that uses NSURLConnection synchronously which will block the main-thread while it waits for the /api/time to return.
I'd like to tell you to simply use the same URL internally and externally (via DNS) but that's not what you want.
I think you're asking how to conditionally call the other url.
You want someAPIMethodCall to be asynchronous... so you don't want to block on the call to checking for the correct api to call.
Aside from caching the results so you don't have to do this every time, you simply want to call another block based method of your own that has a completion block which passes IN a parameter of the URL to call for your real query.
- (void)someAPIMethodCall:(NSDictionary *)parameters completionBlock:(void (^)(void))succesBlock failure((^)(void)):failureBlock {
[self callBlockWithMyApiUrl:^(NSString *apiUrl){
AFHTTPClient *client = [AFHTTPClient clientWithBaseURL:apiUrl];
[client operationWithSuccess:successBlock failure:failureBlock];
} onFailure:^{
failureBlock
}
}
- (NSString *)callBlockWithMyApiUrl:(NSString * (^)(void))success (void (^)(void))failure
{
// Your code to test for the working URI
// If you're doing it this way, I'd suggest caching the result.
// Subscribe to networking interface changes to dump the cache.
}

Resources