---------------------------------------
Licq Plugins Howto v0.2
Graham Roff
---------------------------------------

This document is not nearly complete and is only intended to give a
bried introduction to the main ideas behind the licq plugin system.
Careful perusal of the licq and qt4-gui plugin source code is a good
place to find out more.

1.0  Introduction (IPC and Initialization)

Writing a plugin for licq is not too complicated.  There are two main
ways for inter-system communication, signals and events.  

Signals are asynchronous and indicate some general change or occurance
which the plugin might be interested in being aware of.  Signals include
when your status changes, when a new message arrives, and when you log
on successfully.

Events are synchronous to the extent that they are a response to
something which the particular plugin started.  For example the plugin
might call icqSendUrl() to send a url, and will receive a notification
event in response indicating the success of failure of this call.

The arrival of a signal or event is indicated by activity on a pipe,
specific to each plugin.  Each character read from the pipe can be any
of PLUGIN_SIGNAL, PLUGIN_EVENT, or PLUGIN_SHUTDOWN.  A signal or event
is read from the daemon simply by calling PopPluginSignal() or
PopPluginEvent().

There are three main things each plugin must do:

1.  Each plugin must include plugin.h and implement the functions
    prototyped within.  These functions are described inside this header
    file.  The main ones are:
    LP_Init(int, char **): This function is called to initialize the
    plugin, and is passed any command line arguments applicable.  The
    function should return whether or not it was successful in
    initializing the plugin.
    LP_Main(CICQDaemon *): This function is called within its own thread
    and should actually run the plugin.  It can exit by calling
    LP_Exit(int) or by returning an integer return code.

2.  Each plugin must register with the licq daemon it gets passed in
    LP_Main().  This is done simply by calling CICQDaemon::Register().
    This function returns the descriptor of the pipe to listen on for
    notification of signals and events.  If a plugin exits without either
    calling CICQDaemon::Shutdown() or receiving a shutdown signal then it
    must call CICQDaemon::Unregister() to unregister itself.

3.  Each plugin must exit properly when it receives a PLUGIN_SHUTDOWN
    character on the notification pipe.  This simply involves calling
    LP_Exit() or returning from LP_Main().


2.0  Multi-threading Issues

Licq is a fully multi-threaded program and as such there are some important
issues to be dealt with when writing plugins.  First, any requests to get
user information have been made thread safe (henceforth refered to as mt-safe)
through a simple database type checkout system.  Given a uin, a pointer to 
the relevant user is obtained by calling gUserManager.FetchUser(<uin>, <lock type>)
where the <lock type> is either LOCK_R or LOCK_W depending on whether one wants
read or read/write access to the user (note that many threads may have a user
locked for reading at the same time, but only one thread may have a user locked
for writing, so avoid doing so if possible).
The same idea applies to groups: gUserManager.FetchGroup(<group id>, <lock type>).

Certain system calls should also be avoided or their mt-safe counterparts used.  These
include:
strerror (on some systems this call is mt-safe, use strerror_r to be sure)
gethostbyname (use gethostbyname_r, see socket.cpp for an example)
and any other call that uses an internal static buffer.
