Alicq Module Writing Reference
Content
Module is a basic unit for extending functionality of Alicq. Alicq module
is just a tcl script which is evaluated in alicq interpreter and has full
access to internal valiables and procedures of Alicq. There is no
restictions on content of the module, however, number of helper functions
are designed for module writers to simplity module interoperability and
integration.
On load, each module is placed into it's own child namespace of
::modules namespace. It is possible to override such
behaviour by placing module into arbitrary namespace explicitly, e.g.:
namespace eval ::my_cool_module {
...
}
However, overriding automatical namespace generation can cause
side-effects which module designer should be aware of. Firts of all,
module metainformation becames unavailable, and modules becames invisible
for modules providing configuration dialogs, menu, etc. Then,
module command can not detect if module was loaded to
prevent loading of already loaded module. Later it can cause problems with
module unloading (this feature is not implemented yet), thus such practice
is hoghly deprecated.
Module can contain any number of child namespaces of arbitrary depth,
however, some namespace names have special meaning.
Namespace meta contains module global metaingormation and
metainformation about configurable parameters. Detailed description of
metainformation is given in Metainformation section.
Namespace validate contains validation procedures for
module-specific data types.
Module can operate with arbitrary data scructures within its namespaces,
however, there is one data type which is used for module interoperability
and configuration. It is called objects, though it is nothing more than
standard Tcl arrays, which are defined in child namespaces of
::object namespace. Objects have metainformation which
describes their fields, and Alicq provides two helper commands:
ref and obj to convert object name to
corresponding variable name and vice versa. Such mapping between
object name and object variable makes object names more stable and
independent from actual variable names. Detailed information about objects
can be found in Objects section.
Module can interact with Alicq core and other modules in several ways.
First of all, it can use all avalable commands and access all variables.
Second, module can handle different events. There are several categories of
events which alicq module can handle.
Module can bind hook scripts to windowing
system events using standard Tk command bind. This
allows handing of UI events.
Module can bind hook scripts to open file descriptors using
standard Tcl command fileevent.
This is primary way to monitor changes in object variables and
module configuration parameters. Use standard Tcl command
trace for it.
This is only non-standard way of module intercommunication
in Alicq. It uses helper commands Event and
hook to generate and hook events with no pre-defined
recipient. Purpose of this way of intercommunication is implementation of
indirect calls, when event sender does not know which module or modules can
handle certain procedure call. It allows co-existance of different
implementations of same functionality, e.g. module providing dialogs has
not know which module will handle Send event it generates to
send message.
Alicq Events and Hooks is a primary way of module intercommunication, when
one module has to request another module or modules to perform any action,
and does not exacly knows which modules should perform it.
Module can generate an event using Alicq helep command
Event. Event is identified by unique name and can have
any number of optional parameters, specific for each event.
Event SetStatus online
Module can hook events using hook command, which binds
one or more events to script which is invoked when matching event occurs.
Unlike bind command used to intercept windowing system
events, hooks not replaces old handler with new one, but
adds new handler to list of handlers. These handlers are invoked according
their priorities in foreach loop. This means that each handler can cancel
low-priority handlers by finishig with
return -code break
call, cancel parameters re-assigning in filtering hook using
return -code continue
etc.
If hook is not needed any more, it can be removed using
unhook.
Objects are commonn Tcl arrays resided in child namespaces of
::object namespace. Each object has unique name or
UID - Unique IDentifier. UID of the object
is constructed from its parent namespaces and array name within namespace,
separated with colon:
Contact:ICQ:47298730
Contact:SMS:+375296xxxxxx
Group:common:47298730
Group:common:other
Url:http
Proxy:default
UID can be mapped to actual variable name using
ref, and variable name can be mapped to object name
using obj. Use ref when installing
monitoring of object property, e.g:
proc MonitorObject {uid} {
trace variable [ref $uid](Alias) w [nc AliasChanged $uid]
}
Alicq provides command select to select objects of
given domain or matching any condition. For example
select Contact:ICQ {![info exists Status]||$Status=="offline"}
selects ICQ contacts which has no status or offline.
select {Contact Group:common}
selects all contacts and common groups.
select Proxy {$type=="http"}
selects all http proxies.
Each object can have any number of fields. They are just
array fields, however, developer can provide metainformation for some
fields, which allow other modules to handle them properly, e.g. configure
via configuration dialog, validate new value in startup file commands,
save on change etc. For more information about metainformation see
Metainformation section.
Metainformation is a way to provide information describing module itself,
its configurable parameters, available actions, object fields etc.
Its main purpose is to provide uniform and simple interface for modules
implementins such features as menus, configuration dialogs, etc, as well
as module autodocumentation.
Module metainformation is stored in meta child of module
namespace. It is processed by module loader after sourcing module into
Alicq interpreter.
Module provides metainformation by means of Tcl variables and arrays.
Common Tcl variables are used to provide global module metainformation,
such as author, description, icon, etc.
Name of metavariables and their semantics depends on modules handling
metainformation. No restrictions on metavariables names exist.
namespace eval meta {
set description "Very important module"
set author "Vasiliy Pupkin"
}
Tcl arrays are used to represent metainformation about module configurable
parameters. Name of array should be same as name of Tcl variable,
representing configurable parameters, and names of array fields represent
names of metaproperties. Names of metaproperties and their semantics
depends on modules handling metaproperties. No restrictions on
metaproperties names exist.
namespace eval meta {
set description "Very important module"
set author "Vasiliy Pupkin"
array set logfile {
description "File name to save log to"
type file default my.log
save change
}
array set logging {
description "Logging activity flag"
type boolean default no menu {Tools Logging Active}
save exit
}
array set clean {
description "Clear log"
type action menu {Tools Loggin "Clean Log"}
}
}
Objects also have metainformation which is handled in slightly different
manner. Object metainformation is also represented by Tcl variables and
arrays. Unlike module metainformation, arrays are used to represent
metainformation for object fields, not objects themself. Name of meta array
should be same as name of object field.
Object metainformation is inheritable. It means that metainformation
specified for Contact objects is used for Contact:ICQ objects as well.
namespace eval [ref Contact]::meta {
array set Alias {
description "Contact Alias"
save change
}
array set Send:text {
description "Send simple text message"
type action menu {Send Message}
}
}
namespace eval [ref Contact:ICQ]::meta {
array set rid {
description "ICQ contact server-side roster ID"
type integer save change
}
}
There is no way to describe all possible Alicq Events, because each module
can use its own event for its purpose. This section descibes several
important events which new module writer is probably interested in most of
others.
-
Incoming type sender
time content
[ message-id ]
Incoming message of type type from
sender. Sender is object UID, e.g.
Contact:ICQ:47298730. content of the message depends
on its type, in the simpliest case (type)
is text it is just text string.
message-id represents unique message identifier used
to save and search message in history.
-
Send type recipient
content
Send message of type type to
recipient. Recipient is object UID,
e.g. Contact:ICQ:47298730. content of the message
depends on its type, in the simpliest case
(type) is text it is just text string.
-
SetStatus status
Set ICQ status to status. Status can be one of
online,away,ffc,dnd,occ,NA,offline,invisible
-
InfoRequest uid
Request information about contact uid. Returns
information request reference ref.
-
Info ref args
Result of information request ref as key-value pair
list.
-
search args
Search contact using key-value pairsarg as query.
Returns search request reference ref.
-
SearchResults ref args
Result of search request ref as key-value pair
list.