I am trying to acquire token Interactively for multiple scopes, Policy and RMS scopes using Objective C. I am not sure whether I am doing it right or wrong, the way I am trying to get it as below.
I have written a method "aquireToken" where I am calling the function twice one for Policy scope and other RMS scope and updating result in NSDictionary.
There is a flag which is being updated inside the "completionBlock = ^(MSALResult *result, NSError *error)". But its value is not reflected in the caller "aquireToken" function.
The code snippet is as below:
- (void) aquireToken
{
policyTokenResult = false;
rmsTokenResult = false;
NSError *error = nil;
MSALPublicClientApplication *application = [self createPublicClientApplication:&error];
[self retrieveTokens:application forScopes:scopesPolicy isPolicy:true];
if (policyTokenResult)
{
[self retrieveTokens:application forScopes:scopesRMS isPolicy:false];
}
for (NSString* key in resultMap) {
id value = resultMap[key];
// id object = [resultDict objectForKey:key];
NSLog(#"%# = %#", key, value);
// do stuff
}
}
- (void)retrieveTokens:(MSALPublicClientApplication*) application
forScopes: (NSArray<NSString *> *) scopes
isPolicy: (BOOL) isPolicy
{
NSError *error = nil;
MSALAccount* userAccount = nil;
for (MSALAccount *account in [application allAccounts:&error])
{
if([[account.username uppercaseString] isEqualToString:[authID uppercaseString]])
{
NSLog(#"Account Found: \t%#", account.username);
userAccount = account;
break;
}
}
MSALCompletionBlock completionBlock;
__block __weak MSALCompletionBlock weakCompletionBlock;
weakCompletionBlock = completionBlock = ^(MSALResult *result, NSError *error)
{
dispatch_async(dispatch_get_main_queue(), ^{
if (!error)
{
if (isPolicy)
{
[resultMap setObject:result.accessToken forKey:#"PolicyAccessToken"];
[resultMap setObject:result.account.username forKey:#"UserId"];
authID = result.account.username;
policyTokenResult = true;
}
else
{
[resultMap setObject:result.accessToken forKey:#"RMSAccessToken"];
rmsTokenResult = true;
}
if(policyTokenResult && rmsTokenResult)
{
[resultMap setObject:#"" forKey:#"ResultStatusSuccess"];
}
return;
}
if ([error.domain isEqualToString:MSALErrorDomain] && error.code == MSALErrorInteractionRequired)
{
[self acquireTokenInteractive:application scopes:scopes isPolicy:isPolicy completionBlock:weakCompletionBlock];
return;
}
});
};
if(userAccount)
{
[self acquireTokenSilent:application scopes:scopes forAccount:userAccount isPolicy:isPolicy completionBlock:completionBlock];
}
else
{
[self acquireTokenInteractive:application scopes:scopes isPolicy:isPolicy completionBlock:completionBlock];
}
}
- (void) acquireTokenSilent: (MSALPublicClientApplication *) application
scopes: (NSArray<NSString *> *) scopes
forAccount: (MSALAccount *) userAccount
isPolicy: (BOOL) isPolicy
completionBlock: (MSALCompletionBlock) completionBlock
{
MSALSilentTokenParameters *silentParams = [[MSALSilentTokenParameters alloc] initWithScopes:scopes account:userAccount];
[application acquireTokenSilentWithParameters:silentParams completionBlock:completionBlock];
}
- (void) acquireTokenInteractive: (MSALPublicClientApplication *) application
scopes: (NSArray<NSString *> *) scopes
isPolicy: (BOOL) isPolicy
completionBlock: (MSALCompletionBlock)completionBlock
{
MSALInteractiveTokenParameters *interactiveParams = [[MSALInteractiveTokenParameters alloc] initWithScopes:scopes];
[interactiveParams setPromptType:MSALPromptTypeSelectAccount];
interactiveParams.completionBlockQueue = dispatch_get_main_queue();
[application acquireTokenWithParameters:interactiveParams completionBlock:completionBlock];
}
Say I had the following method call to make:
[[[[Foo init] addString:#"one"] addString:#"one"] addString:#"three"]
Where Foo contains:
#implementation Foo {
NSString *string;
}
- (void)addString:(NSString *)text {
string = [string stringByAppendingString:text];
}
Say I wanted to wait until all the addString methods were completed and wanted to print "onetwothree", but I had no idea how many times addString was going to be called. How would I achieve this? I tried to do this using dispatch_group as in:
#implementation Foo {
NSString *string;
}
- (id)init {
// setup
[self complete];
string = #"";
}
- (void)addString:(NSString *)text {
dispatch_group_async(group, queue, ^ {
string = [string stringByAppendingString:text];
NSLog(#"%#", text);
}
}
- (void)complete {
dispatch_group_notify(group,queue, 0), ^ {
NSLog(#"Final String: %#", string);
});
}
But this prints:
One
Final String:
Two
Three
Any idea how I can get this done?
If you do want to use async processing you can do it this way:
#import "Foo.h"
#implementation Foo {
NSString *_string;
dispatch_group_t _group;
dispatch_queue_t _queue;
}
- (instancetype)init
{
self = [super init];
if (self) {
_string = #"";
_group = dispatch_group_create();
_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
}
return self;
}
- (void)addStrings:(NSArray *)strings {
dispatch_group_async(_group, _queue, ^() {
NSMutableString *result = [NSMutableString new];
for (NSString *str in strings) {
[result appendString:str];
}
_string = [result copy];
});
}
- (void)complete {
dispatch_group_notify(_group, _queue, ^ {
NSLog(#"Final String: %#", _string);
});
}
Call this way:
Foo *foo = [[Foo alloc] init];
[foo addStrings:#[#"one", #"two", #"three"]];
[foo complete];
This question already has answers here:
Restrict NSTextField to only allow numbers
(10 answers)
Closed 8 years ago.
In textfield I want to restrict numbers like (1234567890) and special characters but I want to allow alphanumeric characters. How I am suppose to do this?
Use the UITextField delegate method
textField:shouldChangeCharactersInRange:replacementString:
To check the string that is about to be replaced, if you allow it then return yes if not then return no.
Here is some more information.
Apple UITextField Delegate
try following code
+ (BOOL)isNumber:(NSString *)value {
if ( (value == nil) || ([#"" isEqualToString:value]) ) {
return NO;
}
int l = [value length];
BOOL b = NO;
for (int i = 0; i < l; i++) {
NSString *str =
[[value substringFromIndex:i]
substringToIndex:1];
const char *c =
[str cStringUsingEncoding:
NSASCIIStringEncoding];
if ( c == NULL ) {
b = NO;
break;
}
if ((c[0] >= 0x30) && (c[0] <= 0x39)) {
b = YES;
} else {
b = NO;
break;
}
}
if (b) {
return YES;
} else {
return NO;
}
}
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if ( (string != nil) && (string != #"") ) {
if (![self isNumber:string]) {
return NO;
}
}
return YES;
}
You need to write a NSFormatter and assign it to your text field. Here an example implementation of a such NSFormatter which uses a NSRegularExpression to validate the NSTextField contents.
#interface XXNameElementFormatter : NSFormatter
#end
#implementation HcNameElementFormatter {
NSRegularExpression *_re;
}
- (id)init {
self = [super init];
if (self) {
[self initRegularExpression];
}
return self;
}
- (void)awakeFromNib
{
[self initRegularExpression];
}
- (void)initRegularExpression
{
NSError *reError;
_re = [NSRegularExpression regularExpressionWithPattern:#"^[a-z]*$" options:NSRegularExpressionCaseInsensitive error:&reError];
NSAssert(_re != nil, #"Error in regular expression, error: %#", reError);
}
- (NSString *)stringForObjectValue:(id)obj
{
return obj;
}
- (BOOL)getObjectValue:(out __autoreleasing id *)obj forString:(NSString *)string errorDescription:(out NSString *__autoreleasing *)error
{
*obj = string;
return YES;
}
- (BOOL)isPartialStringValid:(NSString *__autoreleasing *)partialStringPtr proposedSelectedRange:(NSRangePointer)proposedSelRangePtr originalString:(NSString *)origString originalSelectedRange:(NSRange)origSelRange errorDescription:(NSString *__autoreleasing *)error
{
NSParameterAssert(partialStringPtr != nil);
NSString *partialString = *partialStringPtr;
NSRange firstMatch = [_re rangeOfFirstMatchInString:*partialStringPtr options:0 range:NSMakeRange(0, partialString.length)];
return firstMatch.location != NSNotFound;
}
#end
Trying to figure out why NSMutableString:rangeOfString: is returning really weird results. NSLog is showing me a result like this:
location=9223372036854775807 length=0:This is a test
My test string does not contain "###", so I'd expect location=0 length=0. The weird location keeps coming up until the string actually contains "###" then location and length are correct. What am I missing in the below code snippet?
ServerPacketMotd.h
typedef struct _serverPacketMotdStruct
{
int8_t type; /* SP_MOTD */
int8_t pad1;
int8_t pad2;
int8_t pad3;
int8_t line[80];
} serverPacketMotdStruct;
ServerPacketMotd.m
#import "ServerPacketMotd.h"
#interface ServerPacketMotd()
{
NSMutableString *buffer;
}
#end
#implementation ServerPacketMotd
- (id)init
{
if( !( self = [super init] ) )
return nil;
buffer = [[NSMutableString alloc] init];
return self;
}
- (NSMutableData *)handlePacket:(NSData *)data withTag:(long)tag
{
serverPacketMotdStruct gamePacket;
uint16_t size = sizeof(serverPacketMotdStruct);
NSRange packetWindow = NSMakeRange(0, size);
NSRange atAtAt = NSMakeRange(0,0);
while (expression)
{
[data getBytes:&gamePacket range:packetWindow];
[buffer appendFormat:#"%s\n", gamePacket.line];
atAtAt = [buffer rangeOfString:#"###"];
NSLog(#"XXX location=%lu length=%lu:%#", atAtAt.location, atAtAt.length, buffer);
}
Check if atAtAt.location == NSNotFound. A location of 0 means the string was found at location 0, it doesn't mean it wan't found.
I am trying to get the IP Address using NSHost. With the NSHost object I can use the addresses method to access an array of objects one of which is the IP Address. I fear though that the IP Address may change position in the array from one machine to the other. Is there a way to access this information in a universal way?
There was an attempt to answer this question in a previous post, but as you can see it falls short.
IP Address? - Cocoa
Here is my code:
+(NSString *) ipAddress {
NSHost * h = [[[NSHost currentHost] addresses] objectAtIndex:1];
return h ;
}
The only thing I can think of is to use something like "http://www.dyndns.org/cgi-bin/check_ip.cgi" others may have a better way.
This is an example,(i.e a quick cobbled together code)
NSUInteger an_Integer;
NSArray * ipItemsArray;
NSString *externalIP;
NSURL *iPURL = [NSURL URLWithString:#"http://www.dyndns.org/cgi-bin/check_ip.cgi"];
if (iPURL) {
NSError *error = nil;
NSString *theIpHtml = [NSString stringWithContentsOfURL:iPURL
encoding:NSUTF8StringEncoding
error:&error];
if (!error) {
NSScanner *theScanner;
NSString *text = nil;
theScanner = [NSScanner scannerWithString:theIpHtml];
while ([theScanner isAtEnd] == NO) {
// find start of tag
[theScanner scanUpToString:#"<" intoString:NULL] ;
// find end of tag
[theScanner scanUpToString:#">" intoString:&text] ;
// replace the found tag with a space
//(you can filter multi-spaces out later if you wish)
theIpHtml = [theIpHtml stringByReplacingOccurrencesOfString:
[ NSString stringWithFormat:#"%#>", text]
withString:#" "] ;
ipItemsArray =[theIpHtml componentsSeparatedByString:#" "];
an_Integer=[ipItemsArray indexOfObject:#"Address:"];
externalIP =[ipItemsArray objectAtIndex: ++an_Integer];
}
NSLog(#"%#",externalIP);
} else {
NSLog(#"Oops... g %d, %#",
[error code],
[error localizedDescription]);
}
}
[pool drain];
return 0;}
I have used this on many machines without problems.
-(void) getIPWithNSHost{
NSArray *addresses = [[NSHost currentHost] addresses];
for (NSString *anAddress in addresses) {
if (![anAddress hasPrefix:#"127"] && [[anAddress componentsSeparatedByString:#"."] count] == 4) {
stringAddress = anAddress;
break;
} else {
stringAddress = #"IPv4 address not available" ;
}
}
//NSLog (#"getIPWithNSHost: stringAddress = %# ",stringAddress);
}
NSString *stringAddress; is declared else where
I wanted to update my original answer on getting an external ip.
There is not much change but I wanted to show how to get and parse the HTML with use NSXMLDocument and Xquary
This also gives a small illustration of how you can parse HTML by getting the nodes. Which in my opinion is more straight forward. Although NSXMLDocument is initially for XML it will parse the HTML DOM tree
NSString *externalIP;
///--DYNDNS.ORG URL
NSURL *iPURL = [NSURL URLWithString:#"http://www.dyndns.org/cgi-bin/check_ip.cgi"];
if (iPURL) {
NSError *err_p = nil;
//--use NSXMLDocument to get the url:(*Requests NSXMLNode to preserve whitespace characters (such as tabs and carriage returns) in the XML source that are not part of node content*)
NSXMLDocument * xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:iPURL
options:(NSXMLNodePreserveWhitespace|
NSXMLNodePreserveCDATA)
error:&err_p];
if (xmlDoc == nil) {
//-- That did not work so lets see if we can change the malformed XML into valid XML during processing of the document.
xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:iPURL
options:NSXMLDocumentTidyXML
error:&err_p];
}
if (!err_p) {
NSError * error;
//-- We will use XQuary to get the text from the child node. Dyndns.org page is very simple. So we just need to get the Body text.
NSString *xpathQueryTR = #"//body/text()";
//-- we get the first node's string value. We use string value to in effect cast to NSString.
//We the seperate the string into components using a space. and obtain the last object in the returned array.
//--This gives us the IP string without the "Current IP Address:" string.
externalIP = [[[[[xmlDoc nodesForXPath:xpathQueryTR error:&error]objectAtIndex:0] stringValue]componentsSeparatedByString:#" "]lastObject];
if (!error) {
NSLog(#"%#",externalIP);
}else {
NSLog(#"Oops... g %ld, %#",
(long)[error code],
[error localizedDescription]);
}
}else {
NSLog(#"Oops... g %ld, %#",
(long)[err_p code],
[err_p localizedDescription]);
}
}
Made an utility class to find the IP addresses. Minimalistic approach. You can robustify it with more conditions or regex checking.
NSLog(#"Addresses: %#", [[NSHost currentHost] addresses]);
This is the list returned by NSHost
"fe80::1610:9fff:fee1:8c2f%en0",
"192.168.212.61",
"fe80::2829:3bff:fee6:9133%awdl0",
"fe80::e54b:8494:bbc8:3989%utun0",
"fd68:cc16:fad8:ded9:e54b:8494:bbc8:3989",
"10.11.51.61",
"::1",
"127.0.0.1",
"fe80::1%lo0"
Test method,
- (void)testHost {
NSLog(#"Addresses: %#", [[NSHost currentHost] addresses]);
for (NSString *s in [[NSHost currentHost] addresses]) {
IPAddress *addr = [[IPAddress alloc] initWithString:s];
if (![addr isLocalHost] && [addr isIPV4]) {
// do something
}
}
}
IPAddress.h
#import <Foundation/Foundation.h>
#interface IPAddress : NSObject
#property (nonatomic, strong) NSString *IPAddress;
- (id)initWithString:(NSString *)ipaddress;
- (BOOL)isLocalHost;
- (BOOL) isIPV4;
- (BOOL) isIPV6;
#end
IPAddress.m
#import "IPAddress.h"
#implementation IPAddress
- (id)initWithString:(NSString *)ipaddress {
self = [super init];
if (self) {
self.IPAddress = ipaddress;
}
return self;
}
- (BOOL)isLocalHost {
if (self.IPAddress == nil) return NO;
if ([#"127.0.0.1" compare:self.IPAddress options:NSCaseInsensitiveSearch] == NSOrderedSame) {
return YES;
}
if ([#"localhost" compare:self.IPAddress options:NSCaseInsensitiveSearch] == NSOrderedSame) {
return YES;
}
if ([#"::1" compare:self.IPAddress options:NSCaseInsensitiveSearch] == NSOrderedSame) {
return YES;
}
return NO;
}
- (BOOL) isIPV4 {
NSArray *ar = [self.IPAddress componentsSeparatedByString:#"."];
if (ar.count == 4) {
return YES;
}
return NO;
}
- (BOOL) isIPV6 {
if (![self isIPV4]) {
if ([self.IPAddress rangeOfString:#":"].location != NSNotFound) {
return YES;
}
}
return NO;
}
#end
As the answers to the question you mention above have said, there are a variety of IP addresses that a single machine can have. If that is what you want, then you might be better off using the names method of NSHost to get an array of names, which you can then filter for the suffix (i.e *.lan) to get the name of the host you want with this name. In my case. the .lan address returns my network ip address as a dotted quad.
If you want to find the external ip address, then this is a good answer to look at.
My first Answer is to supply the Private IP address assigned to the Machine on private network from say your router.
If you want to see the public IP, which is the one facing the internet. Normally assigned by your service provider. You may want to look at the answer by Jim Dovey --> here
I tested it and it worked well, but read the rest of the comments and answers which point to ambiguities in trying to get a public IP.
You can create a category on NSHost and do something like this:
#import <arpa/inet.h>
#import <ifaddrs.h>
#import <net/if.h>
.h
+ (NSDictionary *) interfaceIP4Addresses;
+ (NSDictionary *) interfaceIP6Addresses;
+ (NSDictionary *) interfaceIPAddresses;
.m
typedef NS_ENUM(NSUInteger, AddressType) {
AddressTypeBoth = 0,
AddressTypeIPv4 = 1,
AddressTypeIPv6 = 2
};
#implementation SomeClass
#pragma mark - Helper Methods:
+ (NSDictionary *) _interfaceAddressesForFamily:(AddressType)family {
NSMutableDictionary *interfaceInfo = [NSMutableDictionary dictionary];
struct ifaddrs *interfaces;
if ( (0 == getifaddrs(&interfaces)) ) {
struct ifaddrs *interface;
for ( interface=interfaces; interface != NULL; interface=interface->ifa_next ) {
if ( (interface->ifa_flags & IFF_UP) && !(interface->ifa_flags & IFF_LOOPBACK) ) {
const struct sockaddr_in *addr = (const struct sockaddr_in *)interface->ifa_addr;
if ( addr && addr->sin_family == PF_INET ) {
if ( (family == AddressTypeBoth) || (family == AddressTypeIPv4) ) {
char ip4Address[INET_ADDRSTRLEN];
inet_ntop( addr->sin_family, &(addr->sin_addr), ip4Address, INET_ADDRSTRLEN );
[interfaceInfo setObject:[NSString stringWithUTF8String:interface->ifa_name]
forKey:[NSString stringWithUTF8String:ip4Address]];
} } else if ( addr && addr->sin_family == PF_INET6 ) {
if ( (family == AddressTypeBoth) || (family == AddressTypeIPv6) ) {
char ip6Address[INET6_ADDRSTRLEN];
inet_ntop( addr->sin_family, &(addr->sin_addr), ip6Address, INET6_ADDRSTRLEN );
[interfaceInfo setObject:[NSString stringWithUTF8String:interface->ifa_name]
forKey:[NSString stringWithUTF8String:ip6Address]];
} }
}
} freeifaddrs( interfaces );
} return [NSDictionary dictionaryWithDictionary:interfaceInfo];
}
#pragma mark - Class Methods:
+ (NSDictionary *) interfaceIP4Addresses { return [self _interfaceAddressesForFamily:AddressTypeIPv4]; }
+ (NSDictionary *) interfaceIP6Addresses { return [self _interfaceAddressesForFamily:AddressTypeIPv6]; }
+ (NSDictionary *) interfaceIPAddresses { return [self _interfaceAddressesForFamily:AddressTypeBoth]; }
#end
This works really fast and well. If you need other info or to monitor then use System Configuration framework.