PluginDevelopersGuide
From AMSN
What Is An aMSN Plugin?
Plugins extend the functionality of aMSN. Some plugins (such as the Nudge plugin) are included with aMSN. Others are avaliable on the plugins page of the aMSN website.
What Do I Need To Create A Plugin?
All you need is the latest version of aMSN, and a plain text editor (not a WYSIWYG editor like MSWord or OOWriter, but something like gedit on Linux, Smultron on Mac OS X, and Notepad2 for Windows).
A knowledge of Tcl/Tk would also help!
What Is The Directory Structure Of A Plugin?
The most basic plugin requires one xml file called plugininfo.xml, and a Tcl source file. The plugininfo.xml file should be layed out like this:
<?xml version="1.0"?> <plugin> <name>The Plugin's Name</name> <author>Your Name</author> <description>A short description of your plugin</description> <description_fr>A translated description in French (fr).</description_fr> <amsn_version>The oldest version of aMSN the plugin will work with.</amsn_version> <plugin_version>The plugin's version.</plugin_version> <plugin_file>the name of the source file (ie. pluginName.tcl).</plugin_file> <plugin_namespace>Your plugin's namespace (only A-Z,a-z,0-9 characters here).</plugin_namespace> <init_procedure>The name of your init procedure.</init_procedure> <deinit_procedure>The name of your deinit procedure.</deinit_procedure> </plugin>
Your tcl source file must have the namespace described in the xml file, and the init & deinit procedures must also exist within your plugins namespace or your plugin will not load.
Your Tcl source file should look like this:
namespace eval ::namespace {
proc init { dir } {
::plugins::RegisterPlugin "Plugin Name (As In The XML File)"
::plugins::RegisterEvent "Plugin Name (As In The XML File)" postEvent localProcToCall
}
proc deinit { } {
#Clean up?
}
}
How Do Plugins Work?
Plugins rely on events in aMSN called PostEvents. These are called when events happen, such as changing state, or a new message is recieved or another similar event.
List of events
Here is a full list of events (SVN r8478):
| FileName or Event | Parameters | Description |
| abook.tcl | ||
| parse_nick | variable login | Before a nick is stored into abook. |
| automsg.tcl | ||
| ChangeMyState | automessage idx | When the user changes his state. |
| chatwindow.tcl | ||
| chatwindow_closed | chatid | When a window is destroyed. |
| new_conversation | chatid usr_name | When a window is created |
| chatmenu | window_name menu_name | When the chat menu is being created. |
| chatwindowbutton | window_name bottom | When the buttons in the chat window are being created. |
| new_chatwindow | win | When a new chat window is opened. |
| chatwininput | input buttons picture window | |
| chatsendbutton | window_name bottomleft | |
| TopUpdate | chatid win_name user_list | When the top of the window is updated with the user names and states. |
| gui.tcl | ||
| chat_ink_send | nick ink chatid win_name | Before an ink is sent. |
| chat_ink_sent | nick ink chatid win_name | After an ink is sent. |
| user_joins_chat | usr_name chatid win_name | When an user joins a chat. |
| user_leaves_chat | usr_name chatid win_name | When an user leaves a chat. |
| chat_msg_send | nick msg chatid win_name fontfamily fontstyle fontcolor | Before a message is sent. |
| chat_msg_sent | nick msg chatid win_name fontfamily fontstyle fontcolor | After a message is sent. |
| chat_msg_receive | user msg chatid fontformat message | Before a message is recieved. |
| chat_msg_received | user msg chatid fontformat message | After a message is recieved. |
| mainmenu | menu | When the main menu is created. |
| new_conversation | chatid usr_name | When a new conversation begins. |
| WinWrite | tagname winname msg | Before text is written to the window. |
| WinWritten | tagname winname msg | After text is written to the window. |
| OnDisconnect | email nick | When you get disconnected. |
| ContactListColourBarDrawn | colorbar text | Straight after the colour bar is drawn in the contact list. |
| ContactListEmailsDraw | text msg | Just before the emails line is drawn in the contact list. |
| ContactListEmailsDrawn | text | Straight after the emails line is drawn in the contact list. |
| ChangeMyState | automessage idx | When the user changes his state. |
| right_menu | menu_name user_login | |
| xtra_choosepic_buttons | target win | |
| loging.tcl | ||
| ft_loged | email txt | When a filetransfer is logged |
| msnp2p.tcl | ||
| WinkReceived | chatid filename | When a wink is received. |
| plugins.tcl | ||
| Load | name status | When a plugin is loaded. |
| PluginConfigured | name | When a plugin's configuration is being saved. |
| protocol.tcl | ||
| contactlistLoaded | ||
| DataCastPacketReceived | chatid typer nick msg id data | |
| PacketReceived | chatid typer nick msg | |
| ChangeState | user substate | When a contact change his/her state. |
| UserConnect | email user_name | When a contact get's connected. |
| OnConnect | When a contact get connected. | |
You subscribe to PostEvents, and when they occur, a specific procedure (which you select) in your plugin will be called. The parameters that occur with a PostEvent are variables which you can read and write to. You can therefore alter the way aMSN functions.
How Do I Subscribe to a PostEvent?
This is done during your plugin's init procedure. First you must register your plugin by running this:
::plugins::RegisterPlugin "Plugin Name (As It Appears In The XML File)"
You can then subscribe to a PostEvent by calling this function in your code:
::plugins::RegisterEvent "Plugin Name (As It Appears In The XML File)" postEvent functionToCall
Your functionToCall must have two arguements: event & epvar. For example:
proc functionToCall {event epvar} {
#Interesting stuff goes here!
return 1
}
How Do I Access/Modify Variables Sent By A Post Event?
The argument "epvar" set by the PostEvent is an array of all the various parameters that are avaliable for the post event. At this point you need to decide if you want a copy of the variable, or if you want to modify the variable (so that aMSN will use your version of the variable instead of it's own).
To Get A Copy Of A Variable
Run this in the function called by the post event:
upvar 2 $epvar args set localVariableName $args(parameterName)
Any changes you make to localVariableName, will not edit the way aMSN functions.
To Modify A Variable
Run this in the function called by the post event:
upvar 2 parameterName parameterName
You can then refer to the parameterName variable, and any changes you make will be reflected back to the copy that aMSN uses.
How Do I Make My Plugin Configurable?
You need to add a list of configurable options for your plugin inside it's namespace. Not inside any of the procs, but just inside the namespace. The options for the type of data you can store are as follows:
| DataType | Description |
| str | String (Plain text). |
| pass | Same thing as str, but for password. |
| bool | Checkbox (1 or 0, activate or desactivate). |
| rbt | RadioButton (Returns the index number of the selected radio button). |
| ext | Action button, the 3rd key here is the command we give to the button. |
| label | Just a place to write some text to describe all the configuration stuff. |
| frame | Frame to put your own custom stuff in, third argument is a proc (with namespace) that takes one argument which will be the path to the window. |
| lst | A listbox of items where one will be selected. 3rd is a list of values and 4th is the name. |
Here's an example of a plugins configlist:
set ::namespace::configlist [list \ [list str "Label" variableName] \ [list pass "Label" variableName] \ [list bool "Label" variableName] \ [list rbt "Item 1 Label" "Item 2 Label" indexNumberOfCurrentRadioButton] \ [list ext "Button Text" command] \ [list label "Label Text"] \ [list lst "Item 1" "Item 2" selectedItemName] \ ]
To set default values for your plugin, then place this in your init proc. If the user changes a value, then the user's choice will override your default values:
array set ::namespace::config {
variableName {"defaultValue"}
}
How Do I Make My Plugin Translatable?
First create a folder inside your plugin called lang. Then create langfiles within this folder with their calling the files lang followed by their locale name. IE for an English lang file, you would put langen. The structure of a langfile is as such:
item1 Translated text for item 1. item2 Translated text for item 2.
You must also place these lines in your init proc (which must have $dir as an arguement):
# Load english by default, then load the current locale if it's avaliable. set langdir [file join $dir "lang"] load_lang en $langdir load_lang [::config::getGlobalKey language] $langdir

