How to check whether app is running using [[NSAppleScript alloc] initWithSource: - objective-c

This is my original script. It will return the current url of Safari
NSAppleScript *scriptURL= [[NSAppleScript alloc] initWithSource:#"tell application \"Safari\" to return URL of front document as string"];
What if I want to check whether the Safari browser is open or not before asking the script to return the URL?
Here is how I do in applescript editor.. So this script will check whether the Safari is running or not.. This works in applescript editor
tell application "Safari"
if it is running then
//return url code here
end if
end tell
What I need now is to straight away called the script from my cocoa app by using ' [[NSAppleScript alloc] initWithSource:'
I've tried this but its not working
NSAppleScript *scriptURL= [[NSAppleScript alloc] initWithSource:#"tell application \"Safari\" if it is running to return URL of front document as string"];

Why would that work? It's bad AppleScript grammar.
There are ways to do this without resorting to AppleScript, but it'll do for now. You can have multiple lines in an embedded script by using the C escape sequence \n to insert a newline:
NSString *source = #"tell application \"Safari\"\nif it is running then\nreturn URL of front document as string\nend if\nend tell";
You can also break up a string constant by placing one right after another, which makes it easier to read:
NSString *source =
#"tell application \"Safari\"\n"
"if it is running then\n"
"return URL of front document as string\n"
"end if\n"
"end tell";
The C compiler will glue these string constants together into a single NSString object.

The OP's AppleScript one liner code is wrong. The AppleScript text in this should work:
NSAppleScript *scriptURL= [[NSAppleScript alloc] initWithSource:#"tell application \"Safari\" to if it is running then return URL of front document as string"];

As dougscripts (+1) has pointed out but I wanted to make it little bit clearer of why the one liner Applescript syntax within the NSAppleScript the OP tried did not work.
And to be honest I did suggest an edit which lost out three to two
The OP's NSAppleScript code:
NSAppleScript *scriptURL= [[NSAppleScript alloc] initWithSource:#"tell application \"Safari\" if it is running to return URL of front document as string"];
Did not work because the syntax is wrong. 
The correct syntax should be:
NSAppleScript *scriptURL= [[NSAppleScript alloc] initWithSource:#"tell application \"Safari\" to if it is running then return URL of front document as string"];
There are two changes within part of the code shown in bold below.
\"Safari\" to if it is running then return URL

Related

OSAKit.framework usage for executing scripts

I am on XCode 9.2, Objective-C, MacOS
i am looking for any example on using osakit.framework to execute a script file(applescript = .scpt or .applescript) or a method in that file with parameters and how to get the response.
My own implementation of applescript works but leaks too much memory so i want to try osakit.framework but its documentation is bad.
The simple implementation is like this
OSAScript *scriptNAME= [[OSAScript alloc] initWithSource:#"tell application \"Firefox\" to return name of window 1"];
NSDictionary * errorDict = nil;
NSAppleEventDescriptor * returnDescriptor = [scriptNAME executeAndReturnError: &errorDict];
NSLog(#"%#", returnDescriptor);
But instead of the script as source in text form i want to load my script file.
Edit:
I tried it with
OSAScript *scriptNAME= [[OSAScript alloc] initWithContentsOfURL:myScriptURL error:&error];
The script gets loaded but i can't call any method.
I Have two simple methods
on test()
display dialog "Hello World"
end
on testWithArguments:arg
display dialog (arg's item 1)
end
The call for the second method i tried:
[scriptNAME executeHandlerWithName:#"testWithArguments" arguments:#[#"Hello World"] error:&errorDict];
-- doesnt work
[scriptNAME executeHandlerWithName:#"testWithArguments:" arguments:#[#"Hello World"] error:&errorDict];
-- doesnt work
Bug found.
It was a wrong configured applescript file. Was declared as a script object from a former test. As simple applescript file it works great.

Mail: Application isn't running

I'm trying to execute simple AppleScript in Objective-C. The code is:
NSString *emailString = #"tell application \"Mail\" to activate";
NSAppleScript *emailScript = [[NSAppleScript alloc] initWithSource: emailString];
NSDictionary *errorDict = NULL;
[emailScript executeAndReturnError: &errorDict];
And got this annoying error:
NSAppleScriptErrorMessage: Mail got an error: Application isn’t
running. NSAppleScriptErrorRange: NSRange: {27, 8}
NSAppleScriptErrorBriefMessage: Application isn’t running.
NSAppleScriptErrorNumber: -600 NSAppleScriptErrorAppName: Mail
It's no problem if I execute the script from Script Editor. I need some help — Thanks!
Solved. My app using Sandbox. And if you want run AppleScript from it, you need edit entitlements file. In me case this help.

I need to put an NSString variable in another string inside the initWithSource function, but I don't know how

I need to put an NSString variable between another string code to get the 'pathToSerialDevice' variable between the other code. Like this:
NSAppleScript *appleScript = [[NSAppleScript alloc]
initWithSource:#"Tell application \"Terminal\" \n\
do script with command \"screen %#", pathToSerialDevice, "\" in front window\n\
end tell"];
And my pathToSerialDevice string is taken from a text field
pathToSerialDevice = [NSString stringWithFormat:_pathTextField.stringValue];
When I display it in the Log, it works, I do it so:
NSLog(#"Your path is %#", pathToSerialDevice);
How to do the same, but in the NSAppleScript? It doesn't work now and I have no idea how to do it. Please help me.
P.S.
I have Xcode 6.1 on OS X 10.10 and it's an OS X app.
initWithSource: takes a regular string, not a format string. Read these docs on the difference.
The easiest thing to do is to just make another string:
NSString *pathToSerialDevice = [NSString stringWithFormat:_pathTextField.stringValue];
NSString *source = [NSString stringWithFormat:#"Tell application \"Terminal\" \n\
do script with command \"screen %# \" in front window\n\
end tell", pathToSerialDevice];
NSAppleScript *appleScript = [[NSAppleScript alloc] initWithSource:source];

Programmatically changing screen lock timeout

In my Cocoa application I would like to access and change the computer's screen lock timeout setting. Changing it in System Preferences does not require the user to enter the admin password.
Unfortunately I couldn't find any information in the documentation, and I'm not sure what topic I should look into (security settings / prefPane programming).
Any help would be appreciated.
NSMutableDictionary* plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:#"/Users/new/Library/Preferences/com.apple.screensaver.plist"];
[plistDict setObject:#"1" forKey:#"askForPassword"];
[plistDict setObject:#"3600" forKey:#"askForPasswordDelay"];
[plistDict writeToFile:#"/Users/new/Library/Preferences/com.apple.screensaver.plist" atomically:YES];
or From terminal
defaults write com.apple.screensaver askForPasswordDelay 5
The above answer apparently works for some, but on 10.8 it fails if you are using FileVault. The setting will stick, but it won't actually take effect until you launch System Preferences. Luckily, there's a way to 'touch' the setting after you are done:
- (void)touchSecurityPreferences;
{
NSAppleScript *kickSecurityPreferencesScript = [[[NSAppleScript alloc] initWithSource: #"tell application \"System Events\" to tell security preferences to set require password to wake to true"] autorelease];
[kickSecurityPreferencesScript executeAndReturnError:nil];
}
Edit Turns out this only works for going from a non-zero setting to zero setting. I assume this is a security thing. To go the other way, launching System Preferences is the only way.
Edit 2 Here's code for launching System Preferences, should you want to do so:
- (void)launchAndQuitSecurityPreferences;
{
// necessary for screen saver setting changes to take effect on file-vault-enabled systems when going from a askForPasswordDelay setting of zero to a non-zero setting
NSAppleScript *kickSecurityPreferencesScript = [[[NSAppleScript alloc] initWithSource:
#"tell application \"System Preferences\"\n"
#" tell anchor \"General\" of pane \"com.apple.preference.security\" to reveal\n"
#" activate\n"
#"end tell\n"
#"delay 0\n"
#"tell application \"System Preferences\" to quit"] autorelease];
[kickSecurityPreferencesScript executeAndReturnError:nil];
}

Is there a way to programmatically connect to a remote server from Cocoa?

Is there an Coca/obj-C API call to mimic the "Connect to Server" action in Finder? It's possible with Automater, so it seems like Finder has a hook somewhere.
Turns out there's an old Carbon function (can't find a Cocoa equivalent) called FSMountServerVolumeSync which does what I was looking for. You can supply and smb:// URL and login credentials.
File Manager Reference
OSStatus FSMountServerVolumeSync (
CFURLRef url,
CFURLRef mountDir,
CFStringRef user,
CFStringRef password,
FSVolumeRefNum *mountedVolumeRefNum,
OptionBits flags
);
An easy way is to just run some applescript code. I'll show you 2 choices. This first one is the standard way to show that Finder window from applescript.
NSString* cmd = #"choose URL";
The resulting window is bare-bones though, so you can actually open the Finder's window with this command...
NSString* cmd = #"tell application \"Finder\" to activate\ndelay 0.2\ntell application \"System Events\" to keystroke \"k\" using command down";
After choosing either of the "cmd" strings, you can execute that applescript code with this...
NSAppleScript* theScript = [[NSAppleScript alloc] initWithSource:cmd];
[theScript executeAndReturnError:nil];
[theScript release];
This might not be the best way, but can't you just use mount?