macdevcenter.com
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Build an iTunes Remote Control
Pages: 1, 2

Serving WAP via CGI (ala Perl)

You can get some very good context for running CGI on Apache here if you need an overview. For our purposes, CGI is simply a means of having a Perl script do two things: 1) provide the appropriate HTTP Response Headers for serving WAP content, and 2) pass messages to a daemon (currently lurking in the shadows) that controls iTunes. The stock installation of Apache with OS X has CGI configured to run by default.



To try CGI out, copy the following script into a file named index.pl, place it into /Library/WebServer/CGI-Executables, and set its permissions to be executable by Apache (user "www") with a chmod 755 index.pl in Terminal. If you know any Perl at all, you'll see that it simply writes out the content type header that the browser expects followed by each line of a file called "menu" (the body of a WML file). The file "menu" also needs to be saved to this same directory. For a quick crash course in Perl, check here.

Here's index.pl:

#!/usr/bin/perl

print "Content-type: text/vnd.wap.wml\n\n";

open MENU, "./menu" or die "'menu' not in current dir";
while (<MENU>) {print "$_";}
close MENU;

Here's the file "menu" that is simply a WML file; it looks strikingly similar to HTML content:

<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC
    "-//WAPFORUM//DTD WML 1.1//EN"
    "http://www.wapforum.org/DTD/wml_1.1.xml">

<wml>
    <card title="iTunes RC">
    <p><a href="/cgi-bin/RandomTrack.pl">RandomTrack</a></p>
    <p><a href="/cgi-bin/PlayPause.pl">Play/Pause</a></p>
    <p><a href="/cgi-bin/MuteUnmute.pl">Mute/Unmute</a></p>
    <p><a href="/cgi-bin/Rewind.pl">Rewind</a></p>
    <p><a href="/cgi-bin/FastForward.pl">FastForward</a></p>
    <p><a href="/cgi-bin/VolumeUp.pl">VolumeUp</a></p>
    <p><a href="/cgi-bin/VolumeDown.pl">VolumeDown</a></p>
    </card>
</wml>

Related Reading

AppleScript: The Missing Manual
By Adam Goldstein

You should be able to open the URL http://your-ip-address in your phone or a WAP emulator and successfully have Apache serve this menu to you. Recall that the extra /cgi-bin/index.pl that fully identifies the URL is implicitly understood through one of the earlier modifications to Apache's configuration file. If you're greeted by a "Forbidden" message instead of seeing the menu, check file permissions on the Perl script; permissions often cause hang ups, but it's to protect us from ourselves, right?

The Rest of the Perl Scripts

So what about all of those other self-naming Perl scripts referenced in index.pl? The short answer is that they do what they say they do by getting a corresponding AppleScript to control iTunes. The longer answer involves a quick aside to explain security permissions.

When we run a Perl script or any other executable on our machine, we run it as the user we logged in as. Except for root level actions, our user login usually gets the job done. When Apache runs a script, however, it runs it under the special user account "www" that is limited in some ways. In short, this is a security precaution. It's impact on our design is minimal, but at the same time, sort of frustrating.

To illustrate the design impact, consider the following scenario: If I execute a Perl script as user "matthew" that contains a line of code executing an AppleScript, the AppleScript executes just fine under the veil of user account "matthew" as well.

User "matthew" runs the Perl script, so user "matthew" inadvertently runs the AppleScript, which then sends Apple events to an application like iTunes (an application also running under user account "matthew"). This scenario isn't possible for our iTunes remote control because the Perl scripts and embedded AppleScripts are executed by Apache under user account "www", and user "www" can't send Apple events to applications (not to mention iTunes running under the different user account "matthew").

For our specific purpose, we can circumvent the inability of Apache to run AppleScripts the way we'd like by having the CGI script write a particular command to a file that a background daemon periodically checks and acts on. If this daemon process is running under our normal user account, the daemon can execute AppleScripts and consequently send Apple events to iTunes. This the long way around, but it does get the job done and is reasonably secure. If you ever need to do something fairly complex involving CGI and AppleScript, have a look at ACGI Dispatcher. It might save you some time at the cost of a few meals.

Let's get rolling again with some more code. Consider the following Perl script, PlayPause.pl, that Apache executes when you click on the corresponding link in index.pl:

#!/usr/bin/perl -w

system "echo 'PlayPause' > /tmp/iTunesRemoteControl";
system "chmod uga+rw /tmp/iTunesRemoteControl";

print "Content-type: text/vnd.wap.wml\n\n";

open MENU, "./menu" or die "'menu' not in current dir";
while (<MENU>) {print "$_";}
close MENU;

This Perl script writes the command "PlayPause" to a file in a temporary directory where everyone has write permissions, changes its permissions so that the daemon (that's our next step) can modify it, and then redisplays the main menu.

The Daemon Glue

Without further adieu, here is the daemon that completes the process:

#!/bin/bash
##########################################################
#Matthew Russell -25 Feb 05
#Usage: prompt$./iTunesRemoteControlDaemon.scr &
#
#This simply reads a file and executes an AppleScript that 
#controls iTunes based on its content.
#
#kill the daemon using the companion script killDaemon.scr
##########################################################

############
#User Prefs
############
scriptDir="/Library/WebServer/CGI-Executables"
remoteCommand="/tmp/iTunesRemoteControl"
delay="1.0"


#############
#begin script
#############
while [ 1 ]; do

status=`cat $remoteCommand`

case $status in
    "RandomTrack") osascript $scriptDir/RandomTrack.scpt;;
    "Rewind") osascript $scriptDir/Rewind.scpt;;
    "FastForward") osascript $scriptDir/FastForward.scpt;;
    "MuteUnmute") osascript $scriptDir/MuteUnmute.scpt;;
    "PlayPause") osascript $scriptDir/PlayPause.scpt;;
    "VolumeDown") osascript $scriptDir/VolumeDown.scpt;;
    "VolumeUp") osascript $scriptDir/VolumeUp.scpt;;
esac

echo "" > $remoteCommand
sleep $delay

done

So as you can see, it's simply a matter of having a daemon script pick up a message from a file and execute a corresponding AppleScript. This would be a good time to check out the man pages for the osascript command and take a crash course in Bash scripting.

I've conveniently bundled all of the scripts here for you along with some troubleshooting help in a README file. Take this archive and extract its contents to your /Library/WebServer/CGI-Executables directory. You must give all of the Perl scripts proper permissions with chmod 755 *.pl. Also, give your daemon executable permissions from your user account with chmod u+x. When all else fails, check and recheck file permissions.

All of the AppleScripts provided can be inspected in the Script Editor via Terminal with open [ScriptName]. All of them are too simple to merit explanation. For example, consider PlayPause.scpt:

tell application "iTunes"
	playpause
end tell

Any questions? If you want some more information on AppleScript, a good place to start is here on Apple's site.

Final Thoughts

The scripts provided do most of the common things you'd want to be able to do from an iTunes remote control. If you want more customization, adapt some of the existing AppleScripts out on the web to fit your needs. Doug's AppleScripts for iTunes is a good starting point. If you plan to keep your remote control up for extended time periods, you'll want to design a simple login system that requires some form of authentication. You can easily do this with another short CGI script. What could be worse than an unknowing web surfer waking you up at night with random music?

Following the design pattern for this remote control, you can control a lot more than iTunes. Stay on top of your web server's security, and have fun.

Matthew Russell is a computer scientist from middle Tennessee; and serves Digital Reasoning Systems as the Director of Advanced Technology. Hacking and writing are two activities essential to his renaissance man regimen.


Return to MacDevCenter.com.