CLEMA protocol

Smiley Packs

Smileys come in packs from the server's catalog, which the server's operator fills; nobody uploads packs. A message names a smiley by its pack and its ID (see Smileys), and what the smiley looks like, its pack says.

Packs

pack.list has no body. It answers with the catalog and the packs the account installed in its panel, in the order the panel shows them:

{"id":"packs-1","type":"pack.list"}
{"id":"packs-1","type":"pack.list","ok":true,"data":{"packs":[{"pack_id":"kolobok","kind":"smileys","version":3,"title":{"en":"Koloboks","ru":"Колобки"}},{"pack_id":"emoji","kind":"emoji","version":1,"title":{"en":"Emoji"}}],"installed":["kolobok"]}}
Field Description
pack_id The pack: up to 32 lowercase letters, digits, dashes and underscores
kind smileys, which messages mark by ranges, or emoji (see Emoji)
version Grows whenever the pack's title, smileys or their order change
title The pack's name by language; en is always there

pack.get answers with one pack and its smileys in order, not_found for a pack the catalog does not have:

{"id":"pack-1","type":"pack.get","data":{"pack_id":"kolobok"}}
{"id":"pack-1","type":"pack.get","ok":true,"data":{"pack":{"pack_id":"kolobok","kind":"smileys","version":3,"title":{"en":"Koloboks","ru":"Колобки"},"smileys":[{"smiley_id":"smile","fallback":":-)","codes":[":)","=)","+)"],"formats":[{"format":"small","width":72,"height":88},{"format":"large","width":144,"height":176}]}]}}}
Field Description
smiley_id The smiley within its pack: up to 64 lowercase letters, digits, dashes and underscores
fallback The text a message carries for the smiley, which the panel puts in
codes Other texts that stand for it, which ICQ clients type
formats Its pictures: small for a line of text and the panel, large for a message of nothing but smileys, each with its size in pixels

Pictures

A smiley's picture is a WebP image anybody may fetch, without a token:

GET /smileys/{pack_id}/{smiley_id}/{format}

It is served with Cache-Control: public, max-age=31536000, immutable: a smiley never changes once published. Its fallback and pictures stay as they are and its codes only grow; a redrawn smiley is a new smiley with a new ID. A smiley its pack drops keeps its pictures, so that the messages it is in still draw it. Clients draw pictures by the size of the text around them, keeping their proportions; a smiley need not be square.

Keeping Packs Up to Date

Drawing a message takes no pack and no version: a client fetches the picture a range names when it displays the message, and keeps it for good. Only a pack's make-up — its title, its smileys and their order, which the panel shows — has a version. A client asks pack.list each time it catches up after connecting (see Following Streams), and fetches again with pack.get a pack it shows whose version changed.

Emoji

A pack of kind emoji is the pictures every Unicode emoji is drawn with, wherever it stands: in messages, reactions, statuses and names. An emoji names itself, so no text marks it: a client draws every emoji there is by the pack. Its smileys are named by the emoji's code points, in lowercase hexadecimal joined by dashes (1f600, 1f468-200d-1f469), and fall back to that very emoji. It is not installed: a client always has it.

Installed Packs

The packs an account installed are the ones its panel shows, in order, on every device. An account that never chose has the catalog's preinstalled packs, whichever they come to be; its devices learn of a change in them from pack.list as they catch up. Showing a smiley needs no pack installed.

{"id":"pack-2","type":"pack.install","data":{"operation_id":"pack-install-1","pack_id":"kolobok"}}
{"id":"pack-2","type":"pack.install","seq":"57","ok":true,"data":{"installed":["kolobok"]}}
{"id":"pack-3","type":"pack.remove","data":{"operation_id":"pack-remove-1","pack_id":"kolobok"}}
{"id":"pack-4","type":"pack.order","data":{"operation_id":"pack-order-1","pack_ids":["animals","kolobok"]}}

pack.install puts a pack of smileys at the end of the panel: not_found for a pack the catalog does not have, invalid_state for a pack of emoji or past 100 packs. pack.remove takes one out. pack.order names every installed pack once, in the order the panel is to show them, and is conflict otherwise: another device changed them meanwhile. Each answers with the installed packs, and the account's other devices are told by pack.installed, pack.removed or pack.ordered in its account stream, carrying them the same way:

{"type":"pack.installed","seq":"57","data":{"installed":["kolobok"]}}

A change that changes nothing — installing an installed pack, say — makes no event.