How do you change your presence to show dnd/away and etc.?
XMPPPresence *presence = [XMPPPresence presenceWithType:status];
[[[self appDelegate] xmppStream] sendElement:presence];
status is an NSString that I set to online/unavailable/away/busy/invisible.
It only works when I go online and/or unavailable.
Here's how it looks like after sending presence in my xmppStream:
<presence type="away"><x xmlns="vcard-temp:x:update"><photo/></x></presence>
To change the status of your client you will need to use this simple code:
XMPPPresence *presence = [XMPPPresence presence];
NSXMLElement *status = [NSXMLElement elementWithName:#"status"];
[status setStringValue:#"online/unavailable/away/busy/invisible"];
[presence addChild:status];
[[self xmppStream] sendElement:presence];
This simply means that the key to change the status of your client is by adding a status element to your presence. Please note that the openfire server will only show the "available/Offline" status when you hover on the user icon in the admin panel. This should not confuse you though. You can simply check the presence message sent by your client and received by the others which will show on of the status you have set ("online/unavailable/away/busy/invisible").
On top of the answer above, there is also a <show> element that should be used in conjunction with the <status> element. By using both elements, you can customize user's presence for each availability states.
Default: Available / Offline
By using <show>: Available / Busy / Away / Extended Away / Offline
By using <show> with <status>: "Free to chat" / "Hard at work" / "In a meeting" / "Out for lunch".
If you use Openfire with this method: In User Sessions > Presence column, you will see:
Different colored icons for each user (e.g. green for available, red for busy, etc.)
A descriptive text beside the icons (e.g. "In a meeting")
Presence child elements
There are 3 elements that can change types of presence in XMPP.
<show/>
<status/>
<priority/> (we'll exclude this for discussion)
Show
<show> specifies an availability status of a user.
Values of the element must be specified according to the list below.
"chat" -- user is actively interested in chatting.
"dnd" -- user is busy (dnd a.k.a 'Do Not Disturb').
"away" -- user is temporarily away.
"xa" -- user is away for an extended period (xa a.k.a. 'eXtended Away').
If this element is not provided, user is assumed to only be either online and available.
Status
<status> describes the availability status of a user. It is usually used in conjunction with the <show> element to provide a detailed description of an availability state.
Values of the element can be of any descriptive text. For instance:
"Available to chat" -- can be used for "chat"
"Busy at work" -- can be used for "dnd"
"In a meeting" -- can be used for "away"
"On a vacation" -- can be used for "xa"
Usage in Objective-C
Here's how you should apply the above concept in code.
// Initialize variables
XMPPPresence *presence = [XMPPPresence presence];
NSXMLElement *show = [NSXMLElement elementWithName:#"show"];
NSXMLElement *status = [NSXMLElement elementWithName:#"status"];
// If user is available
[show setStringValue:#"chat"];
[status setStringValue:#"Available to chat"];
// If user is busy
[show setStringValue:#"dnd"];
[status setStringValue:#"Busy at work"];
// If user is away
[show setStringValue:#"away"];
[status setStringValue:#"In a meeting"];
// If user is away for a long period of time
[show setStringValue:#"xa"];
[status setStringValue:#"On a vacation"];
// Add the XML child elements to XMPPPresence
[presence addChild:show];
[presence addChild:status];
// Update new presence to server
[[[self appDelegate] xmppStream] sendElement:presence];
There you go, your customized user's presence will now be accurately reflected in your server.
See also: Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence
For Swift 5 and above
You can send to status any user
let presence = XMPPPresence(show: XMPPPresence.ShowType(rawValue: XMPPPresence.ShowType.away.rawValue) , status: "I'm working")
stream.send(presence)
and You can listen to all status with above methods
class LastStatus {
var username :String
var lastStatus : String
internal init(username: String, lastStatus: String) {
self.username = username
self.lastStatus = lastStatus
}
}
var lastStatusList : [LastStatus] = []
func xmppStream(_ sender: XMPPStream, didReceive presence: XMPPPresence) {
guard let fromUser = presenceFrom.user else {return}
if presence.showType == XMPPPresence.ShowType.init(rawValue: "away") {
if let status = presence.status {
if lastStatusList.firstIndex(where: { $0.username == fromUser}) == nil {
let userStatus = LastStatus(username: fromUser , lastStatus: status)
lastStatusList.append(userStatus)
} else {
let index = lastStatusList.firstIndex(where: { $0.username == fromUser})!
let changing = lastStatusList[index]
changing.lastStatus = status
}
}
}
}
Related
I've been incorporating NEHotspotHelper into my app that manages a captive network, but I'm having multiple issues. I'm not receiving an Authentication Command (kNEHotspotHelperCommandTypeAuthenticate) after my network that is set with a high level of confidence is in the Evaluating State. Also, my WISPr network is never receiving an Evaluate Command( kNEHotspotHelperCommandTypeEvaluate) when the SSID is selected in the Wi-Fi list in Settings. My goal for the WISPr Hotspot is to send a UINotification requiring a user action. ANyone know what I'm missing as far as not receiving kNEHotspotHelperCommandTypeAuthenticate & kNEHotspotHelperCommandTypeEvaluate in the two situations?
I set up HotspotHelper registerWithOptions in my app delegate as such:
NSMutableDictionary* options = [[NSMutableDictionary alloc] init];
[options setObject:#"Hotspot" forKey:kNEHotspotHelperOptionDisplayName];/
dispatch_queue_t queue = dispatch_queue_create("com.myapp.ex", 0);
BOOL returnType = [NEHotspotHelper registerWithOptions:options queue:queue handler: ^(NEHotspotHelperCommand * cmd) {
NEHotspotNetwork* network;
NSLog(#"COMMAND TYPE: %ld", (long)cmd.commandType);
if (cmd.commandType == kNEHotspotHelperCommandTypeEvaluate || cmd.commandType ==kNEHotspotHelperCommandTypeFilterScanList) {
for (network in cmd.networkList) {
NSLog(#"COMMAND TYPE After: %ld", (long)cmd.commandType);
if ([network.SSID isEqualToString:#"test-WPA-2"]|| [network.SSID isEqualToString:#"WISPr Hotspot"]) {
double signalStrength = network.signalStrength;
NSLog(#"Signal Strength: %f", signalStrength);
[network setConfidence:kNEHotspotHelperConfidenceHigh];
[network setPassword:#"myPassword"];
NEHotspotHelperResponse *response = [cmd createResponse:kNEHotspotHelperResultSuccess];
NSLog(#"Response CMD %#", response);
[response setNetworkList:#[network]];
[response setNetwork:network];
[response deliver];
}
}
}
}];
The first mistake I made in the code above: I was expecting the command type Evaluate to enumerate through the network list. However, the Evaluate command is actually looking to be delivered the connected network. I get the current network with the following code:
NSArray *array = [NEHotspotHelper supportedNetworkInterfaces];
NEHotspotNetwork *connectedNetwork = [array lastObject];
NSLog(#"supported Network Interface: %#", connectedNetwork);
Then check to see if the connected list matches my SSID, if so I set the confidence level of this network and deliver the response to Evaluate:
[connectedNetwork setConfidence:kNEHotspotHelperConfidenceLow];
//[response setNetworkList:#[network]];
[response setNetwork:connectedNetwork];
[response deliver];
The next command the handler is given is Authenticate. My complete code looks as following, I am still working on processing the commands after authenticate. The complete code line is:
BOOL returnType = [NEHotspotHelper registerWithOptions:options queue:queue handler: ^(NEHotspotHelperCommand * cmd) {
NEHotspotNetwork* network;
if (cmd.commandType ==kNEHotspotHelperCommandTypeFilterScanList) {
for (network in cmd.networkList) {
//need to check against list of directories
if ([network.SSID isEqualToString:#"test-WPA-2"]) {
NSLog(#"%#", network.SSID);
NSLog(#"SSID is in Directory: %#", network.SSID);
double signalStrength = network.signalStrength;
NSLog(#"Signal Strength: %f", signalStrength);
[network setConfidence:kNEHotspotHelperConfidenceLow];
[network setPassword:#"password"];
NEHotspotHelperResponse *response = [cmd createResponse:kNEHotspotHelperResultSuccess];
NSLog(#"Response CMD %#", response);
[response setNetworkList:#[network]];
[response setNetwork:network];
[response deliver];
}
}
}
if (cmd.commandType == kNEHotspotHelperCommandTypeEvaluate) {
/* * When a network is joined initially, the state machine enters
* the Evaluating state. In that state, each HotspotHelper receives a
* command of type Evaluate. If one or more helpers indicates that it
* is able to handle the network, the one with the highest confidence
* level is chosen before entering the Authenticating state. As an
* optimization, the first helper to assert a high confidence wins and
* the state machine ignores the other helpers.
*
* If no helpers claim the network, the state machine enters the
* Authenticated state.
*/
NSArray *array = [NEHotspotHelper supportedNetworkInterfaces];
NEHotspotNetwork *connectedNetwork = [array lastObject];
NSLog(#"supported Network Interface: %#", connectedNetwork);
NEHotspotHelperResponse *response = [cmd createResponse:kNEHotspotHelperResultSuccess];
NSLog(#"Response CMD %#", response);
[connectedNetwork setConfidence:kNEHotspotHelperConfidenceLow];
//[response setNetworkList:#[network]];
[response setNetwork:connectedNetwork];
[response deliver];
}
if (cmd.commandType == kNEHotspotHelperCommandTypeAuthenticate) {
NSLog(#"COMMAND TYPE In Auth ***********: %ld \n\n\n\n\n\n", (long)cmd.commandType);
/*
* In the Authenticating state, the chosen helper is given a command of type
* Authenticate. The helper is expected to perform whatever network
* processing is required to make the network available for general
* network traffic. If the authentication is successful, the helper
* indicates that with a Success result. The state machine enters the
* Authenticated state.
*
* On a network that has been authenticated by a helper, the state machine
* enters the Maintaining state when the network is joined again, and also
* periodically while the system remains associated with the network. In the
* Maintaining state, the helper is expected to perform whatever network
* operations are required to determine if the network is still able to
* carry general network traffic. If that is the case, the helper returns
* Success. If not, and authentication is again required, it returns
* AuthenticationRequired to cause the state machine to re-enter the
* Authenticating state.
*
* In the Authenticating state, if the helper determines that it requires
* user interaction to proceed, the helper first arranges to alert
* the user via a UserLocalNotification, then returns a result of
* UIRequired. The state machine enters the PresentingUI state.*/
}
if (cmd.commandType == kNEHotspotHelperCommandTypePresentUI) {
NSLog(#"COMMAND TYPE In Present UI ***********: %ld \n\n\n\n\n\n", (long)cmd.commandType);
}
}];
I am currently using the PFUser method ' signUpInBackgroundWithBlock: ' to sign up my users, but constraints on my UX mean that i can't sign them up on the same ViewController, hence I'm trying to validate the email before calling that method on a PFUser Parse object.
The alternative is to send my users back to earlier view controllers if parse gives me an error back after method call (which I do not want to do)
I have found this Regex pattern, but this is quite an old answer and I know fancier domains have been out since are now out:
https://www.parse.com/questions/email-validation-rules-for-pfsignupviewcontroller
"The alternative is to send my users back to earlier view controllers if parse gives me an error back after method call (which I do not want to do)"
Note - Unfortunately, you simply won't be able to build parse apps unless you "send them back" like that. Unfortunately "it's that simple." Quite literally every single such "step" when dealing with Parse, you have to be able to "go back" in the sense you describe.
In answer to your question, as you probably know essentially THERE IS NO really good way to truly check if a string is an email, due to various problems with the nature of defining an email, and the fact that you simply don't actually want the full set of "really possible" email strings, for any app.
In practice the following category works well.
It's in use in many high volume production apps.
Note that NSPredicate is, I feel, the most natural, reliable way to do this in iOS.
-(BOOL)basicLocalEmailCheck
{
if ( self.length > 50 ) return NO;
// note, first if it ends with a dot and one letter - that is no good
// (the regex below from W3C does allow a final single-letter tld)
NSString *rx = #".*\\..$";
NSPredicate *emailTest = [NSPredicate
predicateWithFormat:#"SELF MATCHES %#", rx];
if ( [emailTest evaluateWithObject:self] ) return NO;
// here's the original from the W3C HTML5 spec....
// ^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+#[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$
// i made a modification,
// you can't have eg "localhost" with no .com,
// and note you have to escape one backslash for the string from the W3C
rx = #"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+#[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?){1,5}$";
emailTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", rx];
return [emailTest evaluateWithObject:self];
}
If you are a beginner and not familiar with categories, it's a good opportunity to use one.
Here are some typical real-world uses...particularly relating to Parse since you mention that.
-(IBAction)joinNow
{
[self.view endEditing:YES];
if ( [self _fieldBlank] )
{ [self woe:#"Please complete all fields."]; return; }
if ( ! [self.email.text basicLocalEmailCheck] )
{ [self woe:#"Please enter a valid email."]; return; }
if ( self.imageHasBeenSet == NO )
{ [self woe:#"Please add a picture."]; return; }
if ( self.password.text.length > 20 ||
self.firstname.text.length > 20 ||
self.surname.text.length > 20 )
{ [self woe:#"20 character limit for names and password."]; return; }
[self ageConfirmThenJoin];
}
-(IBAction)clickLogin:(id)sender
{
[self.view endEditing:YES];
[PFUser logOut];
if ( ! [self.loginEmail.text basicLocalEmailCheck] )
{
[UIAlertView ok:#"Please enter your email in the email field."];
[self begin];
return;
}
[APP huddie];
APP.hud.labelText = #"Logging in ...";
[PFAnalytics trackEvent:#"loginAttempt"];
[PFUser logInWithUsernameInBackground: [self.loginEmail.text lowercaseString]
password: self.loginPassword.text
block:^(PFUser* user, NSError* error)
{
[APP.hud hide:YES];
if (user) // Login successful
{
[PFAnalytics trackEvent:#"loginSuccess"];
[self isLoggedInCheckValid];
return;
}
else
{
// note, with Parse it SEEMS TO BE THE CASE that
// 100, no connection 101, bad user/pass
NSString *msg;
NSString *analyticsMsg = #"otherProblem";
if ( !error)
{
msg = #"Could not connect. Try again later...";
// seems unlikely/impossible this could happen
}
else
{
if ( [error code] == 101 )
{
msg = #"Incorrect email or password. Please try again.";
analyticsMsg = #"passwordWrong";
}
else
{
msg = #"Could not connect. Try again later.";
}
}
[PFAnalytics trackEvent:#"loginFailure"
dimensions:#{ #"reason":analyticsMsg }];
[UIAlertView ok:msg];
[self begin]; // not much else we can do
return;
}
}];
}
If you are after a regular expression, then you could take a look here and here for some solutions.
That being said, if you truly want to ensure that the user has provided you with a valid, active email account you should simply do some very basic validation (see it contains the # character for instance) and then simply send a mail with a link to activate the account.
The regular expressions linked to the answers provided aren't exactly user friendly. To add insult to injury, users can still provide you with bogus email addresses. It might also be the case where an edge case scenario email address fails the verification, thus according to your site the user won't be able to sign up.
I'm trying to read the label of a particular instant message service in the address book. In this case I'm testing with the Facebook Messenger service, on my phone. The contact has linked contacts, but only one recorded instant message service.
I tried to find info on how ABMultiValueCopyLabelAtIndex works, but all I found was that it "may return null". If there's no visible label in the address book then yeah, I understand why it would return null. In this case however there is a label, and it reads "Facebook Messenger" in the person view. I still get null, why?
- (BOOL)personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)personRecord property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue
{
// all IM services:
ABMultiValueRef instantMessageProperty = ABRecordCopyValue(personRecord, property);
// one particular IM service:
CFDictionaryRef instantMessageDict = ABMultiValueCopyValueAtIndex(instantMessageProperty, ABMultiValueGetIndexForIdentifier(instantMessageProperty, identifierForValue));
// its name:
NSString *serviceName = (__bridge NSString*)CFDictionaryGetValue(instantMessageDict, kABPersonInstantMessageServiceKey);
// its label:
NSString *serviceLabel = (__bridge_transfer NSString*)ABMultiValueCopyLabelAtIndex(instantMessageProperty, ABMultiValueGetIndexForIdentifier(instantMessageProperty, identifierForValue));
NSLog(serviceName); // logs "Facebook", so things seem to work
NSLog(serviceLabel); // logs nothing, and I confirmed that serviceLabel == nil
[...]
}
I am trying to implement an Instant Messaging App where users can chat as well as add other users to their roster and accept buddy requests. So, far I have been able to implement the chat and I am also able to receive and accept/reject friend requests.
For accepting/rejecting a subscription request, the code is as follows:
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
{
NSString *presenceType = [presence type]; // online / offline
NSString *myUsername = [[sender myJID] user];
NSString *presenceFromUser = [[presence from] user];
NSString *presencefromStr=[presence fromStr];
if ([presenceType isEqualToString:#"subscribe"]) {
if(buttonIndex==1) { // For accept button
[xmppRoster acceptPresenceSubscriptionRequestFrom:[tmpPresence from] andAddToRoster:YES];
}
else { // For reject button
[xmppRoster rejectPresenceSubscriptionRequestFrom:[tmpPresence from]];
}
}
However, now I am stuck with the problem of not being able to send a friend request. Can anyone guide me on which function of XMPPRoster to use? I tried using the subscribePresenceToUser function, but, it didn't work. Any help will be highly appreciated.
Also, can someone tell if the way I am going with this XMPPRoster subscription mechanism is right or is there a better way to handle the friend requests in XMPPFramework?
Thanks in advance.
Answer by OP in comment:
XMPPJID *jid = [XMPPJID jidWithString:self.addFriendField.text];
[xmppRoster addUser:jid withNickname:nil];
This code snippet sends the request to other users and adds them to their Roster.
You can see XMPPRoster.h to see all the functions available inside the roster extension.
For your answer you have three options:
/**
* Adds the given user to the roster with an optional nickname
* and requests permission to receive presence information from them.
**/
- (void)addUser:(XMPPJID *)jid withNickname:(nullable NSString *)optionalName;
/**
* Adds the given user to the roster with an optional nickname,
* adds the given user to groups
* and requests permission to receive presence information from them.
**/
- (void)addUser:(XMPPJID *)jid withNickname:(nullable NSString *)optionalName groups:(nullable NSArray<NSString*> *)groups;
/**
* Adds the given user to the roster with an optional nickname,
* adds the given user to groups
* and optionally requests permission to receive presence information from them.
**/
- (void)addUser:(XMPPJID *)jid withNickname:(nullable NSString *)optionalName groups:(nullable NSArray<NSString*> *)groups subscribeToPresence:(BOOL)subscribe;
And to accept the friend request : (add as friend, as Fan or Decline)
addToRoster flag = true : Friend
addToRoster flag = false : Fan
/**
* Accepts the presence subscription request the given user.
*
* If you also choose, you can add the user to your roster.
* Doing so is similar to the traditional IM model.
**/
- (void)acceptPresenceSubscriptionRequestFrom:(XMPPJID *)jid andAddToRoster:(BOOL)flag;
/**
* Rejects the presence subscription request from the given user.
*
* If you are already subscribed to the given user's presence,
* rejecting they subscription request will not affect your subscription to their presence.
**/
- (void)rejectPresenceSubscriptionRequestFrom:(XMPPJID *)jid;
I have an app in which the user uploads a video to youtube. I have the user input their password and username to sign in and then they input the "title", "description", "tags", "category", and "privacy setting" i.e. public, private, unlisted. All works well. However I am not able to verify that the password for the given username is valid or even if the username is valid. When the password and username are filled in and the "sign in" button is tapped these are saved into the documents directory as password.txt and username.txt. Then these are used to complete the process and in fact loaded from the documents directory upon subsequent uploads until the user signs out, in which case the files are removed.
My problem is I would like to check with YouTube when the user fills in the password and username and goes to save them to make sure they are valid. Can someone help me with this.
This is the code I use to input the username and password as well as developers key to YouTube to get a service to allow uploading video.
- (GDataServiceGoogleYouTube *)youTubeService {
static GDataServiceGoogleYouTube* service = nil;
if (!service) {
service = [[GDataServiceGoogleYouTube alloc] init];
[service setShouldCacheResponseData:YES];
[service setServiceShouldFollowNextLinks:YES];
[service setIsServiceRetryEnabled:YES];
/*[service setUserCredentialsWithUsername:accountView.text password:PasswordDisplayField.text];*/
}
NSString *username = [accountView.text retain];
NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
accountView.text = [username stringByTrimmingCharactersInSet:whitespace];
/*if ([accountView.text rangeOfString:#"#"].location == NSNotFound)
{ accountView.text = [kYoutubeUsername stringByAppendingString:#"#gmail.com"]; }*/
if (([accountView.text length] > 0) && ([PasswordDisplayField.text length] > 0))
{ [service setUserCredentialsWithUsername:[accountView.text retain] password:[PasswordDisplayField.text retain]]; }
else
{ [service setUserCredentialsWithUsername:nil password:nil]; }
[service setYouTubeDeveloperKey:devKey];
return service;
}
and then I use this code to get the URL for uploading
NSURL *url = [GDataServiceGoogleYouTube youTubeUploadURLForUserID:kGDataServiceDefaultUser];
but I am not sure how to use these to check to see if the username and password are matched and compatible and return an error message is they are not . Also I don't want to save them if they are not correct.
If someone can suggest a solution, a tutorial, video or something else to help me accomplish this I would greatly appreciate it.
Thanks
I would strongly suggest moving to OAuth 2 using the Objective-C client library:
http://code.google.com/p/gdata-objectivec-client/
http://code.google.com/p/gtm-oauth2/
As a user of your application, I'd feel awful knowing that you were storing my Google Account address and password in clear text like that. Please, switch to OAuth 2.