Creating an AIM Lite Plugin to Send a File

by Doug Schwartz
July 11, 2007

Introduction

In my previous article, I created an AIM Lite plugin that sent a text file as part of an IM. In this article I show a simple way to send any file during an IM session, using a new plugin.

The sending plugin lets the user select any file and sends that file to their current buddy.

We are going to create the plugin in the following order:

  1. Create the plugin.xml file.
  2. Create the main.box file.
  3. Create the main.js file.

Creating the plugin.xml File

The plugin.xml file contains a single widget element. This element can contain a number of subelements, but the only required subelement is the uuid, which is a developer or deployment key. The only differences between this plugin.xml file and the one for the receiving plugin are the uuid, name, and description. Don't forget to replace YOUR_DEVELOPER_KEY with your developer key in the following code.

<?xml version="1.0" encoding="utf-8" ?>
<widget
    uuid = "{YOUR_DEVELOPER_KEY}"
    version = "1.0"
    name = "SendFile"
    description = "This plugin sends a file"
    vendor = "Me, Myself, and I Inc."
/>

Creating the main.box File

This file is exactly the same as the main.box for the receiving plugin. The main.box file contains a single window element. This element defines the user interface (UI) for the plugin. A plugin can be visible, invisible (no UI), or only visible in response to an event. The plugin is invisible, and main.box contains the following text:

<?xml version="1.0" encoding="utf-8" ?>
<window
    xmlns="http://www.aol.com/boxely/box.xsd"
    xmlns:s="http://www.aol.com/boxely/style.xsd"
    xmlns:on="http://www.aol.com/boxely/reaction.xsd"
    on:constructed="onConstructed();"
    on:destroyed="onDestroyed();"
    s:height="0"
    s:width="0"
    hidden="true"
    collapsed="true"
    floating="true"
>
  <code id="main" language="jscript" src="main.js"/>
</window>

You can easily tell the plugin is invisible by the hidden="true" element. If the window weren't defined as "hidden," then a new window would pop up onto the screen each time the plugin was instantiated (i.e., each time AIM Lite is run). In fact, a new window is created for each plugin you install, but for plugins that perform most of their work in the background, the windows never appear because the plugin windows are declared as hidden in main.box.

Creating the main.js File

The main.js file is where the plugin's operational activity is coded. The main differences in this code for the current plugin versus the previous plugin is that in this plugin, the sendFile function utilizes a SecondaryManager object to send the file.

GetSecondaryManager is a member of the IAccSession interface. IAccSession is the main interface for accessing AIM functionalities. If you're going to be programming using the AIM SDK, IAccSession is something you'll need to learn about. The new online AIM SDK documentation has all the details of the IAccSession interface.

The first five lines of main.js contain five global variables.

var kCommandId = 0;
var gSession;
var sendTo; 
var AccSecondarySessionServiceId_FileXfer = 3; 
var AccFileXferFlags_ForceNonSecure = 0x2;

Where:

kCommandId
defines the integer value of the plugin command
gSession
caches the session object
sendTo
contains the name of the current buddy
AccSecondarySessionServiceId_FileXfer
identifies a secondary session that is sending files to another user
AccFileXferFlags_ForceNonSecure
identifies a non-secure call

Other than the cmd.text assignment, the onConstructed function is the same as in the previous plugin.

function onConstructed() {
var dict = scene.paramsDictionary;
gSession = dict.valueForKey("session");

var pInfo = dict.valueForKey("pluginInfo");
var cmd = pInfo.addCommand(kCommandId);
cmd.text = "Send file to current buddy";

scene.connectObject(gSession, "session_");
dict.setValueForKey(new commandListener(), "commandTarget");
}

As in the previous article, the sending plugin traps the IM in the BeforeImSend function to get the name of the current buddy. It saves the name of the current buddy in the sendTo variable. We will use this later to create the IM we send.

function session_BeforeImSend(session, imSession, recipient, im) {
    sendTo = recipient.Name;
}

The Exec function only checks whether the incoming id is that of our command, kCommandId. If it is, Exec calls the sendFile function. Here is the Exec function.

commandListener.prototype.Exec=function(id, users) {
    if (id == kCommandId) {
        sendFile();
    }
}

The sendFile function is where the action is. It performs the following steps.

  1. Creates the Open File dialog window so the text file can be selected.
  2. Creates a SecondaryManager object.
  3. Sends the file.

Here is the code of the sendFile function.

function sendFile() {
   var filter = "All Files (*.*)|*.*||";
   var fileList = appUtils.openFileDialog(this.scene,
                                          "Open File",
                                          null,
                                          null,
                                          filter,
                                          false);
    
   if (fileList) {
      var theFile = fileList.getValue(0);       
        
      var xferMgr = gSession.GetSecondaryManager(AccSecondarySessionServiceId_FileXfer); 
       
      var xferSession = xferMgr.send(sendTo, theFile, "", AccFileXferFlags_ForceNonSecure);
    }
}

The appUtils.openFileDialog call brings up a file selection dialog window. Figure 1 shows an example:

The open file dialog
Figure 1. The Open File dialog window

A very interesting component of the sendFile function is the instantiation of the GetSecondaryManager method. GetSecondaryManager is a public member function in the IAccSession interface. Here's its declaration:

HRESULT GetSecondaryManager ([in] xp_int serviceId,[out, retval] IDispatch **ppiManager)

What's happening here is that we are creating a "secondary session," which the IAccSecondarySession interface reference also terms a "rendezvous" session. You've got your standard session where you're communicating with a buddy. Now, using GetSecondaryManager, we create a secondary session, a second communication bridge, which can be used for additional communication, but communication that may be non-standard and which happens behind the scenes.

In passing AccSecondarySessionServiceId_FileXfer to GetSecondaryManager, we're identifying what type of communication we'd like to configure in this particular secondary communication channel. The variable AccSecondarySessionServiceId_FileXfer is initialized as the value 3, which defines that the type of communication on the secondary channel will be file transfers.

There is a lot of flexibility available for secondary sessions. Here are the allowed communication types for secondary sessions:

ID AccSecondarySessionServiceID Variable Name Communication Type
1 AccSecondarySessionServiceId_Im Instant message
2 AccSecondarySessionServiceId_AudioVideo Audio or video
3 AccSecondarySessionServiceId_FileXfer Transferring files
4 AccSecondarySessionServiceId_FileSharing Sharing files
5 AccSecondarySessionServiceId_ShareBuddies Sharing buddy lists
6 AccSecondarySessionServiceId_Custom Open communications (defined by your programming)

As with any plugin, the sending plugin also needs to create the QueryStatus function. Here is the code for this function and the commandListener object.

function commandListener() {}

commandListener.prototype.QueryStatus=function(id,
                                               users) {
   return (id == kCommandId) ? true : false;
}

Testing the plugin

There is no easy way to test this plugin besides deploying it.

  1. Zip up plugin.xml, content/main.box, and content/main.js, to create SendFile.zip.
  2. Rename it as SendFile.awi.
  3. Double-click SendFile.awi.
  4. Open two AIM Lite clients (see "Creating Multiple AIM Lite Clients").
  5. Create an IM session between the two AIM Lite clients.
  6. Select the SendFile plugin in one client.
  7. Select and send a file.

Creating Multiple AIM Lite Clients

You can create multiple AIM Lite clients on the same computer by using the standalone option. Open a command window, navigate to the AIM Lite folder (typically C:\Program Files\AIM Lite), and issue the following command for each client:

aimlite.exe -standalone

Conclusion

Now you understand how to send a file using AIM Lite. The next step would be to create a plugin that lets the receiver change the file name and location where the sent file is stored. I will do this in my next article.

Resources

  • SendFile.zip contains the complete source code for this article.
    If you want to see this plugin at work:
    1. Install AIM Lite.
    2. Unzip SendFile.zip to get the source files.
    3. Open the plugin.xml file.
    4. Change YOUR_DEVELOPER_KEY to your developer key.
    5. Zip the files back up.
    6. Change the file extension to AWI.
    7. Double-click the AWI file to install the plugin.

References

Here are a number of web pages where you can get further information about AIM Lite, plugins, and the source code for this article.

nice work

thanks for links