| 1 | --------------------------------------- |
|---|
| 2 | Licq Plugins Howto v0.2 |
|---|
| 3 | Graham Roff |
|---|
| 4 | --------------------------------------- |
|---|
| 5 | |
|---|
| 6 | This document is not nearly complete and is only intended to give a |
|---|
| 7 | bried introduction to the main ideas behind the licq plugin system. |
|---|
| 8 | Careful perusal of the licq and qt-gui plugin source code is a good |
|---|
| 9 | place to find out more. |
|---|
| 10 | |
|---|
| 11 | 1.0 Introduction (IPC and Initialization) |
|---|
| 12 | |
|---|
| 13 | Writing a plugin for licq is not too complicated. There are two main |
|---|
| 14 | ways for inter-system communication, signals and events. |
|---|
| 15 | |
|---|
| 16 | Signals are asynchronous and indicate some general change or occurance |
|---|
| 17 | which the plugin might be interested in being aware of. Signals include |
|---|
| 18 | when your status changes, when a new message arrives, and when you log |
|---|
| 19 | on successfully. |
|---|
| 20 | |
|---|
| 21 | Events are synchronous to the extent that they are a response to |
|---|
| 22 | something which the particular plugin started. For example the plugin |
|---|
| 23 | might call icqSendUrl() to send a url, and will receive a notification |
|---|
| 24 | event in response indicating the success of failure of this call. |
|---|
| 25 | |
|---|
| 26 | The arrival of a signal or event is indicated by activity on a pipe, |
|---|
| 27 | specific to each plugin. Each character read from the pipe can be any |
|---|
| 28 | of PLUGIN_SIGNAL, PLUGIN_EVENT, or PLUGIN_SHUTDOWN. A signal or event |
|---|
| 29 | is read from the daemon simply by calling PopPluginSignal() or |
|---|
| 30 | PopPluginEvent(). |
|---|
| 31 | |
|---|
| 32 | There are three main things each plugin must do: |
|---|
| 33 | |
|---|
| 34 | 1. Each plugin must include plugin.h and implement the functions |
|---|
| 35 | prototyped within. These functions are described inside this header |
|---|
| 36 | file. The main ones are: |
|---|
| 37 | LP_Init(int, char **): This function is called to initialize the |
|---|
| 38 | plugin, and is passed any command line arguments applicable. The |
|---|
| 39 | function should return whether or not it was successful in |
|---|
| 40 | initializing the plugin. |
|---|
| 41 | LP_Main(CICQDaemon *): This function is called within its own thread |
|---|
| 42 | and should actually run the plugin. It can exit by calling |
|---|
| 43 | LP_Exit(int) or by returning an integer return code. |
|---|
| 44 | |
|---|
| 45 | 2. Each plugin must register with the licq daemon it gets passed in |
|---|
| 46 | LP_Main(). This is done simply by calling CICQDaemon::Register(). |
|---|
| 47 | This function returns the descriptor of the pipe to listen on for |
|---|
| 48 | notification of signals and events. If a plugin exits without either |
|---|
| 49 | calling CICQDaemon::Shutdown() or receiving a shutdown signal then it |
|---|
| 50 | must call CICQDaemon::Unregister() to unregister itself. |
|---|
| 51 | |
|---|
| 52 | 3. Each plugin must exit properly when it receives a PLUGIN_SHUTDOWN |
|---|
| 53 | character on the notification pipe. This simply involves calling |
|---|
| 54 | LP_Exit() or returning from LP_Main(). |
|---|
| 55 | |
|---|
| 56 | |
|---|
| 57 | 2.0 Multi-threading Issues |
|---|
| 58 | |
|---|
| 59 | Licq is a fully multi-threaded program and as such there are some important |
|---|
| 60 | issues to be dealt with when writing plugins. First, any requests to get |
|---|
| 61 | user information have been made thread safe (henceforth refered to as mt-safe) |
|---|
| 62 | through a simple database type checkout system. Given a uin, a pointer to |
|---|
| 63 | the relevant user is obtained by calling gUserManager.FetchUser(<uin>, <lock type>) |
|---|
| 64 | where the <lock type> is either LOCK_R or LOCK_W depending on whether one wants |
|---|
| 65 | read or read/write access to the user (note that many threads may have a user |
|---|
| 66 | locked for reading at the same time, but only one thread may have a user locked |
|---|
| 67 | for writing, so avoid doing so if possible). |
|---|
| 68 | The same idea applies to groups: gUserManager.FetchGroup(<group id>, <lock type>). |
|---|
| 69 | |
|---|
| 70 | Certain system calls should also be avoided or their mt-safe counterparts used. These |
|---|
| 71 | include: |
|---|
| 72 | strerror (on some systems this call is mt-safe, use strerror_r to be sure) |
|---|
| 73 | gethostbyname (use gethostbyname_r, see socket.cpp for an example) |
|---|
| 74 | and any other call that uses an internal static buffer. |
|---|