El Capitan - How to read Mac Os X Mail Accounts Informations - objective-c

I have an Application which uses the Content of the Accounts.plist.
After upgrade to Mac OS El Capitan / 10.11.1 the Accounts.plist isn't supported under the new Mail-Path.
Before:
/Users/[homefolder]/Library/Mail/v2/MailData/Accounts.plist
Now:
/Users/[homefolder]/Library/Mail/v3/MailData/*
How can i get the Mail-Account Details now ?

Stumbled upon a cleaner way to do this. Refer SBSendMail(https://developer.apple.com/library/mac/samplecode/SBSendEmail/Introduction/Intro.html) for Apple's scripting bridge. Then to read smtp servers:
MailApplication *mail = [SBApplication applicationWithBundleIdentifier:#"com.apple.Mail"];
/* set ourself as the delegate to receive any errors */
mail.delegate = self;
SBElementArray *smtpServers = mail.smtpServers;
for (MailSmtpServer *server in smtpServers)
{
NSLog(#"%# %# %# %# %d", server.name, server.password, server.userName, server.serverName, server.port);
}
You can read IMAP & POP account settings similarly.

Related

Grab audioCDPlaylist via ScriptingBridge does not work with macOS Mojave Beta

I have a application which gets audioCDPlayList from iTunes. This app works fine up to macOS High Sierra, but does not work correctly on macOS Mojave Beta 3 (18A326h).
I have investigated the reason and then found that the following strange behavior:
GetAudioCDInfoFromiTunes.h
#import <Foundation/Foundation.h>
#import <ScriptingBridge/ScriptingBridge.h>
#import "iTunes.h"
#interface GetAudioCDInfoFromiTunes : NSObject
- (NSMutableDictionary *)getAudioCDInfoFromiTunes;
#end
GetAudioCDInfoFromiTunes.m
- (NSMutableDictionary *)getAudioCDInfoFromiTunes {
// Declear iTunes scripting bridge variable
iTunesApplication *iTunesApp = [SBApplication applicationWithBundleIdentifier:#"com.apple.iTunes"];
SBElementArray *sources = [iTunesApp sources];
NSLog(#"sources=%#", sources);
NSLog(#"count=%ld", [sources count]);
iTunesPlaylist *aAudioCDPlayList = nil;
for (iTunesSource *src in sources) {
NSLog(#"src=%#", src);
SBElementArray *playlists = [src audioCDPlaylists];
NSLog(#"playlists=%#", playlists);
for (iTunesPlaylist *aPlaylist in playlists) {
NSLog(#"aplaylist=%#", aPlaylist);
if ([aPlaylist isKindOfClass:[NSClassFromString(#"ITunesAudioCDPlaylist") class]]) {
aAudioCDPlayList = [aPlaylist get];
break;
}
}
}
... SNIP ...
}
Executing the above code, NSLog of Line.8, count of sources is 0. And therefore for loop of Line.12 don't work. Then the result [aPlaylist get] is null.
Does anyone know the reason why the count of sources is 0?
Plase let me know how can I run my ScriptingBridge code on Mojave Beta...
Mojave has tightened data security and privacy and that includes scripting. See WWDC 2018 session 702.
The first time your app tries to control iTunes, Mojave will prompt to get your confirmation to allow that. It will remember your choice so it doesn't ask again.
I guess you must have denied it permission once. After that, it just always prevented your app from controlling iTunes.
Since developers need to test their app's behavior when this prompt is displayed, when permission is denied, and when it's granted, Apple has included a command-line utility, tccutil, to reset the remembered user choices. The command to reset permissions regarding which apps may control other apps is tccutil reset AppleEvents.

Cocoa compatible with different Mac OS

I have a Cocoa app which has different features in Mac OS 10.7 and 10.8 (The deployment target is 10.7). For example, in 10.8 I have a button for Sharing Service while in 10.7 the button is hidden.
The problem here is how can I know which kind of Mac OS is there while my app is running. For iOS, I can get it from UIDevice. But for Cocoa, I don't find the similar class.
Currently, I detect the OS using:
- (BOO)isServiceAvalable
{
if (NSClassFromString(#"A_Unique_Class_In_One_OS"))
{
return YES;
}
return NO;
}
I hope there is more elegant way to do it.
StackOverflow: os version checking in cocoa
StackOverflow: How to get the Mac OS X system version?
StackOverflow: How can I determine the running Mac OS X version programmatically?
Cocoa Dev Central: Checking the User's Mac OS X Version
If Gestalt is deprecated as scorpiozj mentions then here's a simple NSApplescript way to do it...
NSString* getSystemVersion() {
NSString* returnString = nil;
NSString* cmd = #"return system version of (get system info)";
NSAppleScript* theScript = [[NSAppleScript alloc] initWithSource:cmd];
NSDictionary* errorDict = nil;
NSAppleEventDescriptor* result = [theScript executeAndReturnError:&errorDict];
[theScript release];
if (errorDict) {
returnString = [NSString stringWithFormat:#"Error:%# %#", [errorDict valueForKey:#"NSAppleScriptErrorNumber"], [errorDict valueForKey:#"NSAppleScriptErrorMessage"]];
} else {
returnString = [result stringValue];
}
return returnString;
}

Issues in using CNCopyCurrentNetworkInfo

I am using the below code to retrieve the SSID of the WiFi network the iPod is connected.
NSArray *ifs = (id)CNCopySupportedInterfaces();
NSLog(#"%s: Supported interfaces: %#", __func__, ifs);
id info = nil;
for (NSString *ifnam in ifs) {
info = (id)CNCopyCurrentNetworkInfo((CFStringRef)ifnam);
NSLog(#"%s: %# => %#", __func__, ifnam, info);
if (info && [info count]) {
break;
}
[info release];
}
Sometimes this code is not returning the proper SSID of the network my device is connected.Any pointers on why the SSID is not retrieved correctly? Does CNCopyCurrentNetworkInfo package dependent on the iOS version of the device?
Thanks.
add SystemConfiguration.framework to project.
import < SystemConfiguration/CaptiveNetwork.h >
CFArrayRef myArray = CNCopySupportedInterfaces();
CFStringRef interfaceName = CFArrayGetValueAtIndex(myArray, 0);
CFDictionaryRef captiveNtwrkDict = CNCopyCurrentNetworkInfo(interfaceName);
NSDictionary *dict = ( NSDictionary*) captiveNtwrkDict;
NSString* ssid = [dict objectForKey:#"SSID"];
NSLog(#"%s ssid : %#",__FUNCTION__, [ssid description]);
For iOS 12 and later, you must enable it from capabilities.
Important
To use this function in iOS 12 and later, enable the Access WiFi Information capability for your app in Xcode. When you enable this capability, Xcode automatically adds the Access WiFi Information entitlement to your entitlements file and App ID. Documentation link
Yes. CNCopyCurrentNetworkInfo is available only in iOS 4.1 and later.
For more info ,please look at the developer.apple SystemConfiguration Reference
you can check the sample code here

Sandboxing coreWLAN?

I'm writing an OS X application that depends on the ability to determine wireless signal strength, but I can't figure out what entitlements to use to sandbox it.
Whenever I use
NSMutableArray *scanResults;
CWInterface *currentInterface = [CWInterface interface];
NSLog(#"currInterface: %#\n", currentInterface);
NSMutableDictionary *signalsDict = [[NSMutableDictionary alloc] init];
NSError *err = nil;
scanResults = [NSMutableSet setWithSet:[currentInterface scanForNetworksWithSSID:nil error:&err]];
I get the error The operation couldn't be completed. (com.apple.coreWLAN.error error 1.) despite having all entitlements checked in XCode. What entitlement(s) am I missing?
The CoreWLANWirelessManager sample project has the same problem.
CoreWLAN doesn't seem to be available at all to sandboxed apps.
Apple's developer documentation states "With App Sandbox, your app cannot modify the system’s network configuration (whether with the System Configuration framework, the CoreWLAN framework, or other similar APIs)", which seems to imply that reading but not writing settings might be OK, but that doesn't seem to work in practice, and this is confirmed by a post by Apple DTS: https://forums.developer.apple.com/thread/11307
How about the entitlements for the Wifi Diagnostics app that ships with Mac OS X 10.11.1, located at /System/Library/CoreServices/Applications/. Checking entitlements I see that it posseses the following: com.apple.wifi.associate, com.apple.wifi.scan, com.apple.wifi.set_channel, com.apple.wifi.start_autojoin, com.apple.wireless-diagnostics, and com.apple.wireless-diagnostics.basic_report.
Are we mere mortals working in a sandbox not able to get these?
I think you need to check Outgoing Connections (Client).
You might want to use Apple80211 private framework by using dlfcn.h library. An iphone example can be found here:
http://www.csse.uwa.edu.au/~chris/iphone/APlogger/
Download the source file and investigate scanner module.
In summary, you will come up with something like this:
#define IF_NAME "en0"
#include <dlfcn.h>
- (void)performScan
{
int (*open)(void *);
int (*bind)(void *, NSString *);
int (*close)(void *);
int (*scan)(void *, NSArray **, void *);
void *libHandle;
void *airportHandle;
libHandle = dlopen("/System/Library/Frameworks/Preferences.framework/Preferences", RTLD_LAZY);
open = dlsym(libHandle, "Apple80211Open");
bind = dlsym(libHandle, "Apple80211BindToInterface");
scan = dlsym(libHandle, "Apple80211Scan");
close = dlsym(libHandle, "Apple80211Close");
open(&airportHandle);
bind(airportHandle, #IF_NAME);
NSArray *found;
NSDictionary *params = [[NSDictionary alloc] init];
scan(airportHandle, &found, params);
int nnw = [found count];
for(int i=0 ; i < nnw ; i++) {
NSDictionary *nw = [found objectAtIndex:i];
NSString *ssid = [self fixSSID:nw];
// RSSI indicates signal strength
int rssi = [[nw objectForKey:#"RSSI"] intValue];
}
// Cleanup
close(airportHandle);
dlclose(libHandle);
}
-(NSString *)fixSSID:(NSDictionary *)nw
{
if ([[nw objectForKey:#"HIDDEN_NETWORK"] boolValue])
return #"<hidden>";
else
return [nw objectForKey:#"SSID_STR"];
}
Note that if you use private frameworks in your iOS apps, you will not be able to publish them on App Store (Apple will reject your app because there is no public documentation for Apple80211 framework). but since your question is regarding OSX development, this doesn't apply for your case.
Hope it helps.

Skype Mac API - Use AppleScript or 5 year old API?

I have a x86_64 app that I would like to have optionally read Skype status messages. However, the 5 year old skype mac framework is 32-bit, and if there is a way to have that compile within a 64-bit app, I haven't found it.
My question is, basically, how should I go about doing this? I really only need to get and set the USERSTATUS AWAY/ONLINE string.
Using AppleScript, a "Should Skype allow this" dialog pops up... every time. This is highly inefficient and downright irritating.
Advice?
I'm considering writing a 32-bit CLI wrapper, but that seems like overkill.
I used Notification Watcher to learn that Skype's API just works with NSDistributedNotifications. Repeating those notifications worked like a charm for a 64bit app.
Check out Scripting Bridge: Introduction to Scripting Bridge Programming Guide for Cocoa
If I remember right, the permission dialog does not come up once you allow permission.
I my Skype Apple Scripts I have to GUI to click them. If they come up.
tell application "Skype" to launch
delay 15
(* this part if the security API window comes up*)
tell application "System Events"
tell application process "Skype"
if exists (radio button "Allow this application to use Skype" of radio group 1 of window "Skype API Security") then
click
delay 0.5
click button "OK" of window "Skype API Security"
end if
end tell
end tell
delay 5
I've found out that if you open "Skype.app" by viewing bundle contents -> Frameworks you'll find a 64bit and 32bit skype.framework
This is an answer in reply to a request from twitter. I used this code after asking this question way back when. I have not needed to look into the Skype API since this works just fine, but I imagine that its been updated since I last tried to use it. Anyhow...
Here's a list of the NSDistributedNotifications that I use when communicating to skype:
SKSkypeAPINotification
SKSkypeAttachResponse
SKSkypeBecameAvailable
SKAvailabilityUpdate
SKSkypeWillQuit
Just like any other kind of NSDistributedNotification, you simply register and process the results:
[[NSDistributedNotificationCenter defaultCenter]
addObserver:self selector:#selector(setStatusAfterQuit:)
name:#"SKSkypeWillQuit"
object:nil
suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately];
These are the iVars that I keep to sync with Skype:
NSString *applicationName;
NSString *mostRecentStatus;
NSString *mostRecentStatusMessage;
NSString *mostRecentUsername;
int APIClientID;
BOOL isConnected;
BOOL needToSetMessage;
NSString *nextMessage;
NSString *nextStatus;
Here's an example of how to connect to skype:
-(void) skypeConnect{
if (!isConnected){
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:#"SKSkypeAPIAvailabilityRequest"
object:nil
userInfo:nil
deliverImmediately:YES];
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:#"SKSkypeAPIAttachRequest"
object:applicationName
userInfo:nil
deliverImmediately:YES];
}
}
Here's an example of getting the status message (after you've registered with Skype):
-(void) processNotification:(NSNotification *) note{
if ([[note name] isEqualToString:#"SKSkypeAttachResponse"]){
if([[[note userInfo] objectForKey:#"SKYPE_API_ATTACH_RESPONSE"] intValue] == 0){
NSLog(#"Failed to connect to Skype.");
isConnected = NO;
}else {
NSLog(#"Connected to Skype.");
APIClientID = [[[note userInfo] objectForKey:#"SKYPE_API_ATTACH_RESPONSE"] intValue];
isConnected = YES;
[self sendCommand:#"GET PROFILE MOOD_TEXT"];
if (needToSetMessage){
[self sendCommand:[NSString stringWithFormat:#"SET USERSTATUS %#",nextStatus]];
[self sendCommand:[NSString stringWithFormat:#"SET PROFILE MOOD_TEXT %#",nextMessage]];
needToSetMessage = NO;
nextMessage = #"";
nextStatus = #"";
}
}
}
}