FIBS Companion Programmers guide






There are two related portions to programming a plugin for the companion: FIBS Companion tasks and GUI integration. I will start with tasks.

FIBS Companion Tasks

In order to understand FIBS tasks, you need to understand that the companion is a socket proxy server with two stream handlers in action when the proxy is running: one for handling "upbound" traffic (that is traffic moving from the local client to the target server) and one for "downstream". Each handler has a queue of tasks that it cycles through while handling its' stream. Tasks are written by the plugin author, and must implement the Task (jave) interface below:
interface Task {
public boolean isDone();
public boolean match(String input);
public void run(Vector strings);
}

A simple example might be a plugin that wants to inject a FIBS command in the upbound stream such as "waitfor marvin". Such a task might look like this:
class WaitforTask implements Task {

//create a WaitforTask for the designated user
public WaitforTask(String username) {
this.username = username;
}

public boolean isDone() {
return this.done;
}

//we don't care what the current string is, just do this ASAP
public boolean match(String s) {
return true;
}

//the handler will pass us the strings it is currently buffering
public void run(Vector strings) {

//mark it as done as soon as it runs, as we only want to do this once
this.done = true;

//insert a waitfor string in the handlers' buffer
strings.insertElementAt("waitfor " + this.username, 0);
}

//initially false
private boolean done = false;

//set at construction time
private String username = null;

}
To make use of such a task, one would presume that a result is required, so a corrosponding task to trigger some notification in addition to whatever the client does might look like this:
class UserWaitTask extends java.util.Observable implements Task {

//create a UserWaitTask for the desingated username
public UserWaitTask(String username) {
this.loginUserString = username + "logs in";
}

public boolean isDone() {
return this.done;
}

//we only execute if the designated user has logged in
public boolean match(String s) {
return s.equals(this.loginUserString);
}

//the handler will
public void run(Vector strings) {

//once the designated user logs in, mark the task as done and notify it's Observers
this.done = true;
this.notifyObservers();

}

private String loginUserString = null;

private boolean done = false;

}
Now that we have the tasks defined for what we want to do, we must insert them into the handlers. Each plugin is required to implement the Plugin interface:
interface Plugin {
void setConnection(Connection connection);
}
This method will get called when the connection to fibs is established. Typically, this connection is in place at the time the module is created, so this method will be called right after the constructor. The Connection object encapsulates the "Down" and "Up" handlers, which in turn both contain an add and remove methods for Tasks.

Note that the code to insert our example tasks above should insert the response task first (UserWaitTask) before the query task (WaitforTask), to ensure that the response is not missed.

Another problem that needs to be avoided is the dreaded "missed input" problem that FIBS sometimes exhibits, that is, sometimes an upstream command that is sent gets completely ignored if FIBS is not ready for it. Many FIBS commands have "confirmation" responses that can be detected. For the waitfor command, several responses are possible, depending on how many users you are already waiting for and who you are waiting for. An additional response task could be written to confirm that the query went through. A utility function could put it all together with retries and a timeout, and the plugin could be written to take all this into account. I will leave all this as an exercise for later.

plugin GUI coding

The FIBS Companion allows you to install your plugin into an existing companion installation. You need to be sure that you have implemented and have a connect
lazy instanciation
numbering
connector methods, getIcon, getName...
example