Why use Automator when you can stay in bash?
I found a really cool little script called appify that will instantly turn other scripts into actual applications. You can try it a few times to observe its behavior. Since you already use bash, I am hoping that this answer as an alternative to exactly what you are asking for is acceptable.
The idea is to split your script into 3 distinct scripts:
1: start ftp service on preferred network interface only
#!/bin/bash
#start ftp service
#sudo="/usr/bin/sudo"
#launchctl="/bin/launchctl"
say="/usr/bin/say"
networksetup="/usr/sbin/networksetup"
tail="/usr/bin/tail"
head="/usr/bin/head"
cut="/usr/bin/cut"
curl="/usr/bin/curl"
currentInterface=$(networksetup -listnetworkserviceorder |tail +2 |head -n1 |cut -c5-12)
getExternaladdress=$(curl ipecho.net/plain)
SiriSays="say -v Samantha"
#sudo -s launchctl load -w /System/Library/LaunchDaemons/ftp.plist
#your command will start ftp on all network interfaces
if [ "$currentInterface" = "Airport" ];
then
networksetup -setpassiveftp Airport on
else
networksetup --setpassiveftp Ethernet on
fi
$SiriSays "ftp service has been initiated for the"
echo $currentInterface |$SiriSays; $SiriSays "interface"
$SiriSays "Your external IP address is"
echo $getExternaladdress | $SiriSays
exit
2: stop ftp service
#!/bin/bash
#stop ftp service
#sudo="/usr/bin/sudo"
#launchctl="/bin/launchctl"
networksetup="/usr/sbin/networksetup"
say="/usr/bin/say"
tail="/usr/bin/tail"
head="/usr/bin/head"
cut="/usr/bin/cut"
currentInterface=$(networksetup -listnetworkserviceorder |tail +2 |head -n1 |cut -c5-12)
SiriSays="say -v Samantha"
#sudo -s launchctl unload -w /System/Library/LaunchDaemons/ftp.plist
#your command requires sudo
if [ "$currentInterface" = "Airport" ];
then
networksetup -setpassiveftp Airport off
else
networksetup -setpassiveftp Ethernet off
fi
$SiriSays "ftp service has been terminated"
exit
3: check ftp service status
#!/bin/bash
#check ftp service status
networksetup="/usr/sbin/networksetup"
say="/usr/bin/say"
tail="/usr/bin/tail"
head="/usr/bin/head"
cut="/usr/bin/cut"
currentInterface=$(networksetup -listnetworkserviceorder |tail +2 |head -n1 |cut -c5-12)
SiriSays="say -v Samantha"
if [ "$currentInterface" = "Airport" ];
then
networksetup -getpassiveftp Airport |$SiriSays
else
networksetup -getpassiveftp Ethernet |$SiriSays
fi
exit
Then apply the appify script to them
What you're left with is three little apps to put in your dock that, when launched, will start or stop the ftp service on your preferred network interface, or tell you what's up with ftp, respectively, and should not require any admin password. I only had time to test the first one, so if they don't work as I hope they do, then you can comment out or delete my logic and use your launchctl method.
Buscar's comment made me check the process hierarchy and it turns out, a service is a sub-sub-sub process of the application that launched it.
So, even though in many cases, a query for the frontmost application
may be ok, I think looking at the process tree is better.
Here is some sample code from a test Service Workflow that for me appears to work every time...
on run {input, parameters}
set arpid to (do shell script "echo $PPID")
display dialog "Automator Runner PID is: " & arpid
set srpid to (do shell script "ps -o ppid -p " & arpid & " | tail -1")
display dialog "Service Runner PID is: " & srpid
set appid to (do shell script "ps -o ppid -p " & srpid & " | tail -1")
display dialog "Application PID is: '" & first word of appid & "'"
tell application "System Events"
set activeApp to (name of first process whose unix id is (appid as integer))
end tell
display dialog activeApp
return input
end run
Best Answer
Yes, it is definitely possible.
I don't think the logic that it is necessary that a paid application is opaque and static is true. It is entirely possible to sell software while providing access to the source code and letting the customer modify it. Software has been sold that way by large and small companies for decades.
If you really want a technical solution, you can use obfuscation to hide the plain text of scripting languages such as AppleScript. Some languages have an eval-like functionality enabling you to deobfuscate source code and run it directly, whereas for AppleScript you probably want to store it in a seperate object file and run it - or employ OSAKit to be able to run the source directly.
Most programmers in closed-souce, commercial software would probably not employ such "tricks", but rather go for a compilable language such as Swift, Objective-C, C++ or similar to get an executeable that is not immediately "readable" by humans.
Note that all software that can be run can also be reverse-engineered.