MacOS - determine the Network Account Server with code - objective-c

I want to detect at runtime of my Mac application (written in Objective-C) if the user's Mac is joined to an Active Directory Server or Open Directory Server and/or any sort of "network account server". And to read the string of that setting if it exists. That is, the the setting from the Login Options pane of the "Users & Groups" applet in Systems Preference. See picture below.
Specifically, just reading the string of the specified server would be sufficient.
What's API set should I be looking at to read this setting?

A computer can be bound to multiple network account servers at one time. To list them you could use the OpenDirectory framework by creating an ODSession and list all registered nodes.
#import <OpenDirectory/OpenDirectory.h>
...
ODSession *mySession = [ODSession defaultSession];
NSError *err;
NSArray *nodeNames = [mySession nodeNamesAndReturnError:&err];
NSLog(#"nodeNames=%#", nodeNames);
I'm bound to Mac-mini.local OpenDirectory Server, and that outputs this:
nodeNames=(
"/Contacts",
"/LDAPv3/Mac-mini.local",
"/Local/Default",
"/Search"
)
To get further information about a registered node, just create an ODNode instance from the node name in the nodeNames array and use that to query that node.
ODNode *node = [[ODNode alloc] initWithSession:mySession name:#"/LDAPv3/Mac-mini.local" error:&err];
Or, you could also create an ODNode instance of a top node, like the /LDAPv3 node, directly and just ask for it's subnodes, like this:
ODNode *node = [[ODNode alloc] initWithSession:mySession name:#"/LDAPv3" error:&error];
NSArray *subnodes = [node subnodeNamesAndReturnError:&err];
NSLog(#"subnodes=%#", subnodes);
That gave me this output:
subnodes=(
"/LDAPv3/Mac-mini.local"
)
Note: there is also -unreachableSubnodeNamesAndReturnError:
If you need more info about this framework, the documentation can be found here

Related

getting info about mac OS X application programmatically

I'm looking for cocoa framework that acquires the following information for each application : vendor name, version and full application name.
Alternatively, I could use a file that contain this information ... I've tried to search it in /Application/(name).app/... but I couldn't find it in specific location that is the same for all applications.
It should be in the info.plist under CFBundleName
If you go into <application>/contents/info.plist you'll find it there
from the  documentation:
CFBundleName (String - iOS, OS X) identifies the short name of the
bundle. This name should be less than 16 characters long and be
suitable for displaying in the menu bar and the app’s Info window. You
can include this key in the InfoPlist.strings file of an appropriate
.lproj subdirectory to provide localized values for it. If you
localize this key, you should also include the key
CFBundleDisplayName.
here's an example code for acquiring version from Info.plist of a selected application:
string GetAppVersion(string app)
{
NSString *vlcFilePath = [NSString stringWithCString:app.c_str()];
NSDictionary* infoDict = [[NSBundle bundleWithPath:vlcFilePath] infoDictionary];
NSString* version = [infoDict objectForKey:#"CFBundleVersion"];
}
...
...
GetAppVersion("/Applications/Notes.app").c_str());

Core Data adding entities at runtime

I am rewriting the question to help clarify and get rid of a lot of code I wrote that really doesn't help.
I am using a .xcdatamodel for my initial schema, but I need to add entities to my schema at runtime and therefore I need to add a new NSManagedObjectModel and copy over the existing entities and then add the new entities.
If I create a new NSPersistantStore first and then ask my NSMigrationManager to migrate, I get an error about how it can't move the source model to destination path because file already exists.
If I simply ask my NSMigrationManager to migrate, then it just crashes without any error codes or anything in the debugger.
NSMappingModel *mappingModel = [NSMappingModel inferredMappingModelForSourceModel:originalModel destinationModel:newModel error:&error];
NSMigrationManager *manager = [[NSMigrationManager alloc] initWithSourceModel:originalModel destinationModel:newModel];
if (![manager migrateStoreFromURL:[originalStore URL]
type:NSSQLiteStoreType
options:[self autoMigrationOptions]
withMappingModel:mappingModel
toDestinationURL:[NSPersistentStore MR_urlForStoreName:[self nextStoreName]]
destinationType:NSSQLiteStoreType
destinationOptions:[self autoMigrationOptions]
error:&error])
{
return NO;
}
The URL's are all good, the mapping model looks good when I log it to the console, the manager exists, etc. In this case I did not create the NSPersistantStore yet, but according to the NSMigrationManager class reference if a store does not exist at the destination URL then one is automatically created.
Anyone have a clue?

RestKit Object Mapping: difficulty using setObjectMapping:forResourcePathPattern:withFetchRequestBlock

My setup
The following all works fine:
RKManagedObjectMapping* chanMapping = [RKManagedObjectMapping mappingForClass:[Channel class] inManagedObjectStore:objectStore];
chanMapping.primaryKeyAttribute = #"chanId";
[chanMapping mapKeyPathsToAttributes:
#"id",#"chanId",
#"name", #"chanName",
nil];
[objectManager.mappingProvider setMapping:chanMapping forKeyPath:#"Channels.channel"];
I can call
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:#"/channels" delegate:self];
and I get my channel's from the server and they're stored locally by Core Data. Perfect.
The issue
However, I now wan't to have RestKit automatically delete Channels from the Core Data store that have been removed from the server the next time a GET is performed. I understand this is supported by adding the following:
[objectManager.mappingProvider setObjectMapping:chanMapping forResourcePathPattern:#"/channels" withFetchRequestBlock:^ (NSString *resourcePath) {
return [Channel fetchRequest];
}];
However with this all the Channels get deleted whenever there is anything new on the server.
Things I've tried [UPDATED]
I've debugged using the steps in the answer below. It looks as though the mapping isn't working / is not being found (i.e. I haven't properly associated the mapping with the resource path).
In deleteCachedObjectsMissingFromResult the cachedObjects array looks good, has all the objects that should be there from the last time but the results array is empty which obviously results in [results containsObject:object] always being NO and all the objects being deleted.
Do I need to change something to do with the resource path mapping?
I looked at your updated description. Give this a try:
Switch back to the setObjectMapping:forResourcePathPattern:withFetchRequestBlock
Set the rootKeyPath on the object mapping you register to Channels.channel
Then give it another try. There is some API work in progress to provide URL and keyPath based mapping configuration in a single line, but its not merged to development yet.
Two things to check out to determine why you are seeing the described behavior:
Open up RKManagedObjectLoader and put a breakpoint within isResponseMappable. This method checks if the response was loaded from the cache and performs a load of the objects using the objects returned by the managed object cache if it returns YES. This is probably where you are seeing the return of the cached objects from.
As for the deletion of cached objects, put a breakpoint within deleteCachedObjectsMissingFromResult and see what is going on in there (if you are even making it into the routine).
The scenario to expect automatic pruning would be:
GET /channels returns 2xx status code with new payload
RKManagedObjectLoader performs pruning

Simplest way to get the PID of a recently launched application

I want to launch a file with a specified application, and I want the launched program to immediately become the frontmost window.
I know that I can do this as follows:
[[NSWorkspace sharedWorkspace] openFile:fileName withApplication:appName];
Then, if I can get the PID of that launched application, I can then do this to make that application frontmost:
NSRunningApplication* app = [NSRunningApplication
runningApplicationWithProcessIdentifier: PID];
[app activateWithOptions: NSApplicationActivateAllWindows];
The question I have is this: what is the simplest, quickest, and most reliable way to get this application's PID right after launching, so I can make sure that this application is frontmost?
This is not as straightforward as it might appear at first glance. For example, I need a process name in order to get the PID using Carbon calls, or via the application dictionary that is accessible via NSRunningApplication. However, in the general case, I don't always know what the process name is, and in some cases, the process name is an empty string.
Furthermore, I might have other instances of this same application already running, and I want to always get the PID of the specific instance of the application that I just launched.
Can anyone suggest a definitive, 100-percent reliable way to get the currently launched application's PID?
Or alternatively, is there a way to launch a given file with a specified application such that the application always opens as the frontmost app?
Have you tried using the other version of openFile which will allow you to deactivate your application, allowing the new application to take focus?
[[NSWorkspace sharedWorkspace] openFile:fileName withApplication:appName andDeactivate:YES];
It is definitely not easy to get the PID of an application. And that's how Apple likes it.. Those cheeky bastards.
I had to write this beast just to get the PID from a full path of an app I knew was running.. Hey it's easier than parsing ps aux !
Sorry if there are some of my own private functions in there but you can get the idea of how I went about it and what I tried to avoid along the way.
+ (NSUInteger)pidFromAppPath:(NSString*)path
{
NSRunningApplication *n = [[[NSWorkspace sharedWorkspace]runningApplications] filterOne:^BOOL(NSRunningApplication *runner) {
// optional: avoid totally faceless apps and "Desk Accesory"-type background apps.
if (runner.activationPolicy == NSApplicationActivationPolicyProhibited) ||
runner.activationPolicy == NSApplicationActivationPolicyAccessory)
return nil;
id runPath = [runner valueForKeyPath:#"bundleURL"];
NSString *runString = [runPath isKindOfClass:[NSString class]]
? runPath
: [runPath isKindOfClass:NSURL.class] ? [((NSURL*)runPath) path]
: nil;
// optional: filter out Google Chrome's mockery of a once sane process-table
if ( !runString
|| [[runString lastPathComponent]contains:#"Google Chrome Helper.app"]
|| [[runString lastPathComponent]contains:#"Google Chrome Worker.app"]
|| [[runString lastPathComponent]contains:#"Google Chrome Renderer.app"] )
return nil;
return [runString isEqualToString:path] ?: nil; // This is where you actually test to see if it's the same as the string passed in, lol.
}];
return n ? [n processIdentifier] : 11000; // if 11000 you messed up.
}
And voilá... NSLOG: Pid of /Applications/Utilities/Terminal.app is 46152

Modifying a file on FTP Server

I have finished the majority of my application that I am working on, but I have run into a problem. Basically, what I wrote streams audio from my server to the iPod and plays it without having to save the file. It has a GUI that allows the user to choose the file they want to listen to, and it works flawlessly.
My problem is that I want to be able to have some sort of a counter that updates every time a user listens to a file. I have a file in the project, "TotalDownloads.txt," that I had planned on using to store the new value and upload back to the server, but when the code executes, nothing changes within that file. I had also tried just declaring the file #"TotalDownloads.txt," but that created a new file in the Macintosh HD named "TotalDownloads.txt."
The two identifiers "//-" and "-//" are to parse the file for the number, when I get this figured out, specifically to isolate the numeric value, should there be any formatting involved. Eventually, I want to have counts for each and every one of the files.
I have no problem with downloading the text file off of the server and reading it into the iPhone, but the problem arises when sending it back. What is the easiest way to 1, make a temporary file text file on the iPhone, and 2, upload it back to the server to replace the existing file?
Is there a way to just modify the file on the server?
Any help is appreciated.
Below is what I have so far:
- (IBAction)action
{
NSURL *textURL = [NSURL URLWithString:#"http://www.faithlifefellowship.us/Audio/TotalDownloads.txt"];
NSString *textFromFile = [NSString stringWithContentsOfURL:textURL encoding:NSUTF8StringEncoding error:false];
int click = [textFromFile intValue];
click += 1;
NSString *replace = #"//-";
NSString *clicks = [NSString stringWithFormat:#"%d",click];
replace = [replace stringByAppendingString:clicks];
replace = [replace stringByAppendingString:#"-//"];
//test is a label I used to check to make sure the download count was being read properly.
test.text = clicks;
[replace writeToFile:[[NSBundle mainBundle] pathForResource:#"TotalDownloads" ofType:#"txt"]atomically:YES encoding:NSUTF8StringEncoding error:NULL];
}
Here is the best way I suggest you do this.
Set up a page on your server that accepts a get request.
Code the page to take the value from that get request (which should be the name of the file you are trying to update) and update the file at that path.
From your app, use UIWebView this way:
UIWebView* web = [UIWebView new];
[web loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.mydomain.com/myPage.php"]]];
web = nil;
Presto!