Scripting


Understanding scripting will give you a handy set of new abilities and ways to use Snak. In many cases you can use an Action to automate Snak's behavior but there are things that go beyond the capabilities of an Action. For those cases, knowledge of regular scripting will be useful.

You can use scripting to complement or even replace some of the built in commands with aliases to provide enhanced functionality. Snak looks for script files in the Scripts folder. The Scripts folder is found in the Application Support folder. You can use the menu item in Window menu to open the folder directly.
A script can be a mini-program with variables and functions, a simple command alias, an entry in the Scripts menu or a command to run in an Action. An alias complements the built-in commands and is used the same way, but it is still a script. The term simply refers to a sequence of program instructions.

Snak supports two different scripting languages - AppleScript and ircII (pronounced irk 2) and come with extensive examples of scripts written in both languages. The two languages differ in their focus, their access to the internal data of Snak, their ease of use and their speed, but you can use scripts written in both languages side by side to get the most benefits of both environments.

Scripts in the ircII language are regular text files that can easily be edited with a text editor, like BBEdit, TextWrangler or even SimpleText. If you edit them in a word processor, please take care to save the files as pure text without formatting or they will become unusable.

AppleScripts are created with the Script Editor application that comes with the operating system. There are also third party script editors and debuggers available that will let you examine a script while it's running to easily debug it.

IMPORTANT: AppleScripts must be saved in compiled form in order for Snak to use them.
For both types of scripts, be sure not to include spaces in the filename under which you save them. You can open the Command Reference from the Help menu to get a full listing of all the loaded scripts and commands. To see the folder with all the available scripts, please use the "Show Script Folder" item in the Scripts menu.

Each connection maintains its own list of loaded scripts, so that you can modify the behavior and use of each connection. For example, one connection could be used to run an automated service, called a bot and another could be used normally.

Standard script files


When you open a connection, the program will automatically read in the contents of the basical and action script files from the Scripts folder. These files contain aliases that extends the built-in command set and serves as examples of how to extend and modify Snak's behavior. The files have informative comments and explanations to help you understand what is going on.

The /msg and /query aliases in the script file called basical are examples of command aliases. They redefine the built in commands of the same names to allow you to use abbreviated nicks for the people you send private messages to. Aliases are also used to provide shortcuts for frequently used commands like /join. For examples the /j alias simply calls the /join command.

The script file action contains a number of small scripts to provide atmosphere, like /sing, /shiver, /slap and many more.

Included with Snak is a complete script package called PurePak, which contains extensive functionality for both channel operators and normal IRC users. It can maintain list of friends and enemies on IRC that can be set up to auto-op friends and try to avoid enemies. It has functions for channel management, and file exchange, and it comes with extensive built-in help. To load purepak, type "/load purepak.irc" and notice the intro messages that come up. The built-in help is accessed with /pphelp and an optional topic like /pphelp main.

Scripts can be complex multi-line programs like PurePak or they can be simple abbreviations of frequently used commands. You are encouraged to study the example script files that come with the program to learn details.

Snak also come with a large number of scripts written in AppleScript. Please see the read me files in the Scripts folder for more information. The Musical script is an extensive package for controlling iTunes from Snak, and for broadcasting information about what songs you are listening to. It can listen for specific messages containing an artist name or song title. If it finds such messages it will instruct iTunes to play the appropriate song. The script comes with its own read me file with full instructions.

AppleScript


AppleScript is a scripting language. Scripting languages have all the capabilities of other programming languages, but are easier to use because their structure is closer to everyday English.

AppleScripts can store data for later use and examine their surroundings to determine what to do next. They can also loop through certain instructions, repeating them as many times as you like, or until something specific happens. These features, and others, are what makes a scripting language - particularly AppleScript ideal for anyone that wants to automate a task.

AppleScript is different from other scripting languages because its reach isn't limited to a single application. AppleScript is part of the Macintosh operating system, and that enables it to work with several different applications at once if necessary. You can extract data from one application and hand it to another for processing with AppleScript, and it can even be used to control other Macs over the network.

How to start


There are many good books about AppleScript, and I can in particular recommend "The TAO of AppleScript" by Derrick Schneider and "AppleScript Language Guide" from Apple.
In order to write an AppleScript that uses Snak, you need to open the Script Editor application that was installed as part of your operating system. It is found in the AppleScript folder in the Applications folder.

There are five main parts to AppleScript:
• Objects - which points to items and information inside the application
• Commands - which acts on those items and information
• Variables - which allows you to store data for later use
• Conditionals - which enable your script to make decisions based on a set of conditions
• Repeat loops - which give you the capability to execute commands repeatedly

Every scriptable application contains a dictionary of the commands and objects it knows about. To see the Snak dictionary, run the Script Editor and select "Open Dictionary" under the file menu and select the Snak application:

Under the heading "Snak Suite" you see all the commands you can send to Snak -
• connect - sent to an IRCConnection object to open a connection.
• disconnect - sent to an IRCConnection object to close a connection.
• echo - sent to a target (a channel, filter, query etc.) to display a message locally. The message is not sent out.
• type - sends a command or message to a specific target as if the user had typed it directly.
• match - used for fast matching of strings against a pattern.
• store data - used to let a script store a setting in the Snak preference file.
• load data - used to let a script retrieve a setting from the Snak preference file.

Command provided for compatibility with older scripts:
• do - sends a command to a specific target as if the user had typed it directly.

This command should not be used in new scripts.

and all the objects you can access through AppleScript -
channels, connections, users, ignoreitems ... and many more.

In the dictionary you will notice that in order to access some objects you have to go through other objects. This is called an object hierarchy.
Snak's object hierarchy is:
• The application contains connections (and more)
• A connection contains channels (and more)
• A channel contains users (and more)

Your first AppleScript


This is an example of a simple, yet (somewhat) useful little script. Once it's loaded into Snak you will be able to type "/countops" to have the script tell you the ratio of channel operators to normal users. The script asks Snak how many users are in the current channel, and how many ops there are among them. Then it calculates the ratio and displays a message.

Open the Scripts folder by choosing "Show Script Folder" in the scripts menu. That will cause the Finder to display the folder where it is. Open the folder itself by doubleclicking it.
In this folder is a script called "countops". Double click this file to open the Script Editor. This will open a window with the text of the script. I have added the line numbers for convenience.


line 1: on run
line 2: tell application "Snak"
line 3: set n to NumberOfUsers of channel CurrentChannel of connection CurrentConnection
line 4: set ops to count (get (every user whose op = true) of channel CurrentChannel of connection CurrentConnection)
line 5:
line 6: if n > 0 then
line 7: set percent to ops / n * 100 as text
line 8: else
line 9: set percent to 0 as text
line 10: end if
line 11:
line 12: set percent to (round (percent + 0.49))
line 13: set CommandString to "/me sees " & ops & " gods and " & n - ops & " mortals on " & currentchannel & ".
line 14: " & percent & "% of the people in " & CurrentChannel & " are gods."
line 15: do CommandString
line 16: end tell
line 17: end run

The above script shows examples of objects, commands, conditionals and variables. The bold words are part of the AppleScript language itself, and the Script Editor will automatically format them.

Starting with line 1: "on run" this is a line that tells Snak in what situation to run the snippet, namely when the uses types "/countops". Other situations are explained later when event handlers are introduced.

Line 2: "tell application "Snak"" is used by the AppleScript system itself and is used to set the target for the following block of AppleScript. Notice how the Script Editor automatically indents the following block.

Now we get to the core of the little script, the place where the interesting action takes place. Line 3 uses both objects and a variable.
"set n to NumberOfUsers of channel CurrentChannel of connection CurrentConnection"

Once you learn how to recognize the individual pieces of the statements they will become understandable and logical.
Here we ask Snak a complex question - how many users are there in the current channel on the current connection, and we store the result into a variable called "n". The channel and the connection are examples of objects.

A central concept in understanding AppleScript is that most scriptable applications have an "object hierarchy" meaning that objects are nested inside each other. You ask the top object (the application) for an object (the connection) that contains your ultimate goal (the channel), and then you ask that channel object for specific information like the number of users.

Line 2: "tell application "Snak"" which you saw first points out the top object (the application) and the "set n to ..." line will first ask for the connection from the application, and then ask for the channel from the connection, and then it asks the channel for the number of users. Try and read the line from the right and you will see the sequence.

Line 4 is quite complex.
"set ops to count (get (every user whose op = true) of channel currentchannel of connection currentconnection)"
Like line 3 it uses a variable and objects, but it also introduces a conditional operation. Again we find a channel object but this time we ask it for a list of all users in the channel whose "op" status is true, meaning that they are channel operators. Then we take the number of results and store in a variable.
The "whose" conditional allows you to easily gather a collection of objects that satisfy a condition.

The next few lines perform the ratio calculation, and put together the string of text that Snak should display with the result.

"set CommandString to "/me sees .."
This line looks difficult, but all it does is to pull together the information we've already found, and fill out a variable that holds a line of text. The '&' character is used to concatenate two pieces of text.

You may recognize "/me" as a Snak command, but this line just puts together a line of text that starts with the "/me" command. The line is stored in a variable called "CommandString".

As you look at the line you can recognize the variables that were defined above to hold the number of users, the number of ops and the ratio. If for example, there are 4 users on channel #macintosh, 2 of which are ops the string will end up looking like this: "/me sees 2 gods and 2 mortals on #macintosh; 50% of the people in #macintosh are gods"

"do CommandString"

Finally we get to do an actual AppleScript command. We have a potential point of confusion here because we are mixing two different kinds of commands. There are normal Snak commands like you type in at the command line like "/me", and then there are Snak AppleScript commands like "do". The "do" Snak AppleScript command makes Snak execute a normal command as if you typed it in through the command line.

That means that you have access to all the built in Snak commands as well as any commands you define in the existing ircII language, from within an AppleScript.

So the "do CommandString" line simply executes the "/me sees ..." command as if you had typed it in yourself, which result in the ratio of ops to normal users being written out and sent as an action message to the channel.

How to load and run AppleScripts


In order to use an AppleScript it needs to be loaded into Snak. Type "/load scriptname" to make Snak read in and prepare the script to be run. If you have a handler in the script called "on load" it will be called right away. Snak will also look for a handler called "on idle" and start executing it if it's present.

If you type the name of the script as a command, the "on run" handler in the script will be run. At this time it's not possible to pass parameters to an AppleScript command, so you are encouraged to use the ircII language to write command aliases. This shortcoming will be remedied.

During development of an AppleScript it's frequently useful to unload an existing script in order to modify it and try again. To unload an a loaded AppleScript type "/unload scriptname".

Snak implements a number of event handlers that enable you to implement extensive functionality and the number of handlers will be improved in the next version. I welcome your feedback and suggestions so be sure to let me know if you need a particular feature.

Event handlers


You can write simple command aliases in AppleScript, but the real power comes when you use "event handlers". These are snippets of AppleScript that you write and load into Snak. The events in an Action is another example of event handlers, except that the events in an Action comes with a predefined set of responses. If you write your own event handler in AppleScript you have complete freedom.

Snak will call your event handlers when particular events happen, like someone joining a channel, leaving a channel, saying something, sending you a private message and more. The event handlers lets you truly customize the way Snak works and responds to events.

Example: If you are an IRC server operator you will get a number of messages from the network itself about the various going ons. This may become annoying if the messages are of no relevance to you. With AppleScript you now have a way to intercept those messages and process or discard them without cluttering up the channels you are in.

Snak will, during its processing of the numerous different events, call some user-defined "hook functions" or event handlers. Depending on the output of these event handlers, Snak may or may not continue processing the event. This means that the user now has the ability to tailor Snak much more closely to his or her needs than ever before.

Snak comes with the script file SnakEventHandlers which contains examples of all the event handlers that Snak currently supports, and shows what parameters they require.

The following example employs an event handler called "on servernotice". Snak will call the servernotice handler whenever it receives a notice from a server as opposed to a normal user. The example script will then examine the text of the notice and if it contains the string [CLONES] the message will be redirected to a custom window in order not to clutter up the regular channel.

Notice how the return value of the handler in the case of a [CLONES] message is true. This means that the script has completely processed the event and Snak should not process it as well.

on servernotice(con, source, sourcehost, target, thestring)
set eventhandled to false
tell application "Snak"
try
if thestring contains "clones" then
tell connection con
echo thestring in filter "[CLONES]"
end tell
-- true tells Snak that this event is completely handled
set eventhandled to true
end if
end try
end tell
return eventhandled
end servernotice


on load()
tell application "Snak"
set con to currentconnection
tell connection con
type "/window new name [CLONES]"
echo "Clone catcher" in filter "[CLONES]"
end tell
end tell
end load

The script uses a dedicated panel for the output. The line "type "/window new name [CLONES]" will open a custom panel that you can use to display text that is filtered out of somewhere else. Such panels are called filter panels.

Stacked event handlers


Snak allows you to have multiple AppleScripts loaded and each of the scripts can implement whatever event handlers it wants. Snak will then call each event handler in turn until one of them returns true, meaning that the event was completely processed.

Snak comes with some sample event handler scripts that illustrate this. If you examine the input1 and input2 scripts in the script folder you will see that they both have an on input handler. If you load them with "/load input1" and "/load input2" and type the text that triggers the action, you will see that both handlers are called.

Likewise, idle handlers can be stacked. The idle1 and idle2 scripts both contain idle handlers and if you load them with "/load idle1" and "/load idle2" you will see periodic messages coming from both of them.

This support for stacked handlers will eliminate much complexity from large script packages.

IrcII scripting


ircII (pronounced irk-two) is the second of the two scripting languages that Snak supports. The language is used in several irc clients with minor variations which means that there is a large body of existing scripts that can be adapted or used directly.

Scripts made in this language can be used side by side with scripts written in AppleScript. A small ircII script is frequently the fastest way to create simple command aliases. You can create an Action to run a command when a certain event happens. This command can use the full range of the ircII language.

Some very large and comprehensive ircII scripts are available, but they can be hard to understand. It helps to have a programming background and be familiar with a language like C if you want to make complicated scripts in ircII or modify existing ircII script packages.

One of the largest and most powerful such packages is called PurePak and is included with Snak. PurePak can be a rich source for tips and inspiration once you have grasped the basics.

The ircII language is rich, expressive and complex. It has many intricacies and while simple aliases and commands are easily within the grasp of a beginner, large programs and script packages should be written in AppleScript unless you really want to learn the ircII language.

There are a number of web sites that contain scripts for the ircII client, and Snak is able to use most of those with only minor modifications.

The site http://www.irchelp.org contains scripts and also an extensive command reference and script guide that is highly recommended. Its location is: http://www.irchelp.org/irchelp/ircii/irciiman.wri

It has chapters on the full syntax of the commands and the correct way to use them. Among the wealth of information in the guide is the full description of the various conditional operators like "if", branching commands like "while", and the full range of expressions that can be written in ircII. If you want to learn ircII scripting, the guide is highly recommended.

It's not possible to access data outside of Snak using the ircII language because it's processed entirely inside the application. AppleScript can be used to tie together multiple applications and access outside data because it's processed by the operating system in cooperation with the application.

Where to start


Snak comes with a number of script files from the regular distribution of ircII, and you are encouraged to open them in a text editor like BBEdit, TextWrangler or SimpleText to see what you can do. Open the Scripts folder by choosing "Show Script Folder" in the Scripts menu. That will cause the Finder to display the folder where it is. Open the folder itself by doubleclicking it.
You will notice the useful /oops alias in the file called basical which uses an user defined variable.

In the file called action you will find an example of the "if" statement. This example sets a string containing the possessive (his/her/the) depending on a gender variable.
That gender variable is defined in the file action, so if you are a woman, you may want to change the gender to "F" in order to get the correct possessive. For more elaborate examples, look in the script files that came with the program.

Example 1: The /J <channel> alias


A simple example is the /j alias. It's simply used as an abbreviation for the normal /join command. If you look in the script file basical you'll see that alias j is defined as /join. /join is a built in command and can be used on the input line with a parameter, and so can /j.
When you type /j, the program will replace the alias with its definition, which in this case is /join.

Example 2: The /op <nick> alias


A slightly more elaborate example is /op. In order to convey operator status on someone you normally have to type /mode <channelname> +o <nick>
However the /op alias is defined as "/mode $C +o" and can be used to simplify this.

You can now convey op status by typing "/op <nick>". The alias makes use of a built-in scripting variable $C, and when the programs finds a variable in an alias the variable will be replaced by its value before executing the command.

Later in this chapter you will find a full list of the available variables and see what they represent, and $C contains the name of the current channel.
The <nick> part of the /mode command shown above is supplied by the >nick> parameter you typed after /op .

Example 3: The /oops <nick> alias


The alias /oops is is used to correct a message that went to, let's say John when it should have gone to Mary. The syntax is simply "/oops <intended nick>"

/oops is defined as

alias oops {
^assign alias.oops $B
msg $. Sorry, that wasn't meant for you.
msg $0 $alias.oops
}

Two new variables appear here : $B which always contain the text of your last message, and $. which is the last nick you messaged. The ^ character makes the assignment "silent", meaning no message is output when the line is processed.

The first line copies the text of the last message to an intermediate variable called "alias.oops". The second line sends a message to the last nick we messaged (John) to say "Sorry, that wasn't meant for you"." The third line resends the original text (stored in the intermediate variable) to the nick that was the first parameter to the alias (Mary).

In addition to variables like $C and $B there is also $0 ($zero) to $9 ($nine).

Numerical variables like that will be replaced by the corresponding argument from the input line. $0 will be replaced by the first argument, $1 will be replaced by the second argument
and so on. If the message is "one two three four", $0 would be "one", $1 is "two" etc. The numeric variables can be combined in a number of ways.

Example 4: The consoleClick alias


The aliases can be run from the input field, and you can also run a particular script when you double click on a user in either the user list or the notify list. The default command for a double click in the notify list is "ConsoleClick". ConsoleClick is an alias, which is defined as "/msg $E $0-".

This looks cryptic, but remember that a /msg always takes two pieces of input : the nick and the message. When Snak interprets the alias it replaces $E with the currently selected nick, and $0- with the entire contents of the input line.

Scripting variables


• Snak supports the numerical variables $0 thru $9. The numerical variables can be used individually or in ranges:
• $n- gives argument n through the last argument.
• $n-m gives arguments n through m.
• $-m gives the first argument through m.
• $* gives the entire contents of the input line. Same as $0-
• $. Nick of the last person to whom you sent a message.
• $, Nick of the last person who sent you a message.
• $: Nick of the last person who joined the channel.
• $; Nick of the last person who sent a message to the channel.
• $? Brings up a dialog where you can enter text. Syntax is $?="explanation"
• $B Text of the last message you sent.
• $C The name of the channel.
• $E Nick of the first selected user in the user list.
• $F User and host information about the first selected user in the user list.
• $I Name of the channel you were last invited to join.
• $J The text of the last private message you received. Used in the Respond contextual menu item to pass the text into the query window.
• $K The character (/) that is used to make the program process some input as a command.
• $N Your nick.
• $T Name of the current channel or query window.
• $W The current selection in the userlist. The nicks are separated by space.

User defined script variables


In the file action you can see an example of the how to affect the execution of the alias depending on outside values. As mentioned before, scripting is really a form of programming, and a programming languages has conditional statements.

This example demonstrates the "if" statement which takes one of two branches depending on a test. The result of the test is either true or false. The syntax for this statement is
IF (<variable-expression>) {<true-command/s>} [{<false-command/s>}].

The angled brackets [] mean that this section is optional, and can be omitted if there is no need to so something is the variable-expression is false. The example in the file is

     if (GENDER) 
{
if ([$GENDER] == [F])
{
assign POSSESSIVE her
}
{
assign POSSESSIVE his
}
}
{
assign POSSESSIVE the
}

This is actually two "if" statements inside each other. The outermost one test if the variable GENDER is defined at all. If not then it assigns "the" to the variable POSSESSIVE. If GENDER is defined then the program runs the innermost "if" which tests its value, and assigns "her" to POSSESSIVE if it's "F". Otherwise POSSESSIVE will be set to "his"