The protocol is part-binary, and works on text-based "commands". 
To begin a command, either side sends a one-byte value 
indicating how many parameters to expect. Then, for each 
"parameter", a 16-bit length value is sent (most significant 
byte first), followed by the parameter, not including the null terminator.

All strings are in UTF-8 encoding.

AUTHENTICATION

To open the connection, the client sends the 8-byte cookie supplied by
the server as it starts (on stdout, or in a file called "authcookie" in
the config dir). The format of the authcookie file is:

Bytes:	Contains:
1-2	A 16-bit unsigned-integer representation of the TCP port on which
	the server is listening, most significant byte first.
3-10	The 8 cookie bytes. These should be sent to the server immediately
	after making the TCP connection. If the cookie is correct, the server
	will respond with the command "cookie_accepted". If not, the server
	will respond with "cookie_rejected", and immediately close the TCP
	connection.

When launching on a pre-opened pipe (with the --pipes option), this step
does not occur.


REQUEST/RESPONSE CONVENTIONS

When the server responds to a request, sometimes its response will be 
designated "(to all)". This means that a change has been made which all 
connected GUIs should be told about. Therefore, a GUI should be prepared 
to act on these messages coming "out of the blue" because a different GUI 
just changed something.

It is also worth noting that every request will be responded to - with the
specified response, or with a client_error complaining that the request
was malformed or otherwise flawed, or by an error dialog.

			    UI CAPABILITIES

A GUI can set various capability flags which affect how it is treated by the core.

HTML:
Client: "html_strip" "1"

Requests that HTML stripping be turned on (details in the "Messages" section)
Defaults to "0"


Message capable:
Client: "msg_capable" "1" (or "msg_capable" "0")

If a user interface is message capable, then it is capable of completely handling
incoming message events. This flag is used when a user interface disconnects. If
there are any message-capable UIs still connected, nothing happens. If there are
no message-capable UIs connected, the core automatically goes into message hold
mode. The ideal user experience is the ability to switch interfaces, hosts, etc
without losing messages, no matter which subsidiary UIs (flashing alerts, systray
applets, and so on) are connected. Such subsidiary UIs should therefore set this
option to "0". Note that it does not affect whether you actually receive messages
by "message_receive". Of course, if message hold is engaged, the usual rules
apply.

Defaults to "1"



				SERVICES
Client: "list_services"

Server: "list_service" "Service name 1" "Themed color" capabilities
Server: "list_service_actions" "Service name 1" "buddy" "Number of actions" "Action 1" "Action 2" ...
Server: "list_service_actions" "Service name 1" "groupchat" "Number of actions" "Action 1" "Action 2" ...
Server: "list_service_actions" "Service name 1" "group_user" "Number of actions" "Action 1" "Action 2" ...
Server: "list_service_states" "Service name 1" "Number of states" "State 1" "State 2" ...
Server: "list_service_done"

Server: "list_service" "Service name 2" "Themed color"
...

Server: "list_services_done"


A service's capabilities are a bitwise OR of various flags, indicating what
a particular service can and cannot do.

0x1	SERVICE_CAN_OFFLINE	- Can send messages to offline users
0x2	SERVICE_CAN_GROUPCHAT	- Can join group chats
0x4	SERVICE_CAN_NAME_CHAT	- The name of a joined groupchat is significant


The "Themed colour" is the colour associated with that IM protocol, in 
HTML format - so, for example, the AIM colour is "#000088".

The different types of actions are:
	buddy		actions which can be performed on any buddy on 
			this service

	groupchat	actions which can be performed on any group chat 
			using this service

	group_user	actions which can be performed on a user in any 
			group chat using this service

Performing actions is covered below.


			CONTACT LIST MANAGEMENT

(1) Synchronisation

Client: "list_contacts"

Server: "list_group" "Group name 1"
Server: "list_contact" "Group name 1" "Contact name 1" is_ignored "Ignore message"
Server: "list_account" "Group name 1" "Contact name 1" "Local buddy account" "Service name 1" "Account name 1" is_blocked
Server: "list_account" "Group name 1" "Contact name 1" "Service name 1" "Local buddy account" "Account name 2" is_blocked
...
Server: "list_contact" "Group name 1" "Contact name 2"
...

Server: "list_group" "Group name 2"
...

Server: "list_contacts_done"


"Local buddy account" is the handle of the local account whose
buddy the remote account is.

is_ignored is a number - 0 for not ignored, 1 for ignored. This indicates
that a contact is ignored. Accounts belonging to that contact may also be
blocked at protocol level (if so, is_blocked will be 1 rather than 0).
If they are not, and any message gets through as far as Everybuddy, they
will receive an auto-reply of "Ignore message" (if it is anything other
than a zero-length string). This can be used to inform a user that they
are being ignored, and why.


(2) Adding and deleting groups/contacts/accounts

Client: "add_group" "Name"
Server (to all): "add_group" "Name"

Client: "add_contact" "Group" "Name"
Server (to all): "add_contact" "Group" "Name"

Client: "add_account" "Group" "Contact" "Local buddy account" "Service" "Account handle"
Server (to all): "add_account" "Group" "Contact" "Local buddy account" "Service" "Account handle"

Client: "del_group" "Name"
Server (to all): "del_group" "Name"

Client: "del_contact" "Group" "Name"
Server (to all): "del_contact" "Group" "Name"

Client: "del_contact" "Group" "Name"
Server (to all): "del_contact" "Group" "Name"

Note that explicitly sending "del_contact" is not usually necessary
(see "del_account" below). An exception is a contact with no accounts
attached.

NOTE: Before explicitly deleting a group or contact, it must be empty

Client: "del_account" "Local handle" "Service" "Buddy handle"
Server (to all): "del_account" "Local handle" "Service" "Buddy handle"

The server is not guaranteed to comply with a "del_account" command - 
for example, if the necessary local account is not online, a buddy might not
be deleted, and the user would be informed with an error dialog.
This could make deleting contacts quite a hassle, which is why a contact
is automatically deleted (with a "del_contact" command sent as appropriate)
when its last account is deleted. "Delete contact" can therefore normally
be accomplished by sending a "del_account" for every buddy account
attached to that contact.


Client: "rename_contact" "Group name" "Contact name" "New contact name"
Server (to all): "rename_contact" "Group name" "Contact name" "New contact name"

Client: "move_contact" "Group name" "Contact name" "New group name"
Server (to all): "move_contact" "Group name" "Contact name" "New group name"

Client: "move_account" "Local handle" "Service" "Buddy handle" "New group name" "New contact name"
Server (to all): "move_account" "Local handle" "Service" "Buddy handle" "New group name" "New contact name"

NOTE: To move a contact or account, the group or contact to which
they are moving must exist first. Contacts from which the last account
has been moved away will be deleted, and a "del_contact" sent as
appropriate.


(3) Ignoring/unignoring contacts

Note: For now, whether an actual account is blocked or not is irrelevant
and should not be relied upon.

Client: "ignore_contact" "Group name" "Contact name" "Ignore message"
Server (to all): "ignore_contact" "Group name" "Contact name" "Ignore message"

If possible, the user will be blocked at a protocol level, which bars all
messages from getting through. If this is not possible, an auto-responder
will instead be set up. If "Ignore message" is an empty string, the response
to any message from the ignored contact will be:
"This is an automated message. The person you attempted to contact is
ignoring you and did not receive your message."

If an "Ignore message" has been specified, the above string will have
"Explanation: <ignore message>" appended to it.

If the ignore message is to be changed, then "ignore_contact" can be sent
again with the new ignore message - it is not necessary to unignore the
contact first.


To unignore a contact:

Client: "unignore_contact" "Group name" "Contact name"
Server (to all): "unignore_contact" "Group name" "Contact name"



			LOCAL ACCOUNTS MANAGEMENT

Client: "list_local_accounts"

Server: "list_local_account" "Local username 1" "Service name 1"
Server: "list_local_account" "Local username 2" "Service name 2"
...

Server: "list_local_accounts_done"


To add a local account:

Client: "add_local_account" "Local username" "Service name"
Server (to all): "add_local_account" "Local username" "Service name"

NOTE: after adding an account, vital settings such as passwords must be
entered in the preference page belonging to that local account. See
below for details of pref pages. Each account's pref page is entitled
"username_protocol" (eg "blip109@hotmail.com_MSN"), for direct reference if the
GUI wishes to pop the page up immediately after adding the account. All accounts'
config pages are also accessible as one of the subpages of the "accounts" page -
see the prefs section for more details.

Deleting a local account:

Client: "del_local_account" "Local username" "Service name"
Server (to all): "del_local_account" "Local username" "Service name"

Note: Between the client's request and the confirmation of deletion, and after
the confirmation of addition, a set of add/remove buddy events can occur. If a
local account is deleted, all its associated buddies are deleted. However, the
core keeps a reference to these buddies for as long as their respective contacts
exist, so if the local account is re-added, buddies reappear under their
correct contacts.



			SETTING AN AWAY MESSAGE

An away message is a message that gets sent to anyone who tries to contact
the user. Some protocols (eg AIM) have protocol-level support for away
messages. Some plugins (like MSN) use the body of the away message
to guess which state they should set the account to (eg if the word "phone"
is mentioned, the On The Phone state is set).

An away message has both a title and a body. The title is a short summary
of the user's state, and can also be used by plugins (for example the Yahoo
plugin, which uses the title as a custom state if it can't guess anything
from the body text).

To set an away message:

Client: "set_away" "title" "body"
Server (to all): "set_away" "title" "body"

To clear an away message (ie to mark yourself as "back"):
Client: "unset_away"
Server (to all): "unset_away"

If the away message is to be changed, set_away may be called a second time,
with no intervening unset_away call.



				DIALOGS
All dialogs (in a GUI situation, they are usually implemented as 
dialog boxes, but they can be implemented any way the GUI client
wishes) have a "tag code" attached to them - a string 
(usually a number) that identifies them uniquely. Each dialog, 
no matter what type it is, has one of these codes. Each 
type of dialog has a different initiation command, and a 
different variation on the resolve_dialog command. On connection,
each GUI receives all outstanding dialog boxes.

(1) Error messages
These are usually modal dialog boxes

An error message is sent out to all connected clients.

Server: "error_dialog" "tag code" "message_title" "message_body"


When a client wishes to "resolve" one of these errors, it sends:

Client: "resolve_dialog" "tag code"

The server then broadcasts the fact that this error message has
been resolved, with:

Server: "dialog_resolved" "tag code"


(2) Yes/No dialog

Server: "yesno_dialog" "tag code" "title" "message" "default result"

To resolve:

Client: "resolve_dialog" "tag code" "result"
"result" is either "1" or "0"

The server then broadcasts:
Server: "dialog_resolved" "tag code"


(3) List boxes

Server: "list_dialog" "tag code" "title" "message" "number of options" "option 1" "option 2" ...

To resolve:
Client: "resolve_dialog" "tag code" "selected"
"selected" is the value of the option that was selected

Server (to all): "dialog_resolved" "tag code"

(4) Text-entry dialogs
These are large dialogs suitable for entry of large amounts of 
text, such as a buddy profile. When it opens, usually it will 
have something in it already. If not, "current contents" is an 
empty string. "is html" will be "1" if the text is expected to
be formatted as html, otherwise it will be "0".


Server: "text_dialog" "tag code" "title" "message" "current contents" "is html"

Client: "resolve_dialog" "tag code" "new contents"

Server (to all): "dialog_resolved" "tag code"


SPECIAL CASE - One-client-only errors
This only occurs when a particular client has broken the 
protocol (tried to do something to a buddy that doesn't exist, 
responding to a dialog that has already been resolved, etc).

Server: "client_error" "error message"

As there are no other recipients apart from this GUI client, it 
is unacknowledged.





			STATUS NOTIFICATION
Logged out:
Server: "buddy_logout" "Local buddy account" "Service name" "Buddy handle"

Logged in:
Server: "buddy_login" "Local buddy account" "Service name" "Buddy handle"


		    SETTING LOCAL ACCOUNT STATUS
Sign on all:
Client: "sign_on_all"

Sign off all:
Client: "sign_on_all"

Note that the sign on/off all operation has no affect on already-connected 
accounts, so it is safe to do them automatically. Be aware, however, that 
if no change occurs, no local_account_update will happen either, so the 
user interface should check whether the account they want to use is 
already ready when they "list_local_accounts" to avoid looping for 
something that won't ever happen.


Status change:
Server: "buddy_status" "Local buddy account" "Service name" "Buddy handle" state "Status string"
(state is a number - 0 for offline, 1 for online, 2 for away)


Telling an individual local account to log in:
Client: "local_account_login" "Local account handle" "Service name"

Telling an individual local account to log out:
Client: "local_account_login" "Local account handle" "Service name"

The effect of "sign_on_all" is the same as that of giving a
"local_account_login" for every local account. (Likewise "sign_off_all")


Changing the status of a local account:
Client: "set_local_account_status" "Local account handle" "Service name" "Status"

Status change in local account:
Server: "local_account_update" "Local account handle" "Service name" connected ready "Status string"
(connected and state are numbers, 1 for true, 0 for false. If connected 
is true, the account is either connected or in the process of connecting 
to the server. If ready is true, the account is ready to send messages, 
add/delete buddies, etc)


			SENDING AND RECEIVING MESSAGES

(1) Receiving
Server: "message_receive" "Group name" "Contact name" "Local handle" "Service name" "Buddy handle" "Message"

(2) Third-person notifications

Service: "notify_3rdperson" "Group name" "Contact name" "Text"

This text should be inserted into the chat window with no frills (except
maybe a timestamp if the UI designer wishes).

(3) Sending
Client: "message_send" "Group name" "Contact name" "Local handle" "Service name" "Buddy handle" "Message"
If the service name is an empty string (""), then all the data will
be ignored apart from the contact name and message. Suitable accounts
will be chosen by the server for the actual sending, and will be
reported by the subsequent broadcast.

The server then broadcasts this to all clients:
Server: "message_send" "Group name" "Contact name" "Local handle" "Service name" "Buddy handle" "Message"


NOTE ON HTML:
All the message contents referred to above are in HTML format, unless the
user interface specifies otherwise (more on that later). The HTML has been
run through the core's HTML parser and then re-rendered, so it is guaranteed
to be "clean" - only certain tags are allowed, none are unclosed, and every
other < and & sign has been encoded (as &lt; and &amp;). It is therefore
safe to send straight-off to a very trusting HTML parser, such as a web
browser or HTML-viewer widget.

Alternatively, the user interface may request stripped-text output. Unlike
other options, this affects only this interface, and no others currently
connected. Stripped text has been parsed, and then rendered into plain text.
Recognised HTML tags have been removed, and quoted characters (such as "&lt;",
"&amp;", "&quot;", etc) have been converted back into their ASCII equivalents.

For example, a message which contains:
Visit the < a href = http://www.everybuddy.com>Everybuddy website

will become:
Visit the <a href="http://www.everybuddy.com">Everybuddy website</a>

or, if the UI has specified plain text:
Visit the Everybuddy website

To specify that the UI would prefer plain text, this command is used:

Client: "html_strip" "1"

Although HTML is the default, the user interface may explicitly request
HTML with:

Client: "html_strip" "0"

This command is unacknowledged.


(4) Queuing

	Everybuddy has a message-queuing system, which can be turned on or off
at any point. When it is turned on, any message events (sending, receiving,
3rd-person events) are held until they are either explicitly released, or
implicitly released by turning message hold off.

To turn on message hold:
Client: "message_hold" "1"
Server (to all): "message_hold" "1"

To retrieve all held messages so far *without* turning off message hold:
Client: "get_held_messages"

For each message:
Server (to all): "held_message" time "Group" "Contact" "Local handle" "Service" "Buddy handle" "Message"

For each *sent* message:
Server (to all): "held_sent_message" time "Group" "Contact" "Local handle" "Service" "Buddy handle" "Message"

For each 3rd-person message:
Server (to all): "held_3rdperson" time "Group" "Contact" "Message"

Note that "time" is in "seconds ago" - so, if it is 5, that message happened
5 seconds ago.

Server (to all): "held_messages_done" num
...where num is the number of held messages just delivered

To turn off message hold:
Client: "message_hold" "0"
Server (to all): <same results as if the client had sent "get_held_messages">

Server (to all): "message_hold" "0"


When the first message arrives after message_hold is turned on (ie when
there is at least one waiting message):
Server (to all): "holding_message"

This is also sent to a new client as they connect to a core with at least one
waiting message.



				GROUP CHAT
	Everybuddy supports a generic concept of a "group chat" for any chat
which involves more than one other user. A group chat can contain any number
of users, which must include the owner of the EB-lite process, although they
are not yet identified as such - this will be amended!

A group chat has a numerical ID which is used to refer to it, a title, a local
account with which it is associated, and a list of its user population.


To request to join a chat:

Client: "join_group_chat" "Local handle" "Service" "Name"

Note that the name of the room bears no necessary relation to the title of the
group chat which is joined as a result. Join does not occur immediately, but
may be asynchronous. Unless the service has SERVICE_CAN_NAME_CHAT set in its
capability flags, the "Name" parameter is ignored (although it must still
be present).

In response to either a join_group_chat from a client, or an invitation that
is accepted (delivered by means of an ordinary dialog), the server may
announce the arrival of a new group chat with:

Server (to all): "new_group_chat" "Local handle" "Service name" chat_id "Title"
Server (to all): "list_group_user" chat_id "Username 1"
Server (to all): "list_group_user" chat_id "Username 2"
...
Server (to all): "list_group_chat_done"


To invite a user into a group chat:
Client: "group_chat_invite" chat_id "handle"


To send a message into a group chat:

Client: "group_chat_send" chat_id "Message"
Server (to all): "group_chat_send" chat_id "Message as sent"


When a message is received a group chat:
Server: "group_chat_recv" chat_id "Sending handle" "Message"

Third-person commentary in a group chat:
Server: "group_chat_3rdperson" chat_id "Message"


When the chat's title changes:
Server: "group_chat_update" chat_id "Title"

When someone joins the chat:
Server: "group_chat_joined" chat_id "handle

When someone leaves the chat:
Server: "group_chat_left" chat_id "handle"

To close a group chat:
Client: "close_group_chat" chat_id

When a chat is closed:
Server: "close_group_chat" chat_id


Special command (experimental, may become deprecated, in which case it will
result in a warning dialog):
Client: "group_chat_hide" chat_id

The server will then send "group_chat_close" as if the chat had been closed,
but the next time any message is received, the group chat will be reannounced
as a new chat, and the message will appear. This is an experimental feature
for "auto-lurking", but I am not sure whether it is a sufficiently elegant
solution. Please implement it, and see if it's useful!


				 CHAT LOGS
NOTE: THIS IS A DRAFT SPECIFICATION. THESE FEATURES ARE ONLY PARTIALLY
IMPLEMENTED, IF AT ALL.

If logging is enabled, Everybuddy stores each conversation in a separate 
log file. A conversation with a contact starts with the first message or 
third-person notification to or from this contact, and ends when no such 
message has been exchanged for fifteen minutes.  A group chat is logged as 
one big conversation.

Conversation logs have arbitrary, meaningless names. These names can be 
found with the "log_search" command. There are two types of conversations,
group chats:

Client: "log_search" "g" max_results start_time end_time "local handle" "service" "text"

...and one-on-one chats with contacts:

Client: "log_search" "c" max_results start_time end_time "group" "contact" "text"

To search for either:

Client: "log_search" "a" max_results start_time end_time "text"


max_results is (surprise!) a cap on how many results get sent back - use 
this if at all possible, otherwise slow connections will feel the hit 
big-time on general searches. A negative value gives the last X events 
rather than the first.

start_time and end_time are lower and upper constraints on the time at 
which the conversation(s) started. As with held messages, the units are 
"seconds ago", which means that start_time is a higher number than 
end_time for any useful search.

"group" and "contact" identify the contact in the conversation(s)

"local handle" and "service" identify the local account (or just the 
service, if you leave out the handle) of a group chat



Any of these parameters may be omitted (empty string), and they will 
simply be ignored. For single-contact conversations, if "group" and
"contact" do not specify an existing contact, Everybuddy will silently
act as if you did not specify them.


The server will return each search result in this form:

Server: "log_result" "id" "type" start_time [extra options]

"id" is the arbitrary unique ID for this conversation log.

"type" is either "contact" or "group", as before. start_time is the time 
at which the conversation started, and the extra options depend on the 
type.

For a contact conversation:
Server: "log_result" "id" "contact" start_time "group" "contact"

For a group chat:
Server: "log_result" "id" "group" start_time "local handle" "service"

To signal the end of the search results:
Server: "log_results_done"


To retrieve a log file, given the id:
Client: "get_stream" "log" "id"
Server: "get_stream" "log" "id" stream_id

"log" is a string literal. stream_id is the numerical ID of this stream.
The contents of the file will arrive as a stream, in the usual manner

The format is as follows:

[quad]	- four bytes, time of event (since conversation started)
[byte]	- message type ('S' for sent, 'R' for received, '3' for 3rd-person)
[len+string] - two-byte length followed by string (rather like a parameter 
in low-level GUIcomms), handle of the account sending the message (empty
string for 3rd-person)
[len+string] - service carrying this message ("" for 3rd-person)
[quadlen+string] - four-byte length followed by string, the message itself.
Message is in force-validated HTML (as with messages when html_strip is set
to 0)

Rinse and repeat above sequence with no gaps until EOF.

BEWARE: This file format is binary, and NOT safe to handle as a string if
null zero is used as a terminator character. Be careful.


			     DATA MESSAGES

File transfers, inline data such as images and push-to-talk voice, and
webcams are all carried by data messages, which are arbitrary-length
streams of data. Each data message has a content-type, which follows the
MIME convention (eg "image/png"), and a disposition, which gives hints
as to the presentation of this data message at the other end.
Currently defined disposition values are "inline" and "webcam", with all
unknown dispositions (or those unsupported by the service used) being
treated as standard file transfers.

To send a data message:
Client: "data_message_send" "Group" "Contact" "Local account" "Service" "Handle" "Content-Type" "Disposition" "Length" "Stream ID"

The client should start streaming the data message with id "Stream ID"
directly after sending this message. HOWEVER, if for some reason the
data message cannot be sent (contact offline, data messages not supported,
or whatever), an "up_stream_error" will be sent directly, instructing the
UI to stop sending.



				STREAMING
Sometimes, a GUIcomms connection needs to transport a large wadge of
data, which is a bit big to send at once, and really needs to be
multiplexed with other commands.

A stream has an ID (numerical, but best not to rely on that - treat it
as a string if you can). Either side can send a stream once the other
side has been notified that it is coming (how this negotiation happens
is specific to the particular application, see CHAT LOGS for an
example). Streams are chopped up into bits, and each chunk sent with an
"sdata" command:

"sdata" "stream_id" "DATA"

Note that the DATA may be binary, including null zeros, and will therefore
break if you try to handle it as a null-terminated string.

A stream is terminated with:
"stream_ends" "stream_id"

Or, in case of error:
"up_stream_error" "stream_id" "error code"
for streams going *to* the core, and:
"down_stream_error" "stream_id" "error code"
for streams coming *from* the core.

Error codes include -1 for user-initiated abort (don't show an
error dialog), and -2 for I/O error. This may expand, but assume
any other error to be fatal and unexpected.

A UI may deliberately abort a stream going in either direction:
Client: "up_stream_abort" "stream_id"
or
Client: "down_stream_abort" "stream_id"

The core will confirm this with the appropriate XXX_stream_error.


NOTE: stream_ids are only unique within streams going in a particular
direction to/from a particular user interface. The user interface
is expected to make up the IDs for upward streams, and the core for
downward streams, but because IDs do not need to be unique over
both directions, they will not collide with each other.



For example:

The client has just requested a logfile, and the server is agreeing:
C: "get_stream" "log" "24573541_0"
S: "get_stream" "log" "24573541_0" "45"

S: "sdata" "45" "<CHUNK OF LOGFILE HERE>"
S: "sdata" "45" "<ANOTHER CHUNK HERE>"
S: "stream_ends" "45"



				PREFERENCES
Everybuddy preferences are stored in "pages". A "page" in turn contains
zero or more sub-pages, and zero or more "components". Each page has a
"name", which is a unique identifier, and a "title", which should be
displayed to the user.

Each component has a "name" which identifies it uniquely, a "title" which
is actually displayed as a caption, and a "value" which can be set (more
on that later).

Components can be of several types:

	"label"		Explanatory label. The value of this
			component is redundant, and the title is the
			label's caption.

	"string"	Single-line text entry.

	"password"	Single-line text entry, but to hidden
			from over-the-shoulder peeking by whatever
			means necessary (normally, asterisks instead
			of letters).

	"toggle"	A value that can be on or off (stored as
			"1" or "0"). Usually a checkbox.

	"option"	Multiple-choice option. The value is the value
			of the selected option.

	"button"	Push-button. The value of this component
			is redundant, but setting it to any value
			indicates that the button has been pushed.


The "root" page of the preferences is always called "mainprefs". All
other prefs pages are subpages of "mainprefs" (or subpages of subpages
of mainprefs, or subpages of subpages of- oh, you get the idea...).

There is a special second root - a page called "accounts", which holds
the account editor, from which the user adds, removes, and modifies
accounts. It is a normal prefs page in all respects except that it is
not a child of "mainprefs".


To retrieve the contents of a preferences page:

Client: "list_pref_page" "page name"
Server: "list_pref_page" "page name" "page title"
Server: "list_subpages" "page name"
Server: "list_subpage" "page name" "subpage 1 name" "subpage 1 title"
Server: "list_subpage" "page name" "subpage 2 name" "subpage 2 title"
...
Server: "list_subpages_done"

Server: "list_components" "page name"
Server: "list_component" "page name" "type" "name" "title" "value"

[[[ OPTIONAL:
If the component is of type "option":

Server: "option_data" "page name" "component name" num_options "Option 0" "Option 1" ...

num_options is the number of options

]]]

Server: "list_component" "page name" "type" "name 2" "title 2" "value 2"
...

Server: "list_components_done"
Server: "list_pref_page_done"


To set the value of any pref, the client sends:
Client: "set_pref_value" "page name" "component name" "value"

CAUTION: If the prefs dialog box uses an "OK" button to send all the prefs
values at once, be sure to omit components of type "button", as setting
their value AT ALL indicates that the button has been pressed. Also, if
a button is pressed, the client should first set the value of all prefs on
that page (or at least all prefs listed before the button in question),
otherwise the button-pressed code is working with old values, and will
produce interesting and occasionally spectacular results.

CAUTION mk 2: The server does NOT broadcast every change to any preference,
and the actual content and structure of prefs pages can change dynamically,
so it is wise to reload the prefs as closely as possible before the widgets
are actually displayed.

CAUTION mk 3: A button may result in a change in the page on which the button
is located and/or any of its children. Therefore, a GUI should reload that
page after any button press.

				   ACTIONS
Actions are an extension mechanism, whereby the core can add extra "verbs"
to various objects. Services use them to implement service-specific features,
and other features use them for their own purposes. For example, Jabber's
"appear invisible to..." functionality could be implemented by a
service-specific action, applicable to all buddy accounts on the Jabber
service. The automatic translator plugin, by contrast, uses a generic
action applicable to any contact to allow the user to specify a language
with which to talk to a contact.

Service-specific actions are listed as part of the response to the
"list_services" command documented above. Generic actions come in four
flavours: "general", "group", "contact", and "buddy_generic". "general"
actions are not associated with any particular object on the contact list
- in effect, they just add another option to the UI's command menu (or
equivalent). "group" actions apply to a group on the contact list, "contact"
actions to a contact, and "buddy_generic" to any buddy account (the name
is to distinguish them from service-specific "buddy" actions, which can only
be performed on buddy accounts on a particular service).

To list the available actions:

Client: "list_actions"

Server: "list_actions" "general" num_actions "action 1" "action 2" "action 3" ...
Server: "list_actions" "group" num_actions "action 1" "action 2" ...
Server: "list_actions" "contact" num_actions "action 1" "action 2" ...
Server: "list_actions" "buddy_generic" num_actions "action 1" "action 2" ...
Server: "list_actions_done"

			      PERFORMING ACTIONS

To perform an action:

(1) on a buddy

If it's an action associated with the service:
Client: "perform_action" "buddy" "action name" "local account" "service name" "buddy handle"

If it's a generic action:
Client: "perform_action" "buddy_generic" "action name" "local account" "service name" "buddy handle"

(2) on a groupchat

Client: "perform_action" "groupchat" "action name" "chat ID"

(3) on a groupchat user

Client: "perform_action" "group_user" "action name" "chat ID" "user handle"

(4) on a group

Client: "perform_action" "group" "action name" "group name"

(5) on a contact

Client: "perform_action" "contact" "action name" "group name" "contact name"

(6) on nothing (a general action)

Client: "perform_action" "general" "action name"

Actions are unacknowledged, although they will usually produce some sort of
change which will be reported to the UI in the normal fashion.



			PERSISTENT DATA STORAGE

The core allows user interfaces to associate arbitrary name/value pairs with
particular local accounts, contacts, or in a "general" category for data
not associated with a particular object. For example, a vocal user interface
could conceivably store information in which voice to use for messages
originating from a particular contact, or an iChat-like interface could
use this data to associate avatar images with contacts and/or local accounts.
On a more prosaic level, user interfacs can store persistent settings here,
and have them take effect on any user interface which understands such
settings, wherever it is being run.

This data is stored in the Everybuddy registry. By convention, the / character
is used as a separator. It is stored as name/value pairs.


There are two commands for manipulating data, each of which comes in a
particular variant for each object in which data is stored. The mandatory
parameters come first in all cases, followed by a keyword to denote the
storage location, and parameters to that keyword. The simplest storage
location is "general". It takes no parameters, and denotes the set of
general data not associated with any particular object. For simplicity,
this form will be used to demonstrate the commands.


To get a value:
Client: "get_data" "value name" "keyword" [keyword parameters]
Server: "return_data" "name" "value" "keyword" [keyword parameters]

For example:

Client: "get_data" "view_accounts_on_startup" "general"
Server: "return_data" "view_accounts_on_startup" "1" "general"

The above example illustrates something else - preferences which can apply
to more than one user interface. Such preferences should be standardised
as far as possible, so other user interfaces can take advantage of them.
For now, there are no documented storage locations, but if you use this
feature please let me (meredydd@everybuddy.com) know about the names so they
can be included in future versions of this document.



To put a value:
Client: "put_data" "name" "value" "keyword" [keyword parameters]
<this command is unacknowledged, except in the case of a malformed command>


Storage locations by keyword:

"general"
	This keyword takes no parameters, and denotes a general location
for data not associated with any object.


"contact"
	This keyword denotes extra data attached to a contact. It takes two
parameters, group and contact name. For example:

Client: "put_data" "voice_ui/voicename" "female1" "contact" "Buddies" "Jane"

would put the value "female1" into the name "voice_ui/voicename" for the
contact "Jane" in the "Buddies" group.
