The native Common Lisp library for XMPP RFCs.
WARNING: This library is under heavy development.
The XMPP basically constists of the core and XEP parts, the library tries to follow an idea of an extendable design incorporating several layers.
The low-level code that is responsible for such things like:
connecting to server through TCP socket, making the socket secure using TLS,
SASL authentication, XML parsing, and the core set of stanzas; is in the xmpp%
package.
So, in fact, it implements the basic blocks for the Core part of the protocol, consequently,
theoretically, it can be used to implement not only the client side but also the server side.
The high-level part is in the package cl-ngxmpp-client
(there is xmpp
alias for it) — the most
interesting part for users of the library. It hides all low-level stuff under the hood,
instead of that, it gives you well-bounded entities (futher I'll call them "domains") such as:
roster, message chat, groupchat, file transfer, etc. The basic use-case suggests reacting on
incoming events defining hooks available for particular entity. There is a simple EDSL which
allows you to define your own XEPs easily.
This section is not finished yet...
To understand better what I mean I draw this diagram:
Global View
+--------------------------------------------------------------------------------------+
| |
| +-------------, Core (Low-level) |
| | +-----------, |
| | | +-----------, +--------------+ +--------------+ +----------------+ |
| | | | | | XML-STREAM | | CONNECTION | | ADAPTER | |
| `-| | XEPs | | | | | | | |
| `-| | | connection @----->| adapter @-------->| socket-stream | |
| +-----------+ +--------------+ +--------------+ +----------------+ |
| ^ ^ |
| | Client | (High-level) |
| | | |
| +-------------|---+ +-------------|----+ |
| | SESSION | | | CLIENT | | |
| | | | | | | |
| | client @----|------->| xml-stream @` | |
| | | | +------------------+ |
| | xeps-list @-* | |
| | | +-------------------, |
| | domains @----------->| +-------------------, |
| | | | | +------------------+ |
| +-----------------+ | | | | |
| | | | DOMAINs ---. | |
| `-| | | | |
| `-| | | |
| +----------------|-+ |
+-----------------------------------------------|--------------------------------------+
|
V
Domain View
SESSION DOMAIN
Network ------> route_stanza() user-defined-routes
(dispathers over stanza's type)
domains
You shouldn't use it, it's an internal API.
Use this API for simple apps or as a foundation for your own extensions above the cl-ngxmpp library.
The very basic example how to create a client, connect the client to a xmpp server, log in, send a message, and wait for a response:
(ql:quickload :cl-ngxmpp-client)
(let ((xmpp-client (make-instance 'xmpp:client :debuggable t)))
(xmpp:connect-client xmpp-client :server-hostname "hostname")
(when (xmpp:connectedp xmpp-client)
(xmpp:login-client xmpp-client
:username "username"
:password "password"
;; Only PLAIN and DIGEST-MD5 mechanisms are available due to the lack
;; of support for others in the cl+ssl library
:mechanism "PLAIN or DIGEST-MD5")
(when (xmpp:loggedinp xmpp-client)
(xmpp:send-stanza xmpp-client 'xmpp%:message-stanza :to "to_jid" :body "message")
(let ((response (xmpp:receive-stanza xmpp-client)))
;; Here you get the instance of one of the stanza classes (see src/core/stanzas.lisp file).
;; Do whatever you want with it.
(do something with the response)))))
Another way to handle incoming stanzas, but I wouldn't recommend using it:
(ql:quickload :cl-ngxmpp-client)
;; Define a method for handling stanzas of a type of 'message'
(defmethod xmpp%:handle-stanza ((stanza xmpp%:message-stanza))
(print stanza))
(let ((xmpp-client (make-instance 'xmpp:client :debuggable t)))
(xmpp:connect-client xmpp-client :server-hostname "hostname")
(when (xmpp:connectedp xmpp-client)
(xmpp:login-client xmpp-client
:username "username"
:password "password"
:mechanism "PLAIN or DIGEST-MD5")
(when (xmpp:loggedinp xmpp-client)
(xmpp:send-stanza xmpp-client 'xmpp%:message-stanza :to "to_jid" :body "message")
;; It waits for an incoming stanza, then calls an appropriate handle-stanza method.
;; It's something like an asynchronous interface. See also xmpp:proceed-stanza-loop.
(xmpp:proceed-stanza xmpp-client))))
In case if you miss some functionality in the core XMPP protocol and need to use certain XEPs, you can easily turn on needed XEPs (see a list of available XEPs in src/xeps/ directory):
(ql:quickload :cl-ngxmpp-client)
(let ((xmpp-client (make-instance 'xmpp:client :debuggable t)))
(xmpp:register-xeps xmpp-client '("multi-user-chat"
"delayed-delivery"))
...)
;; Each xep provides its own list of stanzas, these stanzas are the same as usual stanzas
;; from the core (xmpp%) package. That means that you can use them the same
;; way as you did with core stanzas.
;;
;; Attention! The way to work with XEPs can be changed in the future!
Notice! Current examples are deprecated!
You can find the examples inside a src/client/examples/
directory.
First you need to load an 'examples' system:
(ql:quickload :cl-ngxmpp-client.examples)
There is an echo-bot.lisp
example, to run it type in REPL:
(cl-ngxmpp-client.examples.echo-bot:run
:server-hostname "<your jabber server>"
:username "<your jabber login>"
:password "<your jabber password>"
:to "<opponent's jid>"
:message "<body of your message>")
after that the bot will send a message to your opponent, and then will be waiting for messages from him/her in an infinite loop.
- Migrate from cl-async to blackbird library
- Fix the Travis-CI build
- Develop a DSL to have a more concise way to define stanzas
- Re-use the brand new
define-stanza
in a definition of thedefine-xep
macro - Use short package nicknames instead of the long names
- Reorganize the structure of files and directories
- Be able to represent stanzas as XML-encoded strings
- Implement a generic
print-debug
function - Make the README file more descriptive
- CANCELLED Move the
handle-stanza
generic method from thexmpp%
package into thexmpp
(since, it's not a part of the stanza protocol anymore) - Get rid of the
send-*
methods/functions, substitute them with asend-stanza
macro - Re-think and (it would be better) rewrite/remove some code in the
client/xeps/xeps.lisp
- Revisit the
core/xeps.lisp
. Thexmpp-xeps:register-xeps
function should work in the context ofclient
objects. Currently, it affects the global context, so that if multipleclients
are running in the same lisp image, they are writing/reading to/from a dynamic variable stanzas-dispatchers simultaneously, that's a race condition. - Implement an utility to generate a stanza id
- Generate the make-stanza methods automatically by macro
- Prepare the core version of the library for getting it into quicklisp repo
- Show usage examples
- Merge the development and master branches to make a release
- Write more XEPs (see next item)
- NOT FINISHED 0045 Multi User Chat (MUC)
- 0203 Delayed Delivery
- 0004 Data Forms
- NOT FINISHED 0077 In-Band Registration
- Add the remaining stanzas of the core protocol
- Figure out how to validate stanzas (xml schema is a good option I guess). Since there is no CL library for xmlschema, I can go further and try to develop one. It can be used for stanza validation/generation, and can avoid a manual work for these areas in the future.
- Make a logging subsystem pluggable
- Avoid creating a lot of object while dispatching through the stanzas hierarchy, because this can create an additional load on a GC. I might do a research how MOP can help me with this.
- Develop a high-level interface (EPIC)
- Rewrite the tests using mocks
- Add more comments and code documentation
- Think about adding hooks for the basic actions like: connecting, disconnecting, authenticating, etc.
It could be represented as a set of well-defined wrappers over the
xmpp%:handle-stanza
method. There are some number of approaches to managable, user-defined, flexible hook systems: global hooks, e.g.(add-hook 'some-hook #'(lambda () ...))
; per-session hooks. - Improve security (SSL, TLS)
- Add the hostname verification against a SSL certificate (https://tools.ietf.org/html/rfc6125#section-5)
- Add a support for the modern cryptography mechanisms. There are limitations in cl+ssl library.
- Develop a small tool for getting shell over xmpp.
- Develop a simple MUC bot based on 'Markov chains' as an yet another example