Note: When I started writing this, I was using customized mongooseim version 3.7.1, now latest updates using TOML config and such have come up as on July 2021. So, if you want to refer to the latest documentation, feel free to read it here .
XMPP Jargon
Client to Server (C2S)
The client can be any medium such as mobile, web or any application that knows to talk in XMPP protocol
Server to Server (S2S)
Any other XMPP Server that knows how to connect to an XMPP based Server.
Federation
Inter-connecting different XMPP servers, such as a.chat.com
can be federated to talk to b.chatty.org
. Note, the difference in domain chat.com
and chatty.org
.
XML Namespace (xmlns)
A specific set of resource or route or functions, that are identified by the namespaces
Jid or Jabber ID
A Jabber ID is a unique ID given to each user in a Jabber Server / XMPP Server to identify the users.
Understanding XMPP
XMPP is not a technology or a language, instead a protocol using structured XML to instruct the server to put or get data. The XML queries are called Stanzas. There are three basic stanzas, that we’ll use to satisfy most of our needs:
<iq>
— Info(rmation) Query Stanza, used mainly for command exchanges<message>
— Message Stanza, used mainly for transferring messages<presence>
— Presence Stanza, used mainly for exchanging presence (online status, other user status messages, etc., )
IQ stanza Sample
<!-- (IQ Stanza sent to Server) -->
<iq from='user@example.com/mobile' to='user@example.com' id='x13' type='get'>
<query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>
<!-- (IQ Stanza received from Server) -->
<iq from='juliet@capulet.lit' to='juliet@capulet.lit/balcony' id='disco1' type='result'>
<query xmlns='http://jabber.org/protocol/disco#info'>
<identity category='account' type='registered'/>
<feature var='urn:xmpp:push:0'/>
...
</query>
</iq>
In the above example, all we’re trying to do is query the supported features from the server. If you examine closely, you might be wondering what is from
, to
, id
, type
, etc., . Those who are familiar with XML, know it as attributes
.
There are 4 types of IQ stanzas:
get
: Retrieving something from the serverset
: Storing something in the Server’s Databaseresult
: Server sends back some query resultserror
: Server sends an error stanza with details
How a stanza is represented in MongooseIM:
Before we dive into it, I’m using MongooseIM to demonstrate, as ejabberd uses a different library for parsing xml files. So, there are going to be subtle differences in a very major way.
MongooseIM uses a library called exml
and some old modules might be referring to xml
to parse to actual xml stanzas from erlang records. Here, we have a common erlang record to define xml stanzas.
If you’re familiar with erlang, you are probably already aware of RECORDS
. To put it simply, erlang record is equivalent to a C struct. For more detailed description, you can check here
.
The stanza as an erlang record is represented as Follows:
#xmlel{
name = <<"message">>,
attrs = [
{<<"xmlns">>, <<"jabber:client">>},
{<<"id">>, <<"43a6d6be-de78-47d7-a283-e391ae7b2d83">>},
{<<"from">>, <<"test@jabber.fr">>},
{<<"to">>, <<"friend@jabber.fr">>}
],
children = [
#xmlel{
name = <<"body">>,
children = [
#xmlcdata{ content = <<"Hello, world!">> }
]
}
]
}
%% The above record when you convert to XML String will be as follows:
<message xmlns='jabber:client' id='43a6d6be-de78-47d7-a283-e391ae7b2d83' from='test@jabber.fr' to='friend@jabber.fr'>
<body>Hello, world!</body>
</message>
Any Stanzas that reach the server will go through a series of steps and then get converted to the xmlel
record and that is what will be passed around most of the time. It is very much essential to get an understanding how to read, manipulate the stanzas in order to be working with them.
- xmlel ⇛ Erlang Record Name
- name ⇛ XML ELEMENT NAME
- attrs ⇛ XML ELEMENT ATTRIBUTES
- children ⇛ XML_ELEMENTS_INSIDE_THE_PARENT_XML_ELEMENT
I’m assuming that you’d set up mongooseim in your machine already using docker or else please read my Part 1 and Part 2 .
- Get into the running mongooseim container using
docker exec -it mongooseim bash
- Run the command
make shell
or./rebar3 shell
, which will automatically compile the src files and drop you in an interactive erlang shell with mongooseim running
Note: You will see a lot of logs being printed out as a part of boot up process.
Now this gets interesting, in the shell:
- Copy and paste the above XML string stanza assigning it to an Erlang Variable
(mongooseim@localhost)2> A = <<"<message xmlns='jabber:client' id='43a6d6be-de78-47d7-a283-e391ae7b2d83' from='test@jabber.fr' to='friend@jabber.fr'>
(mongooseim@localhost)2> <body>Hello, world!</body>
(mongooseim@localhost)2> </message>">>.
<<"<message xmlns='jabber:client' id='43a6d6be-de78-47d7-a283-e391ae7b2d83' from='test@jabber.fr' to='friend@jabber.fr'"...>>
- Call the following function
exml:parse(ANY VARIABLE NAME)
(mongooseim@localhost)5> {ok, B} = exml:parse(A).
{ok,{xmlel,<<"message">>,
[{<<"xmlns">>,<<"jabber:client">>},
{<<"id">>,<<"43a6d6be-de78-47d7-a283-e391ae7b2d83">>},
{<<"from">>,<<"test@jabber.fr">>},
{<<"to">>,<<"friend@jabber.fr">>}],
[{xmlel,<<"body">>,[],[{xmlcdata,<<"Hello, world!">>}]}]}}
(mongooseim@localhost)6> exml:to_pretty_iolist(B).
<<"<message xmlns='jabber:client' id='43a6d6be-de78-47d7-a283-e391ae7b2d83' from='test@jabber.fr' to='friend@jabber.fr'"...>>
In the illustration above, I have shown how to encode and decode XML stanzas from String to Erlang Records and Vice Versa.
Important thing to remember, most of the XML elements or components are represented as Erlang Records in MongooseIM, for example, Jabber ID/Jid is a record and so on.
With this, I’ll be wrapping us this part and continue with more information in the next part…