Journal of a Bot - XMPPhttps://blog.agayon.be/2022-09-11T15:00:00+02:00Updates: chatty server and HTTPAuthentificationOverXMPP2022-09-11T15:00:00+02:002022-09-11T15:00:00+02:00Arnaudtag:blog.agayon.be,2022-09-11:/xmpp_auth_update.html
<p>It's been a long time since I updated this blog. It will be a short update post about two projects.</p>
<h1>chatty_server</h1>
<p>The first is chatty_server, a small XMPP bot I use to interact with my server. It allows me to get information about the CPU load, traffic, weather etc.
It also has a small feature to get reminder messages. There was a bug that allowed anyone to spam reminders. Anybody can add the bot to their rooster and could create random reminders that I would get.
I got none, so the bot must remain quite unheard-of. </p>
<h1>HTTPAuthentificationOverXMPP</h1>
<p>The second project is HTTPAuthentificationOverXMPP, a component that I use to allow 2 Factor authentication with XMPP.
The <a href="https://git.kingpenguin.tk/chteufleur/HTTPAuthentificationOverXMPP">original project</a> had not been updated for a long time and I wanted to try to modify it to rely on another XMPP go library.
I have never coded in <a href="https://go.dev/">the Golang language</a> and it seemed like a nice introduction. I relied on <a href="https://github.com/FluuxIO/go-xmpp">go-xmpp</a> where I added the <a href="https://github.com/jarobase/go-xmpp/commit/1346ff2a1327414bca0cf4d8b6dba5bea27aa3fc">support for XEP 0070</a>. It was really interesting. The new component is running for several months and I am quite happy with it even if I don't have any serious project relying on it.</p>
<p>The https://demo.agayon.be/ website is still up if you want to test it.<br/>
I hope being able to provide more update about my projects in the future :-).</p>
<h1 id="links">Links</h1>
<ul>
<li><a href="https://xmpp.org/extensions/xep-0070.html">XEP-0070</a></li>
<li><a href="https://git.kingpenguin.tk/chteufleur/HTTPAuthentificationOverXMPP">Authentication component by Chteufleur</a></li>
<li><a href="https://github.com/jarobase/go-xmpp/tree/xep-0070-httpauth">Fork of go-xmpp</a></li>
<li><a href="https://gitlab.com/jnanar/HTTPAuthentificationOverXMPP/-/tree/update_FluuxIO">Fork of HTTPAuthentificationOverXMPP</a></li>
<li><a href="https://gitlab.com/r1dScripts/chatty_server">Chatty Server</a></li>
</ul>
Using Prosody with a HTTP Reverse Proxy2021-03-21T15:00:00+01:002021-03-21T15:00:00+01:00Arnaudtag:blog.agayon.be,2021-03-21:/prosody_http.html
<p>It's been a while since I first installed prosody on Agayon.be. I use it to experiments with my bots, to keep contact with the XMPP community and discover new cool stuffs to do.
Recently I struggled a bit because I wanted to hide the prosody small HTTP server behind my Proxy. For various reasons, I still use Apache 2.4 and I could not get it to work with prosody. I mostly use the HTTP server for bosh authentication with <a href="https://conversejs.org/">Converse.js</a> and with the <a href="https://modules.prosody.im/mod_http_upload.html">http_upload</a> module.
When the 5281 port was accessible and Prosody handled the requests directly on the internet it worked well. But when I followed the documentation to use a proxy, it stopped working.
All my PUT requests got a 404 error. I tested my setup with <a href="https://slixmpp.readthedocs.io/en/latest/">Slixmpp</a> and the http_upload example.</p>
<p>Here is my configuration before the fix:</p>
<h2>Prosody</h2>
<h3>Main config</h3>
<div class="highlight"><pre><span></span><code><span class="k">[...]</span>
<span class="na">https_ports</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">{ 5281 }</span>
<span class="na">https_interfaces</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">{ "127.0.0.1", "::1" }</span>
<span class="na">trusted_proxies</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">{ "127.0.0.1", "::1"}</span>
<span class="k">[...]</span>
</code></pre></div>
<h3>VirtualHost</h3>
<div class="highlight"><pre><span></span><code><span class="k">[...]</span>
<span class="na">Component "upload.example.com" "http_upload"</span>
<span class="w"> </span><span class="na">http_max_content_size</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">10485760</span>
<span class="w"> </span><span class="na">http_external_url</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"https://upload.example.com/"</span>
<span class="k">[...]</span>
</code></pre></div>
<h2>Apache VirtualHost</h2>
<div class="highlight"><pre><span></span><code><span class="o">[</span>...<span class="o">]</span>
ProxyPass<span class="w"> </span>/<span class="w"> </span>http://localhost:5280/
ProxyPassReverse<span class="w"> </span>/<span class="w"> </span>http://localhost:5280/
<span class="o">[</span>...<span class="o">]</span>
</code></pre></div>
<h2>Logs</h2>
<h3>Client</h3>
<div class="highlight"><pre><span></span><code><span class="k">[...]</span>
<span class="na">Client</span><span class="o">:</span>
<span class="na">DEBUG SEND</span><span class="o">:</span><span class="w"> </span><span class="s"><iq id="23efd54cf4b2487386852e800f2ea411" to="upload.example.com" type="get"><request xmlns="urn:xmpp:http:upload:0" filename="robot.png" size="118037" content-type="image/png" /></iq></span>
<span class="na">DEBUG RECV</span><span class="o">:</span><span class="w"> </span><span class="s"><iq type="result" id="23efd54cf4b2487386852e800f2ea411" from="upload.example.com" to="test@example.com/test"><slot xmlns="urn:xmpp:http:upload:0"><get url="https://upload.example.com/upload/au5rOiUMomJbDI3q/robot.png" /><put url="https://upload.example.com/upload/au5rOiUMomJbDI3q/robot.png" /></slot></iq></span>
<span class="na">ERROR Could not upload file</span><span class="o">:</span><span class="w"> </span><span class="s">404 (<!DOCTYPE html></span>
<span class="na"><html></span>
<span class="na"><head></span>
<span class="na"><meta charset</span><span class="o">=</span><span class="s">"utf-8"></span>
<span class="na"><title>404 Not Found</title></span>
<span class="na">example.com</span>
<span class="k">[...]</span>
</code></pre></div>
<h3>Server</h3>
<div class="highlight"><pre><span></span><code><span class="k">[...]</span>
<span class="na">Mar 21 10</span><span class="o">:</span><span class="s">02:42 c2s5586c8e88960 debug Received[c2s]: <iq id='23efd54cf4b2487386852e800f2ea411' type='get' to='upload.example.com'></span>
<span class="na">Mar 21 10</span><span class="o">:</span><span class="s">02:42 c2s5586c8e88960 debug Given upload slot "au5rOiUMomJbDI3q/robot.png"</span>
<span class="na">Mar 21 10</span><span class="o">:</span><span class="s">02:42 c2s5586c8e88960 debug Sending[c2s]: <iq type='result' id='23efd54cf4b2487386852e800f2ea411' from='upload.example.com' to='memo@agayon.be/test'></span>
<span class="na">Mar 21 10</span><span class="o">:</span><span class="s">02:42 socket debug server.lua: accepted new client connection from ::1:49436 to 5280</span>
<span class="na">Mar 21 10</span><span class="o">:</span><span class="s">02:42 http.server debug Firing event: PUT /upload/au5rOiUMomJbDI3q/robot.png</span>
<span class="na">Mar 21 10</span><span class="o">:</span><span class="s">02:42 http.server debug Firing event: PUT localhost/upload/au5rOiUMomJbDI3q/robot.png</span>
</code></pre></div>
<p>What is important to see is the second event:</p>
<div class="highlight"><pre><span></span><code><span class="n">PUT</span><span class="w"> </span><span class="n">localhost</span><span class="o">/</span><span class="n">upload</span><span class="o">/</span><span class="n">au5rOiUMomJbDI3q</span><span class="o">/</span><span class="n">robot</span><span class="o">.</span><span class="n">png</span>
</code></pre></div>
<p>on a working configuration it is </p>
<div class="highlight"><pre><span></span><code><span class="n">PUT</span><span class="w"> </span><span class="n">upload</span><span class="o">.</span><span class="n">example</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">upload</span><span class="o">/</span><span class="n">au5rOiUMomJbDI3q</span><span class="o">/</span><span class="n">robot</span><span class="o">.</span><span class="n">png</span>
</code></pre></div>
<h1>The fix</h1>
<p>After a small discussion with Link Mauve from JabberFr, he suggested me to use setup the proxy to tell him to force its headers:</p>
<h2>Apache</h2>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="p">[</span><span class="o">...</span><span class="p">]</span>
<span class="w"> </span><span class="n">RequestHeader</span><span class="w"> </span><span class="n">set</span><span class="w"> </span><span class="n">Host</span><span class="w"> </span><span class="s2">"upload.example.com"</span>
<span class="w"> </span><span class="n">ProxyPreserveHost</span><span class="w"> </span><span class="n">On</span>
<span class="w"> </span><span class="n">ProxyPass</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">localhost</span><span class="p">:</span><span class="mi">5280</span><span class="o">/</span>
<span class="w"> </span><span class="n">ProxyPassReverse</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">localhost</span><span class="p">:</span><span class="mi">5280</span><span class="o">/</span>
<span class="w"> </span><span class="p">[</span><span class="o">...</span><span class="p">]</span>
</code></pre></div>
<h2>Nginx</h2>
<div class="highlight"><pre><span></span><code><span class="k">[...]</span>
<span class="na">proxy_set_header Host "upload.example.com";</span>
<span class="k">[...]</span>
</code></pre></div>
<p>Two small lines and now it is working as expected :-).</p>
<h1 id="links">Links</h1>
<ul>
<li><a href="https://modules.prosody.im/mod_http_upload.html">http_upload module</a></li>
<li><a href="https://prosody.im/doc/http">Posody http configuration</a></li>
</ul>
Update Errol: the XMPP Automatic file sender2020-05-10T17:00:00+02:002020-05-10T17:00:00+02:00Arnaudtag:blog.agayon.be,2020-05-10:/errol_update1.html
<p>Errol is a file sender that can be used to watch a directory and automatically transfers the new files (or modified ones) with XMPP. </p>
<p>You can find the <a href="https://blog.agayon.be/errol.html">previous description here</a>.</p>
<p>I recently updated it to V2.0.1. This articles describes the changes since last article.</p>
<p>Errol is a file sender that can be used to watch a directory and automatically transfers the new files (or modified ones) with XMPP. </p>
<p>You can find the <a href="https://blog.agayon.be/errol.html">previous description here</a>.</p>
<p>I recently updated it to V2.0.1. This articles describes the changes since last article.</p>
<h1>Changelog</h1>
<ul>
<li>Replaced all the <code>yield from</code> syntax to <code>async/await</code> syntax for asyncio calls</li>
<li>Added some options to enable or not the muc/pubsub features. If your XMPP account does not have a proper pubsub service or if you don't want to advertise your file transfer, these functionalities are not mandatory anymore.</li>
<li>Moving from <a href="https://github.com/rbarrois/aionotify">aionotify</a> to <a href="https://pypi.org/project/watchdog/">watchdog</a>. aionotify was not actively developed since 2 years. Even if is not asynchronous, watchdog can be used with <a href="https://github.com/biesnecker/hachiko">hachiko</a>.</li>
</ul>
<p><strong>Errol should now be usable on Linux, Windows, Mac OS X and FreeBSD</strong> because watchdog supports all these operating systems. Note: only Linux has been tested so far.</p>
<p>I also performed small improvements, refactoring and bug fixes.</p>
<h1>Getting started</h1>
<p>The list of dependencies has been updated but remains quite small.</p>
<ul>
<li><a href="https://lab.louiz.org/poezio/slixmpp">slixmpp</a></li>
<li><a href="https://docs.python.org/3/library/asyncio.html">asyncio </a></li>
<li><a href="https://docs.python.org/3/library/configparser.html">configparser</a></li>
<li><a href="https://pypi.org/project/watchdog/">watchdog</a></li>
<li><a href="https://github.com/biesnecker/hachiko">hachiko</a></li>
</ul>
<h2>Installing</h2>
<p>You can easily install errol with pip.</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>errol
</code></pre></div>
<p>On Archlinux, a PKGBUILD is available in <a href="https://aur.archlinux.org/packages/python-errol/">AUR</a>.</p>
<h2>Configuration</h2>
<p>The complete list of options is available in the template config file.</p>
<div class="highlight"><pre><span></span><code><span class="err">$</span><span class="w"> </span><span class="n">cat</span><span class="w"> </span><span class="n">config</span><span class="p">.</span><span class="n">example</span><span class="p">.</span><span class="n">ini</span>
<span class="o">[</span><span class="n">XMPP</span><span class="o">]</span>
<span class="n">pubsub_enable</span><span class="o">=</span><span class="k">true</span>
<span class="n">muc_enable</span><span class="o">=</span><span class="k">true</span>
<span class="n">pubsub</span><span class="o">=</span><span class="n">pubsub</span><span class="p">.</span><span class="n">example</span><span class="p">.</span><span class="n">org</span>
<span class="n">node</span><span class="o">=</span><span class="n">be</span><span class="p">.</span><span class="n">agayon</span><span class="p">.</span><span class="nl">errol</span><span class="p">:</span><span class="mi">0</span>
<span class="n">room</span><span class="o">=</span><span class="n">chat</span><span class="nv">@chat</span><span class="p">.</span><span class="n">example</span><span class="p">.</span><span class="n">org</span>
<span class="n">jid</span><span class="o">=</span><span class="n">jid</span><span class="nv">@example</span><span class="p">.</span><span class="n">org</span><span class="o">/</span><span class="n">errol</span>
<span class="n">password</span><span class="o">=</span><span class="n">pass</span>
<span class="n">ressource_receiver</span><span class="o">=-</span><span class="n">receiver</span>
<span class="n">ressource_sender</span><span class="o">=-</span>
<span class="n">nick_sender</span><span class="o">=</span><span class="n">example_sender</span>
<span class="n">nick_receiver</span><span class="o">=</span><span class="n">example_receiver</span>
<span class="n">receiver</span><span class="o">=</span><span class="n">jid</span><span class="nv">@example</span><span class="p">.</span><span class="n">org</span><span class="o">/</span><span class="n">errol</span><span class="o">-</span><span class="n">receiver</span>
<span class="n">presence_file</span><span class="o">=/</span><span class="n">tmp</span><span class="o">/</span><span class="n">errol_presence</span><span class="p">.</span><span class="n">txt</span>
</code></pre></div>
<ul>
<li>jid : the jabber account</li>
<li>password: the xmpp password</li>
<li>pubsub: the pubsub server (publish activity)</li>
<li>room: the MUC (chatroom) where errol display information.</li>
<li>presence_file: a writable file used to keep track of presences. I use it in a Django Application. [ref]When receiver is online, the file contains '1' and '0' otherwise. It is not super clean but I did not wanted to bring XMPP features in a Django app.[/ref]</li>
</ul>
<p>The files will be sent by jid@example.org/errol-0 and received by jid@example.org/errol-receiver
. The nicks are the usernames used on the MUC.</p>
<h1>Use it</h1>
<p>Errol should now be usable with only a simple XMPP account and a directory to watch. If you are interested by the Pubsub feature, don't hesitate to read the <a href="https://blog.agayon.be/errol.html">previous article</a>. It contains a section to setup a pubsub node, configure it and access it with several tools.</p>
<h1 id="links">Links</h1>
<ul>
<li><a href="https://gitlab.com/jnanar/errol">Git repository</a></li>
<li><a href="https://pypi.python.org/pypi/errol">pypi package</a></li>
<li><a href="https://blog.agayon.be/errol.html">Previous article</a></li>
</ul>New Converse plugin: Verify HTTP requests with XMPP2019-09-15T12:30:00+02:002019-09-15T12:30:00+02:00Arnaudtag:blog.agayon.be,2019-09-15:/converse_xep_0070.html
<p><a href="https://conversejs.org/">Converse</a> is a JavaScript XMPP client that can be run in a web browser. Unfortunately, it does not support the XMPP extension (XEP) that allows to verify HTTP Requests via XMPP (XMPP): <a href="https://xmpp.org/extensions/xep-0070.html">XEP-0070</a>. So I decided to code a <a href="https://gitlab.com/jnanar/converse-http-auth">small plugin</a> to provide this functionality.</p>
<p>This article follows the serie about this XEP:</p>
<ul>
<li>One about <a href="https://blog.agayon.be/xmpp_auth_django.html">Passordless Authentication using XMPP on a Django website</a>.</li>
<li>A <a href="https://blog.agayon.be/xmpp_auth_django_demo.html">presentation about a demo website</a> providing this functionnality.</li>
</ul>
<p><img alt="screenshot" src="https://blog.agayon.be/images/http_auth.png" style="width: 1080px; height: auto; max-width: 100%;"/></p>
<p><a href="https://conversejs.org/">Converse</a> is a JavaScript XMPP client that can be run in a web browser. Unfortunately, it does not support the XMPP extension (XEP) that allows to verify HTTP Requests via XMPP (XMPP): <a href="https://xmpp.org/extensions/xep-0070.html">XEP-0070</a>. So I decided to code a <a href="https://gitlab.com/jnanar/converse-http-auth">small plugin</a> to provide this functionality.</p>
<p>This article follows the serie about this XEP:</p>
<ul>
<li>One about <a href="https://blog.agayon.be/xmpp_auth_django.html">Passordless Authentication using XMPP on a Django website</a>.</li>
<li>A <a href="https://blog.agayon.be/xmpp_auth_django_demo.html">presentation about a demo website</a> providing this functionnality.</li>
</ul>
<p><img alt="screenshot" src="https://blog.agayon.be/images/http_auth.png" style="width: 1080px; height: auto; max-width: 100%;"/></p>
<h2>How to use it</h2>
<p>See the <a href="https://m.conversejs.org/docs/html/plugin_development.html">official documentation</a> on how to install this plugin.</p>
<p>If you want to hide the authentication request of your provider, you can set the following option in your <code>converse.initialize</code> function:</p>
<p><code>hidden: ['auth.example.com']</code></p>
<p>It will also work with any jid. </p>
<p>You can test the implementation with my demo website: <a href="https://demo.agayon.be/">https://demo.agayon.be/</a></p>
<h1>Links</h1>
<ul>
<li><a href="https://gitlab.com/jnanar/converse-http-auth">Code on Gitlab</a></li>
<li><a href="https://xmpp.org/extensions/xep-0070.html">XEP-0070</a></li>
<li><a href="https://blog.agayon.be/xmpp_auth_django.html">Django authentification</a></li>
<li><a href="https://blog.agayon.be/xmpp_auth_django_demo.html">Demo</a></li>
<li><a href="https://git.kingpenguin.tk/chteufleur/HTTPAuthentificationOverXMPP">Authentication component by Chteufleur</a></li>
<li><a href="https://linuxfr.org/news/authentifiez-vous-sans-mot-de-passe-grace-a-xmpp">Description of the mechanism</a> (french)</li>
</ul>Demo Website: Authentication with XMPP2018-03-18T19:00:00+01:002018-03-18T19:00:00+01:00Arnaudtag:blog.agayon.be,2018-03-18:/xmpp_auth_django_demo.html
<p>This article follow up the article about <a href="https://blog.agayon.be/xmpp_auth_django.html">Authentication without password using XMPP on a Django website</a> previously presented here. This article introduced the XMPP extension (XEP-0070) which allows one to connect on a website with his XMPP account, without additional password. </p>
<p>Unfortunately, the XEP-0070 is not widely used but this article aims to present you my little contribution to change this situation.</p>
<p>This article follow up the article about <a href="https://blog.agayon.be/xmpp_auth_django.html">Authentication without password using XMPP on a Django website</a> previously presented here. This article introduced the XMPP extension (XEP-0070) which allows one to connect on a website with his XMPP account, without additional password. </p>
<p>Unfortunately, the XEP-0070 is not widely used but this article aims to present you my little contribution to change this situation.</p>
<h1>Introduction</h1>
<p>Those who know me know that I tends to have multiple projects in parallels. I have one in the back of my head since several months but it is too early to talk about it yet. I want this project to be usable with XMPP. Some resources will be accessible on a web server but I don't want to force users to manage additional passwords. This is the perfect use case of XEP-0070.[ref]<a href="https://www.goffi.org/">Goffi</a> from the <a href="https://salut-a-toi.org/">Salut à Toi </a> project is curently working on a different solution to adress these kind of challenges. [/ref] </p>
<p>In order to test the accessibility and the number of user-friendly clients that support this extension, I published a small demo website: </p>
<h1><a href="https://demo.agayon.be/">https://demo.agayon.be/</a></h1>
<p>This website is built with the famous <a href="https://www.djangoproject.com/">Django framework</a>. Moreover, the revelant code is available in the <a href="https://blog.agayon.be/xmpp_auth_django.html">previous post</a> and on the <a href="https://gitlab.com/earth_explorer/demo">Gitlab page</a>.</p>
<p>You can try the demo by clicking on the "Sign In" button. The only information needed is your XMPP account (JID). You will then receive a request on your XMPP client. If it does support the XEP, you will be invited to click in a dialog box in order to accept the connection.</p>
<p>It your client does not support it, there is a fallback mechanism where you receive a message from "auth.agayon.be". Unfortunately, The method may be tedious on some mobile clients. It is quite sad because it is the best use case of the XEP.</p>
<h1>Examples</h1>
<h2>Movim (new)</h2>
<p>Shortly after I submitted a <a href="https://github.com/movim/movim/issues/600">bug report</a> about this feature, <a href="https://nl.movim.eu/?blog/edhelas@movim.eu">edhelas</a> from the Movim project implemented it. His reactivity is remarkable. The feature is available on the <a href="https://movim.eu/#get_it">official pods</a>.</p>
<p><img alt="Movim" src="https://blog.agayon.be/images/XEP-0070-movim.png" style="width: 406px; height: auto; max-width: 100%;"/></p>
<h2>Gajim</h2>
<p><img alt="Gajim XEP-0070" src="https://blog.agayon.be/images/XEP-0070-Gajim.png" style="width: 514px; height: auto; max-width: 100%;"/></p>
<h2>Salut à toi (Primitivus)</h2>
<p><img alt="Primitivus XEP-0070" src="https://blog.agayon.be/images/XEP-0070-primitivus.png.webp" style="width: 658px; height: auto; max-width: 100%;"/></p>
<h2>Conversations</h2>
<p>Unfortunately, <a href="https://conversations.im/">Conversations</a>, one of the best mobile clients, <a href="https://github.com/siacs/Conversations/issues/1972">does not support the feature yet</a>.</p>
<p><img alt="Conversations" src="https://blog.agayon.be/images/XEP-0070-conversations.png" style="width: 384px; height: auto; max-width: 100%;"/></p>
<h1>Sources</h1>
<p>The sources are available on my <a href="https://gitlab.com/earth_explorer/demo">gitlab.com account</a>.</p>
<p>The service is still in beta. Do not hesitate to contact me if you experience some bugs with the demo.</p>
<h1>Conclusions</h1>
<p>You no longer have excuses to avoid to authenticate users on your platform with XMPP. </p>
<ul>
<li>Nice and user-friendly clients implement it.</li>
<li>The Chteufleur's component is stable and easy to use.</li>
<li>It is quite easy to add the functionality on the website running with django, <a href="https://wordpress.org/plugins/xmpp-auth/">Wordpress</a> and it should not be an insurmountable challenge with <a href="http://rubyonrails.org/">ruby on rails</a>.</li>
</ul>
<p>In the future, I will probably encourage new users to use Movim with my projects as it does not require installation and it supports the XEP.</p>
<p>I hope to be able to give you updates soon about the agayon project.</p>
<p>In the meantime, bug reports have been submitted:</p>
<ul>
<li><a href="https://github.com/siacs/Conversations/issues/1972">Conversations</a></li>
<li><a href="https://github.com/jcbrand/converse.js/issues/1020">Converse.js</a></li>
<li><a href="https://github.com/movim/movim/issues/600">Movim</a> (Already fixed as previously mentioned)</li>
</ul>
<p>Stay tuned !</p>
<h1>Links</h1>
<ul>
<li><a href="https://xmpp.org/extensions/xep-0070.html">XEP-0070</a></li>
<li><a href="https://git.kingpenguin.tk/chteufleur/HTTPAuthentificationOverXMPP">Authentication component by Chteufleur</a></li>
<li><a href="https://linuxfr.org/news/authentifiez-vous-sans-mot-de-passe-grace-a-xmpp">Description of the mechanism</a> (french)</li>
<li><a href="https://docs.djangoproject.com/en/1.10/topics/auth/default/">Django authentification</a></li>
<li><a href="https://blog.agayon.be/xmpp_auth_django.html">Previous article</a></li>
<li><a href="https://gitlab.com/earth_explorer/demo">Code on Gitlab</a></li>
</ul>Errol: XMPP Automatic file sender2018-01-01T14:00:00+01:002018-01-01T14:00:00+01:00Arnaudtag:blog.agayon.be,2018-01-01:/errol.html
<p>Errol is a file sender that rely on <a href="https://en.wikipedia.org/wiki/Inotify">inotify</a>. It can be used to watch a directory and automatically transfers the new files (or modified ones) with XMPP.</p>
<p>Errol is a file sender that rely on <a href="https://en.wikipedia.org/wiki/Inotify">inotify</a>. It can be used to watch a directory and automatically transfers the new files (or modified ones) with XMPP.</p>
<h1>The origins</h1>
<p>Errol find its origin in tasks I am doing for a small association, "<a href="http://www.compagnonsducep.be">Les compagnons du CEP</a>", a joint buying organization who sells wines. I manage their ERP, the excellent <a href="https://www.odoo.com/">Odoo</a>. One of these tasks is the generation of their price list from an Excel spreadsheet (yeah, I know). I designed this process with a <a href="https://www.latex-project.org/">LaTeX</a> generator written in python because I am fluent with it since 10 years. As I did not want to install a LaTeX distribution on the production server, the logical decision was to delocalize this task on another machine. The user uploads his excel file on a webpage, the file is saved in a "watched" directory and its transfer is triggered on the second machine with XMPP. The generation of the latex document and its compilation is performed with LaTeX and the resulting PDF is sent back to the server. The PDF is therefore available for download.</p>
<h2>Why Errol?</h2>
<p>In the fictional universe of Harry Potter, <a href="https://en.wikipedia.org/wiki/Magical_creatures_in_Harry_Potter#The_Weasleys'_creatures"><strong>Errol</strong></a> is the Weasley family's owl. It is quite old and awkward. One could says the same about XMPP but Errol is quite useful, XMPP is too :-). Errol is a great grey owl. (see pictures)</p>
<p><a href="https://www.flickr.com/photos/blurredca/10527590684/"><img alt="photo credit: blurred.ca https://www.flickr.com/photos/blurredca/10527590684/" src="https://blog.agayon.be/images/owl6.jpg" style="width: 752px; height: auto; max-width: 100%;"/></a>
Photo credit: <a href="https://www.flickr.com/photos/blurredca/">blurred.ca</a>, Great Grey Owl</p>
<hr/>
<h1>Howto</h1>
<h2>Prerequisites</h2>
<p>Errol needs the following requirements:</p>
<ul>
<li>A system supporting <a href="https://en.wikipedia.org/wiki/Inotify">inotify</a> (Linux).</li>
<li>an XMPP (jabber) account supporting the following XEPs: <a href="https://xmpp.org/extensions/xep-0198.html">Stream Management</a>, <a href="https://xmpp.org/extensions/xep-0060.html">Publish-Subscribe</a>, <a href="https://xmpp.org/extensions/xep-0045.html">Multi-User Chat</a></li>
<li>A PubSub service where the nodes can be set as open. The node name is defined in the configuration file. I personally use <a href="https://blog.agayon.be/sat_pubsub.html">sat_pubsub</a>. A PubSub
component developed for the project <a href="https://salut-a-toi.org/">Salut à Toi</a>. </li>
<li>A Multi-User Chat because not all XMPP accounts support PubSub. For now, some information are still shared through MUC messages. This behavior could change in the future.</li>
<li>The latest (dev) version of <a href="https://lab.louiz.org/poezio/slixmpp">Slixmpp</a>.</li>
</ul>
<p>You can use your own XMPP server or choose a XMPP service among the following <a href="https://conversations.im/compliance/">list</a>. </p>
<h3>Create the PubSub node</h3>
<p>This step is optional if you already have a write access on the pubsub node. The following example use <a href="https://blog.agayon.be/sat_jp.html">jp</a>, the Salut à Toi command-line interface but
<a href="https://lab.louiz.org/poezio/slixmpp">slixmpp</a> or
<a href="https://github.com/fritzy/SleekXMPP">sleekxmpp</a> can be used. </p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>pubsub<span class="w"> </span>node<span class="w"> </span>create<span class="w"> </span>-f<span class="w"> </span>publish_model<span class="w"> </span>open<span class="w"> </span>be.agayon.errol:0<span class="w"> </span>-s<span class="w"> </span>pubsub.agayon.be<span class="w"> </span>-c
</code></pre></div>
<p>The node name be.agayon.errol:0 is recommended in order to identify the functionality.</p>
<p>As an example, there are the node options on the service pubsub.agayon.be:</p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">jp</span><span class="w"> </span><span class="n">pubsub</span><span class="w"> </span><span class="n">node</span><span class="w"> </span><span class="n">info</span><span class="w"> </span><span class="n">be</span><span class="o">.</span><span class="n">agayon</span><span class="o">.</span><span class="n">errol</span><span class="p">:</span><span class="mi">0</span><span class="w"> </span><span class="o">-</span><span class="n">s</span><span class="w"> </span><span class="n">pubsub</span><span class="o">.</span><span class="n">agayon</span><span class="o">.</span><span class="n">be</span>
<span class="n">persist_items</span><span class="p">:</span><span class="w"> </span><span class="n">True</span>
<span class="n">deliver_payloads</span><span class="p">:</span><span class="w"> </span><span class="n">True</span>
<span class="n">serial_ids</span><span class="p">:</span><span class="w"> </span><span class="n">False</span>
<span class="n">publish_model</span><span class="p">:</span><span class="w"> </span><span class="n">open</span>
<span class="n">access_model</span><span class="p">:</span><span class="w"> </span><span class="n">open</span>
<span class="n">send_last_published_item</span><span class="p">:</span><span class="w"> </span><span class="n">on_sub</span>
</code></pre></div>
<p>If your server supports <a href="https://xmpp.org/extensions/xep-0163.html">Personal Eventing Protocol</a>(PEP) or if you do not want to use the generic PubSub service of your server, you can use your jid.</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>pubsub<span class="w"> </span>node<span class="w"> </span>create<span class="w"> </span>-f<span class="w"> </span>publish_model<span class="w"> </span>open<span class="w"> </span>be.agayon.errol:0<span class="w"> </span>-s<span class="w"> </span>info@agayon.be<span class="w"> </span>-c
</code></pre></div>
<h3>Tests</h3>
<p>You can test your setup with the examples scripts of <a href="https://git.poez.io/slixmpp">slixmpp</a>.</p>
<ul>
<li><a href="https://git.poez.io/slixmpp/tree/examples/pubsub_client.py">pubsub_client.py</a></li>
<li><a href="https://git.poez.io/slixmpp/tree/examples/pubsub_events.py">pubsub_events.py</a></li>
<li><a href="https://git.poez.io/slixmpp/tree/examples/s5b_transfer/s5b_receiver.py">s5b_receiver.py</a></li>
<li><a href="https://git.poez.io/slixmpp/tree/examples/s5b_transfer/s5b_sender.py">s5b_sender.py</a></li>
</ul>
<p>Example:</p>
<div class="highlight"><pre><span></span><code><span class="p">.</span><span class="o">/</span><span class="n">s5b_file_sender</span><span class="p">.</span><span class="n">py</span><span class="w"> </span><span class="o">-</span><span class="n">j</span><span class="w"> </span><span class="n">jid</span><span class="nv">@example</span><span class="p">.</span><span class="n">org</span><span class="w"> </span><span class="o">-</span><span class="n">p</span><span class="w"> </span><span class="n">pass</span><span class="w"> </span><span class="o">-</span><span class="n">r</span><span class="w"> </span><span class="n">john</span><span class="nv">@example</span><span class="p">.</span><span class="n">org</span><span class="w"> </span><span class="o">-</span><span class="n">f</span><span class="w"> </span><span class="o">/</span><span class="k">path</span><span class="o">/</span><span class="k">to</span><span class="o">/</span><span class="k">file</span><span class="p">.</span><span class="n">txt</span><span class="w"> </span>
</code></pre></div>
<p>See the scripts for more information.</p>
<h2>Getting started with Errol</h2>
<p>Errol needs the following dependencies:</p>
<ul>
<li><a href="https://lab.louiz.org/poezio/slixmpp">slixmpp</a> (python 3 only), git revision after 2017-12-27</li>
<li><a href="https://docs.python.org/3/library/asyncio.html">asyncio </a></li>
<li><a href="https://docs.python.org/3/library/configparser.html">configparser</a></li>
<li><a href="https://github.com/rbarrois/aionotify">aionotify</a></li>
</ul>
<h2>Installing</h2>
<p>You can easily install errol with pip:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>errol
</code></pre></div>
<p>Note: errol can be installed in a <a href="https://virtualenv.pypa.io/en/stable/userguide/">virtualenv</a>.</p>
<p>You can also clone the git repository:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>git<span class="w"> </span>clone<span class="w"> </span>https://gitlab.com/jnanar/errol.git
$<span class="w"> </span><span class="nb">cd</span><span class="w"> </span>errol
$<span class="w"> </span>python3<span class="w"> </span>setup.py<span class="w"> </span>install
</code></pre></div>
<p>On Archlinux:</p>
<div class="highlight"><pre><span></span><code>A PKGBUILD will be available soon.
</code></pre></div>
<h2>Configuration</h2>
<p>You need to provide information about the XMPP account.</p>
<div class="highlight"><pre><span></span><code><span class="err">$</span><span class="w"> </span><span class="n">cat</span><span class="w"> </span><span class="n">config</span><span class="p">.</span><span class="n">example</span><span class="p">.</span><span class="n">ini</span>
<span class="o">[</span><span class="n">XMPP</span><span class="o">]</span>
<span class="n">pubsub</span><span class="o">=</span><span class="n">pubsub</span><span class="p">.</span><span class="n">example</span><span class="p">.</span><span class="n">org</span>
<span class="n">node</span><span class="o">=</span><span class="n">be</span><span class="p">.</span><span class="n">agayon</span><span class="p">.</span><span class="nl">errol</span><span class="p">:</span><span class="mi">0</span>
<span class="n">room</span><span class="o">=</span><span class="n">chat</span><span class="nv">@chat</span><span class="p">.</span><span class="n">example</span><span class="p">.</span><span class="n">org</span>
<span class="n">jid</span><span class="o">=</span><span class="n">jid</span><span class="nv">@example</span><span class="p">.</span><span class="n">org</span><span class="o">/</span><span class="n">errol</span>
<span class="n">password</span><span class="o">=</span><span class="n">pass</span>
<span class="n">ressource_receiver</span><span class="o">=-</span><span class="n">receiver</span>
<span class="n">ressource_sender</span><span class="o">=-</span>
<span class="n">nick_sender</span><span class="o">=</span><span class="n">example_sender</span>
<span class="n">nick_receiver</span><span class="o">=</span><span class="n">example_receiver</span>
<span class="n">receiver</span><span class="o">=</span><span class="n">jid</span><span class="nv">@example</span><span class="p">.</span><span class="n">org</span><span class="o">/</span><span class="n">errol</span><span class="o">-</span><span class="n">receiver</span>
</code></pre></div>
<ul>
<li>jid : the jabber account</li>
<li>password: the xmpp password</li>
<li>pubsub: the PubSub server (publish activity)</li>
<li>room: the MUC (chatroom) where errol display information.</li>
</ul>
<p>The files will be sent by jid@example.org/errol-0 and received by jid@example.org/errol-receiver
. The nicks are the usernames used on the MUC.</p>
<h2>Flying</h2>
<p><a href="https://www.flickr.com/photos/widnr/8716853721/"><img alt="Photo credit: Wisconsin Department of Natural Resources https://www.flickr.com/photos/widnr/" src="https://blog.agayon.be/images/owl7.jpg" style="width: 704px; height: auto; max-width: 100%;"/></a>
Photo credit: <a href="https://www.flickr.com/photos/widnr/">Wisconsin Department of Natural Resources</a>, Great Grey Owl at Mauston</p>
<p>Once installed, Errol can be launched in a terminal.</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>errol<span class="w"> </span>--help
usage:<span class="w"> </span>errol<span class="w"> </span><span class="o">[</span>-h<span class="o">]</span><span class="w"> </span><span class="o">[</span>-e<span class="w"> </span>EVENTS<span class="o">]</span><span class="w"> </span><span class="o">[</span>-f<span class="w"> </span>FILE<span class="o">]</span><span class="w"> </span><span class="o">[</span>-d<span class="o">]</span><span class="w"> </span>-p<span class="w"> </span>PATH<span class="w"> </span>-c<span class="w"> </span>COMMAND
Automatic<span class="w"> </span>XMPP<span class="w"> </span>file<span class="w"> </span>sender<span class="w"> </span>and<span class="w"> </span>directory<span class="w"> </span>watcher
optional<span class="w"> </span>arguments:
<span class="w"> </span>-h,<span class="w"> </span>--help<span class="w"> </span>show<span class="w"> </span>this<span class="w"> </span><span class="nb">help</span><span class="w"> </span>message<span class="w"> </span>and<span class="w"> </span><span class="nb">exit</span>
<span class="w"> </span>-e<span class="w"> </span>EVENTS,<span class="w"> </span>--events<span class="w"> </span>EVENTS
<span class="w"> </span>Number<span class="w"> </span>of<span class="w"> </span>events<span class="w"> </span>to<span class="w"> </span>watch<span class="w"> </span><span class="o">(</span>delete,<span class="w"> </span>create<span class="w"> </span>modify<span class="o">)</span><span class="w"> </span><span class="k">in</span>
<span class="w"> </span>the<span class="w"> </span>directory.<span class="w"> </span>Once<span class="w"> </span>reached,<span class="w"> </span>the<span class="w"> </span>program<span class="w"> </span>stops.
<span class="w"> </span>-f<span class="w"> </span>FILE,<span class="w"> </span>--file<span class="w"> </span>FILE<span class="w"> </span>Config<span class="w"> </span>file<span class="w"> </span>containing<span class="w"> </span>XMPP<span class="w"> </span>parameters
<span class="w"> </span>-d,<span class="w"> </span>--debug<span class="w"> </span><span class="nb">set</span><span class="w"> </span>logging<span class="w"> </span>to<span class="w"> </span>DEBUG
<span class="w"> </span>-p<span class="w"> </span>PATH,<span class="w"> </span>--path<span class="w"> </span>PATH<span class="w"> </span>The<span class="w"> </span>path<span class="w"> </span>watched.
<span class="w"> </span>-c<span class="w"> </span>COMMAND,<span class="w"> </span>--command<span class="w"> </span>COMMAND
<span class="w"> </span>The<span class="w"> </span>executed<span class="w"> </span>command:<span class="w"> </span>xmpp<span class="w"> </span>or<span class="w"> </span>watcher
</code></pre></div>
<h3>In Hogwarts</h3>
<p>If you want to watch the directory /tmp/sender, the following command can be used:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>errol<span class="w"> </span>-f<span class="w"> </span>config.example.ini<span class="w"> </span>-p<span class="w"> </span>/tmp/sender<span class="w"> </span>-c<span class="w"> </span>watcher
</code></pre></div>
<p>All modified or new files created in the watched location will be sent by XMPP.</p>
<h3>In Azkaban</h3>
<p>If you want to receive the files, you have to launch Errol with the following command line.</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>errol<span class="w"> </span>-f<span class="w"> </span>config.example.ini<span class="w"> </span>-p<span class="w"> </span>/tmp/receiver<span class="w"> </span>-c<span class="w"> </span>xmpp
</code></pre></div>
<p>All the received files will be stored in the directory defined with the option '-p'.</p>
<h2>License</h2>
<p>This project is licensed under the GPLv3 - see the <a href="https://gitlab.com/jnanar/errol/blob/master/LICENCE.txt">LICENSE.txt</a> file for details</p>
<h1>Why not X or Y?</h1>
<p><a href="https://www.flickr.com/photos/volvob12b/37310719232/"><img alt="Photo credit: Bernard Spragg. NZ https://www.flickr.com/photos/volvob12b/37310719232/" src="https://blog.agayon.be/images/owl3.jpg" style="width: 821px; height: auto; max-width: 100%;"/></a>
Photo credit: <a href="https://www.flickr.com/photos/volvob12b/">Bernard Spragg. NZ</a>, Great Grey Owl (Strix nebulosa)</p>
<p>There are plenty solutions for this kind of needs. Some of them are more mature. I choose XMPP for several reasons:</p>
<ul>
<li><a href="https://agayon.be">agayon.be</a> already provides a up-to-date XMPP server with all the needed XEPs enabled.</li>
<li>I do not want to open additional port on the client that performs the LaTeX compilation.</li>
<li>I wanted to learn to work with XMPP for machine to machine communications and use PubSub notifications (because why not?).</li>
</ul>
<p>Among the alternatives, I could have build the service on top of:</p>
<ul>
<li>sockets</li>
<li>HTTP file transfer</li>
<li>REST API</li>
<li>SSH and remote commands.</li>
<li>rsync</li>
<li>...</li>
</ul>
<h2>Acknowledgments</h2>
<p><a href="https://www.flickr.com/photos/115391424@N05/36873334554/"><img alt="Photo credit: lasta29, Great grey owl, Osaka Tennoji Zoo https://www.flickr.com/photos/115391424@N05/36873334554/" src="https://blog.agayon.be/images/owl5.jpg" style="width: 750px; height: auto; max-width: 100%;"/></a>
Photo credit: <a href="https://www.flickr.com/photos/115391424@N05/">lasta29</a>, Great grey owl, Osaka Tennoji Zoo</p>
<ul>
<li>The french XMPP community (availaible on sat@chat.jabberfr.org, jabberfr@chat.jabberfr.org, ...)</li>
<li><a href="https://lab.louiz.org/poezio/slixmpp">The Slixmpp maintainers</a> Florent Le Coz, Mathieu Pasquet for their nice library.</li>
<li>Emmanuel Gil Peyrot (Link mauve) for its reactivity.</li>
<li>Goffi from the <a href="https://salut-a-toi.org/">Salut à Toi</a> project for his explanations and his disponibility.</li>
</ul>
<h1 id="links">Links</h1>
<ul>
<li><a href="https://gitlab.com/jnanar/errol">Git repository</a></li>
<li><a href="https://pypi.python.org/pypi/errol">pypi package</a></li>
<li><a href="https://salut-a-toi.org/">Salut à Toi</a></li>
<li><a href="https://docs.python.org/3/library/asyncio.html">asyncio </a></li>
<li><a href="https://lab.louiz.org/poezio/slixmpp">slixmpp</a></li>
<li><a href="https://github.com/rbarrois/aionotify">aionotify</a></li>
</ul>Using sat-pubsub, a great pubsub component2017-11-26T20:00:00+01:002019-05-30T16:00:00+02:00Arnaudtag:blog.agayon.be,2017-11-26:/sat_pubsub.html
<p>In the continuity with the <a href="https://blog.agayon.be/sat_jp.html">previous post about jp</a>, the following article present <a href="https://wiki.goffi.org/wiki/Libervia/en#S.C3.A0T_PubSub">sat_pubsub</a>, a XMPP Publish-Subscribe (Pubsub) Service Component, build for the need of the « <a href="https://salut-a-toi.org/">Salut à Toi</a> » project.</p>
<p><a href="https://salut-a-toi.org/">Salut à toi</a> (SàT) is a unique XMPP client. As its official description says, it's a "multipurpose, multi front-end, free (libre) and decentralized communication tool". It has been actively developed by Jérôme Poisson (Goffi) and Adrien Cossa (Souliane) since 2008.</p>
<p>sat_pubsub allows us to use our own up-to-date persistent pubsub service.</p>
<p>This article is composed of several sections</p>
<ul>
<li><a href="#why">Why sat_pubsub ?</a> </li>
<li><a href="#install">Let's install it !</a></li>
<li><a href="#test">Let's use it !</a></li>
<li>A note about <a href="#agayon">Agayon XMPP service</a></li>
<li><a href="#future">Future of SàT</a></li>
<li><a href="#links">Links</a></li>
</ul>
<p>In the continuity with the <a href="https://blog.agayon.be/sat_jp.html">previous post about jp</a>, the following article present <a href="https://wiki.goffi.org/wiki/Libervia/en#S.C3.A0T_PubSub">sat_pubsub</a>, a XMPP Publish-Subscribe (Pubsub) Service Component, build for the need of the « <a href="https://salut-a-toi.org/">Salut à Toi</a> » project.</p>
<p><a href="https://salut-a-toi.org/">Salut à toi</a> (SàT) is a unique XMPP client. As its official description says, it's a "multipurpose, multi front-end, free (libre) and decentralized communication tool". It has been actively developed by Jérôme Poisson (Goffi) and Adrien Cossa (Souliane) since 2008.</p>
<p>sat_pubsub allows us to use our own up-to-date persistent pubsub service.</p>
<p>This article is composed of several sections</p>
<ul>
<li><a href="#why">Why sat_pubsub ?</a> </li>
<li><a href="#install">Let's install it !</a></li>
<li><a href="#test">Let's use it !</a></li>
<li>A note about <a href="#agayon">Agayon XMPP service</a></li>
<li><a href="#future">Future of SàT</a></li>
<li><a href="#links">Links</a></li>
</ul>
<h1 id="why">Why sat_pubsub ?</h1>
<p>There are <strong>three</strong> main reasons to use sat_pubsub.</p>
<p>First, the XMPP servers come with variable pubsub support. Using an external component allows users to benefits constant features independent of the XMPP server or provider.</p>
<p>Secondly, sat_pubub is the only free (libre) implementation that support Pubsub MAM (Message Archive Management). It allows one to research a pubsub node. This feature is used to research blog post in the database.</p>
<p>Thirdly, sat_pubsub is used to test new functionalities like the ability to restrict blog post to specific group of contacts (think about circles on Google+). [ref]See the following <a href="https://www.goffi.org/blog/goffi/S%C3%A0T_DOTCLEAR_IMPORT_BLOG_default_goffi_69%3A2012%2F06%2F24%2FFine-access-tuning-for-PubSub">blog post</a> for more information.[/ref]. </p>
<h1 id="install">Let's install it !</h1>
<p>This section describes the installation process of sat_pubsub in a python virtualenv. Unfortunately, I have encountered difficulties to install twisted, a dependency of SàT, in a virtualenv with pip because my production machine has no compiler. I managed to avoid the problem by installing python2-twisted (the distribution package) then the virtualenv was created with the option <code>--system-site-packages</code> to give it access to the system packages. Thereafter, it is possible to install sat_tmp, a small python module that monkey patch wokkel, a dependency of sat_pubsub.</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>python2-twisted
<span class="o">[</span>...<span class="o">]</span>
$<span class="w"> </span>hg<span class="w"> </span>clone<span class="w"> </span>http://repos.goffi.org/sat_tmp
$<span class="w"> </span><span class="nb">cd</span><span class="w"> </span>sat_tmp/
$<span class="w"> </span>virtualenv<span class="w"> </span>env<span class="w"> </span>-ppython2.7<span class="w"> </span>--system-site-packages
$<span class="w"> </span><span class="nb">source</span><span class="w"> </span>env/bin/activate
<span class="o">(</span>env<span class="o">)</span>$<span class="w"> </span>python2<span class="w"> </span>setup.py<span class="w"> </span>install
<span class="o">(</span>env<span class="o">)</span>$<span class="w"> </span><span class="nb">cd</span><span class="w"> </span>../
<span class="o">(</span>env<span class="o">)</span>$<span class="w"> </span>hg<span class="w"> </span>clone<span class="w"> </span>https://repos.goffi.org/sat_pubsub
<span class="o">(</span>env<span class="o">)</span>$<span class="w"> </span><span class="nb">cd</span><span class="w"> </span>sat_pubsub
<span class="o">(</span>env<span class="o">)</span>$<span class="w"> </span>python2<span class="w"> </span>setup.py<span class="w"> </span>install
</code></pre></div>
<h2>Setup the database</h2>
<p>According to the official <a href="https://wiki.goffi.org/wiki/Libervia/en#S.C3.A0T_PubSub">documentation</a>, we need to create the database and install the SQL schema.</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>sudo<span class="w"> </span>-u<span class="w"> </span>postgres<span class="w"> </span>createuser<span class="w"> </span>-d<span class="w"> </span>-P<span class="w"> </span><span class="sb">`</span>whoami<span class="sb">`</span>
$<span class="w"> </span>createdb<span class="w"> </span>pubsub
$<span class="w"> </span>psql<span class="w"> </span>pubsub<span class="w"> </span><<span class="w"> </span>sat_pubsub/db/pubsub.sql
</code></pre></div>
<h2>Configure Prosody</h2>
<p>In order to use sat_pubsub, we need to declare it in our prosody config file. Once again, the information is available in the <a href="https://wiki.goffi.org/wiki/Libervia/en#S.C3.A0T_PubSub">documentation</a>. Two files need to be modified: </p>
<ul>
<li>/etc/prosody/prosody.cfg.lua</li>
</ul>
<div class="highlight"><pre><span></span><code><span class="p">[...]</span>
<span class="n">modules_enabled</span> <span class="o">=</span> <span class="p">{</span>
<span class="p">[...]</span>
<span class="s2">"delegation"</span><span class="p">;</span>
<span class="s2">"privilege"</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">[...]</span>
</code></pre></div>
<ul>
<li>/etc/prosody/conf.avail/your_domain.cfg.lua</li>
</ul>
<p>This file defines the domain configuration of your XMPP server.</p>
<p>This is a copy of the configuration for the agayon server. The pubsub component is available at the address pubsub.agayon.be.
The following configuration:</p>
<ul>
<li>enables pubsub MAM,</li>
<li>uses the component for microblogging activity,</li>
<li>announces the pubsub nodes and items in <a href="https://xmpp.org/extensions/xep-0030.html">disco requests</a>,</li>
<li>lets the component access the roster and presence informations (used for <a href="https://xmpp.org/extensions/xep-0163.html">PEP</a>).</li>
</ul>
<div class="highlight"><pre><span></span><code><span class="n">VirtualHost</span> <span class="s2">"agayon.be"</span>
<span class="n">enabled</span> <span class="o">=</span> <span class="kc">true</span>
<span class="p">[...]</span>
<span class="n">privileged_entities</span> <span class="o">=</span> <span class="p">{</span>
<span class="p">[</span><span class="s2">"pubsub.agayon.be"</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
<span class="n">roster</span> <span class="o">=</span> <span class="s2">"get"</span><span class="p">;</span>
<span class="n">message</span> <span class="o">=</span> <span class="s2">"outgoing"</span><span class="p">;</span>
<span class="n">presence</span> <span class="o">=</span> <span class="s2">"roster"</span><span class="p">;</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="n">delegations</span> <span class="o">=</span> <span class="p">{</span>
<span class="p">[</span><span class="s2">"urn:xmpp:mam:1"</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
<span class="n">filtering</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"node"</span><span class="p">};</span>
<span class="n">jid</span> <span class="o">=</span> <span class="s2">"pubsub.agayon.be"</span><span class="p">;</span>
<span class="p">},</span>
<span class="p">[</span><span class="s2">"http://jabber.org/protocol/pubsub"</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
<span class="n">jid</span> <span class="o">=</span> <span class="s2">"pubsub.agayon.be"</span><span class="p">;</span>
<span class="p">},</span>
<span class="p">[</span><span class="s2">"http://jabber.org/protocol/pubsub#owner"</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
<span class="n">jid</span> <span class="o">=</span> <span class="s2">"pubsub.agayon.be"</span><span class="p">;</span>
<span class="p">},</span>
<span class="p">[</span><span class="s2">"https://salut-a-toi/protocol/schema:0"</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
<span class="n">jid</span> <span class="o">=</span> <span class="s2">"pubsub.agayon.be"</span><span class="p">;</span>
<span class="p">},</span>
<span class="p">[</span><span class="s2">"http://jabber.org/protocol/disco#items:*"</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
<span class="n">jid</span> <span class="o">=</span> <span class="s2">"pubsub.agayon.be"</span><span class="p">;</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="n">Component</span> <span class="s2">"pubsub.agayon.be"</span>
<span class="n">component_secret</span> <span class="o">=</span> <span class="s2">"shared_secret"</span>
<span class="n">modules_enabled</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"delegation"</span><span class="p">,</span> <span class="s2">"privilege"</span><span class="p">}</span>
</code></pre></div>
<h2>Launch</h2>
<div class="highlight"><pre><span></span><code><span class="o">(</span>env<span class="o">)</span>$<span class="w"> </span>twistd<span class="w"> </span>sat_pubsub<span class="w"> </span>--jid<span class="o">=</span>pubsub.agayon.be<span class="w"> </span>--secret<span class="o">=</span>shared_secret<span class="w"> </span>--rhost<span class="o">=</span><span class="m">127</span>.0.0.1<span class="w"> </span><span class="se">\</span>
--rport<span class="o">=</span><span class="m">5347</span><span class="w"> </span>--backend<span class="o">=</span>pgsql<span class="w"> </span>--dbuser<span class="o">=</span>user<span class="w"> </span>--dbpass<span class="o">=</span>pass_psql<span class="w"> </span>--dbname<span class="o">=</span>pubsub<span class="w"> </span>--dbhost<span class="o">=</span>localhost<span class="w"> </span>--dbport<span class="o">=</span><span class="m">5432</span>
</code></pre></div>
<h1 id="test">Let's use it !</h1>
<p>Once prosody is restarted, the component is accessible through any XMPP client. See the following example with <a href="https://blog.agayon.be/sat_jp.html">jp</a>.</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>info<span class="w"> </span>disco<span class="w"> </span>pubsub.agayon.be<span class="w"> </span>-c
Features
http://jabber.org/protocol/disco#items
http://jabber.org/protocol/pubsub#auto-create
http://jabber.org/protocol/pubsub#config-node
http://jabber.org/protocol/pubsub#create-nodes
http://jabber.org/protocol/pubsub#delete-any
http://jabber.org/protocol/pubsub#delete-nodes
http://jabber.org/protocol/pubsub#groupblog
http://jabber.org/protocol/pubsub#instant-nodes
http://jabber.org/protocol/pubsub#item-ids
http://jabber.org/protocol/pubsub#meta-data
http://jabber.org/protocol/pubsub#outcast-affiliation
http://jabber.org/protocol/pubsub#persistent-items
http://jabber.org/protocol/pubsub#publish
http://jabber.org/protocol/pubsub#publish-options
http://jabber.org/protocol/pubsub#publisher-affiliation
http://jabber.org/protocol/pubsub#purge-nodes
http://jabber.org/protocol/pubsub#retract-items
http://jabber.org/protocol/pubsub#retrieve-affiliations
http://jabber.org/protocol/pubsub#retrieve-default
http://jabber.org/protocol/pubsub#retrieve-items
http://jabber.org/protocol/pubsub#retrieve-subscriptions
http://jabber.org/protocol/pubsub#subscribe
https://salut-a-toi.org/spec/pubsub_admin:0
https://salut-a-toi/protocol/schema:0
jabber:iq:version
urn:xmpp:mam:2
urn:xmpp:order-by:0
Identities
┌───────┬─────────┬───────────────────────────┐
│catego<span class="w"> </span>│<span class="w"> </span><span class="nb">type</span><span class="w"> </span>│<span class="w"> </span>name<span class="w"> </span>│
├┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤
│pubsub<span class="w"> </span>│<span class="w"> </span>service<span class="w"> </span>│<span class="w"> </span>Salut<span class="w"> </span>à<span class="w"> </span>Toi<span class="w"> </span>pubsub<span class="w"> </span>service│
└───────┴─────────┴───────────────────────────┘
Items
┌─────────────────┬───────────────────┬─┐
│entity<span class="w"> </span>│<span class="w"> </span>node<span class="w"> </span>│<span class="w"> </span>│
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┼┄┤
│pubsub.agayon.be<span class="w"> </span>│<span class="w"> </span>be.agayon.errol:0<span class="w"> </span>│<span class="w"> </span>│
│pubsub.agayon.be<span class="w"> </span>│<span class="w"> </span>tests<span class="w"> </span>│<span class="w"> </span>│
│pubsub.agayon.be<span class="w"> </span>│<span class="w"> </span>Agayon<span class="w"> </span>│<span class="w"> </span>│
└─────────────────┴───────────────────┴─┘
</code></pre></div>
<p>The following commands are used to create a node, subscribe to it and edit an item (see <a href="https://blog.agayon.be/sat_jp.html">the previous article</a>).</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>pubsub<span class="w"> </span>node<span class="w"> </span>create<span class="w"> </span>-s<span class="w"> </span>pubsub.agayon.be<span class="w"> </span>-n<span class="w"> </span>node_name
$<span class="w"> </span>jp<span class="w"> </span>pubsub<span class="w"> </span>subscribe<span class="w"> </span>-s<span class="w"> </span>pubsub.agayon.be<span class="w"> </span>-n<span class="w"> </span>node_name
$<span class="w"> </span>jp<span class="w"> </span>pubsub<span class="w"> </span>edit<span class="w"> </span>-s<span class="w"> </span>pubsub.agayon.be<span class="w"> </span>-n<span class="w"> </span>node_name
</code></pre></div>
<p>The default text editor is then opened. It is possible to directly edit a XML file. This command is useful for debugging purpose.</p>
<h1 id="agayon">About Agayon XMPP service</h1>
<p>All the tests described in this blog are realized on the Agayon.be XMPP service. It is not opened for registration but having this field of experimentation is great to learn, practice
and question the potential uses of XMPP. I use it with several accounts, depending on my use:</p>
<ul>
<li>obtain statistics about the server with <a href="https://gitlab.com/r1dScripts/chatty_server">chatty_server</a>, a <a href="https://blog.agayon.be/chatty_server.html">small python bot</a>.</li>
<li>write memos to save links in a dummy account,</li>
<li>automatic file transfer, </li>
<li>daily logs sender with <a href="https://sourceforge.net/projects/logwatch/files/">logwatch</a></li>
<li>...</li>
</ul>
<p><a href="https://xmpp.org/extensions/xep-0375.html">Most moderns XEPs</a> are enabled in order to provide an up-to-date experience: <a href="https://xmpp.org/extensions/xep-0163.html">PEP</a>, <a href="https://xmpp.org/extensions/xep-0280.html">Carbon</a>, <a href="https://xmpp.org/extensions/xep-0198.html">Stream Management</a>, <a href="https://xmpp.org/extensions/xep-0060.html">persistent pubsub</a>, <a href="https://xmpp.org/extensions/xep-0313.html">MAM</a>, <a href="https://xmpp.org/extensions/xep-0368.html">SRV records over TLS</a> (useful to pass blocking WiFi accesses), etc.</p>
<h1 id="future">Future of SàT</h1>
<p>In a near future, the SàT project will make great announcements about new uses of pubsub. I hope this article will make you want to install sat_pubsub and experiment with nodes, data and notifications.</p>
<p>Stay tuned !</p>
<h1 id="links">Links</h1>
<ul>
<li><a href="https://repos.goffi.org/sat_pubsub/">sat_pubsub repository</a></li>
<li><a href="https://repos.goffi.org/sat_pubsub/file/tip/INSTALL">Install notes</a> (maybe outdated)</li>
<li><a href="https://blog.agayon.be/sat_jp.html">The previous article about JP</a></li>
</ul>JP, a powerful command line interface for Salut-à-Toi2017-10-17T20:00:00+02:002019-05-30T16:00:00+02:00Arnaudtag:blog.agayon.be,2017-10-17:/sat_jp.html
<p><a href="https://salut-a-toi.org/">Salut à toi</a> is a unique XMPP client. As its official description says, it's a "multipurpose, multi front-end, free (libre) and decentralized communication tool". It has been actively developed by Jérôme Poisson (Goffi) and Adrien Cossa (Souliane) since 2008. Today, I will focus on the use of "<a href="https://wiki.goffi.org/wiki/Jp/en">JP</a>", a command-line interface. It can be used to send or receive files directly from a shell, pipe commands to or from XMPP, use XMPP easily in a script and of course play with pubsub nodes.</p>
<p><a href="https://salut-a-toi.org/">Salut à toi</a> is a unique XMPP client. As its official description says, it's a "multipurpose, multi front-end, free (libre) and decentralized communication tool". It has been actively developed by Jérôme Poisson (Goffi) and Adrien Cossa (Souliane) since 2008. Today, I will focus on the use of "<a href="https://wiki.goffi.org/wiki/Jp/en">JP</a>", a command-line interface. It can be used to send or receive files directly from a shell, pipe commands to or from XMPP, use XMPP easily in a script and of course play with pubsub nodes.</p>
<p>The following article describes uses of JP. Several of them are availabled in the <a href="https://repos.goffi.org/sat/">trunk version of Salut-à-Toi</a>.</p>
<h1>Introduction</h1>
<p>JP can be used to launch complexes commands in script, for debugging purpose or to explore XMPP services.
JP is the command line interface and it connect to the daemon Salut-à-Toi (SàT). You can share the session between the front-ends:</p>
<ul>
<li><a href="https://wiki.goffi.org/wiki/Jp/en">JP</a> of course.</li>
<li><a href="https://wiki.goffi.org/wiki/Primitivus/en">Primitivus</a> as a console front-end.</li>
<li><a href="https://wiki.goffi.org/wiki/Libervia/en">Livervia</a>, a web based front-end.</li>
<li><a href="https://salut-a-toi.org/static/images/screenshots/sententia/sententia.png">Sententia</a> an Emacs front-end (WIP).</li>
<li><a href="https://www.goffi.org/blog/goffi/9ff9bb64-1e1f-4334-80e5-a86f0b6b795b?tag=jabber-xmpp">Cagou</a> an original mobile XMPP client based on SàT (WIP).</li>
</ul>
<p>If you want to send a file easily, discover which services are available on a server, send messages in your scripts, manage your xmpp account, control video player, edit your blog post with your favorite editor, pipe streams, manage your pubsub nodes etc, JP is for you!</p>
<h1>Usage</h1>
<p>JP can be used as a command line tools or in a small shell environment.</p>
<p>First, we need to configure and launch the daemon sat.</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>sat
</code></pre></div>
<p>Your default profile will be connected. If you have no profile, JP can be used to create one. </p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>profile<span class="w"> </span>create<span class="w"> </span>-j<span class="w"> </span>my_jid@example.org<span class="w"> </span>-x<span class="w"> </span>mypassword<span class="w"> </span>profile_name
$<span class="w"> </span>jp<span class="w"> </span>profile<span class="w"> </span>connect<span class="w"> </span>-p<span class="w"> </span>profile_name
</code></pre></div>
<p>Your password is saved in the sat settings.
You can connect automatically with the option <code>-c</code>. It should be noted that SàT defines a default profile. It can be bypassed with the option <code>-p</code>. [ref]It is possible to use <code>jp profile modify</code> to set the default profile.[/ref]</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"test message"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>jp<span class="w"> </span>message<span class="w"> </span>send<span class="w"> </span>recipient@example.org<span class="w"> </span>-p<span class="w"> </span>profile_name<span class="w"> </span>-c
</code></pre></div>
<p>You can obtain help about a command with the option <code>-h</code>.</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>pubsub<span class="w"> </span>-h
usage:<span class="w"> </span>jp<span class="w"> </span>pubsub<span class="w"> </span><span class="o">[</span>-h<span class="o">]</span>
<span class="w"> </span><span class="o">{</span>get,delete,edit,subscribe,unsubscribe,subscriptions,node,affiliations,search,hook,uri<span class="o">}</span>
<span class="w"> </span>...
positional<span class="w"> </span>arguments:
<span class="w"> </span><span class="o">{</span>get,delete,edit,subscribe,unsubscribe,subscriptions,node,affiliations,search,hook,uri<span class="o">}</span>
<span class="w"> </span>get<span class="w"> </span>get<span class="w"> </span>pubsub<span class="w"> </span>item<span class="o">(</span>s<span class="o">)</span>
<span class="w"> </span>delete<span class="w"> </span>delete<span class="w"> </span>an<span class="w"> </span>item
<span class="w"> </span>edit<span class="w"> </span>edit<span class="w"> </span>an<span class="w"> </span>existing<span class="w"> </span>or<span class="w"> </span>new<span class="w"> </span>pubsub<span class="w"> </span>item
<span class="w"> </span>subscribe<span class="w"> </span>subscribe<span class="w"> </span>to<span class="w"> </span>a<span class="w"> </span>node
<span class="w"> </span>unsubscribe<span class="w"> </span>unsubscribe<span class="w"> </span>from<span class="w"> </span>a<span class="w"> </span>node
<span class="w"> </span>subscriptions<span class="w"> </span>retrieve<span class="w"> </span>all<span class="w"> </span>subscriptions<span class="w"> </span>on<span class="w"> </span>a<span class="w"> </span>service
<span class="w"> </span>node<span class="w"> </span>node<span class="w"> </span>handling
<span class="w"> </span>affiliations<span class="w"> </span>retrieve<span class="w"> </span>all<span class="w"> </span>affiliations<span class="w"> </span>on<span class="w"> </span>a<span class="w"> </span>service
<span class="w"> </span>search<span class="w"> </span>search<span class="w"> </span>items<span class="w"> </span>corresponding<span class="w"> </span>to<span class="w"> </span>filters
<span class="w"> </span>hook<span class="w"> </span>trigger<span class="w"> </span>action<span class="w"> </span>on<span class="w"> </span>Pubsub<span class="w"> </span>notifications
<span class="w"> </span>uri<span class="w"> </span>build<span class="w"> </span>URI
optional<span class="w"> </span>arguments:
<span class="w"> </span>-h,<span class="w"> </span>--help<span class="w"> </span>show<span class="w"> </span>this<span class="w"> </span><span class="nb">help</span><span class="w"> </span>message<span class="w"> </span>and<span class="w"> </span><span class="nb">exit</span>
</code></pre></div>
<p>JP is a Swiss army knife. Let's discover its possibilities through a few examples.</p>
<h1>Examples</h1>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>-h
usage:<span class="w"> </span>jp<span class="w"> </span><span class="o">[</span>-h<span class="o">]</span><span class="w"> </span><span class="o">[</span>--version<span class="o">]</span>
<span class="w"> </span><span class="o">{</span>file,input,uri,message,event,info,account,param,debug,ad-hoc,ticket,invitation,profile,shell,avatar,pipe,pubsub,bookmarks,roster,identity,blog<span class="o">}</span>
<span class="w"> </span>...
This<span class="w"> </span>software<span class="w"> </span>is<span class="w"> </span>a<span class="w"> </span><span class="nb">command</span><span class="w"> </span>line<span class="w"> </span>tool<span class="w"> </span><span class="k">for</span><span class="w"> </span>XMPP.
Get<span class="w"> </span>the<span class="w"> </span>latest<span class="w"> </span>version<span class="w"> </span>at<span class="w"> </span>http://salut-a-toi.org
optional<span class="w"> </span>arguments:
<span class="w"> </span>-h,<span class="w"> </span>--help<span class="w"> </span>show<span class="w"> </span>this<span class="w"> </span><span class="nb">help</span><span class="w"> </span>message<span class="w"> </span>and<span class="w"> </span><span class="nb">exit</span>
<span class="w"> </span>--version<span class="w"> </span>show<span class="w"> </span>programʼs<span class="w"> </span>version<span class="w"> </span>number<span class="w"> </span>and<span class="w"> </span><span class="nb">exit</span>
Available<span class="w"> </span>commands:
<span class="w"> </span><span class="o">{</span>file,input,uri,message,event,info,account,param,debug,ad-hoc,ticket,invitation,profile,shell,avatar,pipe,pubsub,bookmarks,roster,identity,blog<span class="o">}</span>
<span class="w"> </span>file<span class="w"> </span>File<span class="w"> </span>sending/receiving
<span class="w"> </span>input<span class="w"> </span>launch<span class="w"> </span><span class="nb">command</span><span class="w"> </span>with<span class="w"> </span>external<span class="w"> </span>input
<span class="w"> </span>uri<span class="w"> </span>XMPP<span class="w"> </span>URI<span class="w"> </span>parsing/generation
<span class="w"> </span>message<span class="w"> </span>messages<span class="w"> </span>handling
<span class="w"> </span>event<span class="w"> </span>event<span class="w"> </span>management
<span class="w"> </span>info<span class="w"> </span>Get<span class="w"> </span>various<span class="w"> </span>pieces<span class="w"> </span>of<span class="w"> </span>information<span class="w"> </span>on<span class="w"> </span>entities
<span class="w"> </span>account<span class="w"> </span>XMPP<span class="w"> </span>account<span class="w"> </span>management
<span class="w"> </span>param<span class="w"> </span>Save/load<span class="w"> </span>parameters<span class="w"> </span>template
<span class="w"> </span>debug<span class="w"> </span>debugging<span class="w"> </span>tools
<span class="w"> </span>ad-hoc<span class="w"> </span>Ad-hoc<span class="w"> </span>commands
<span class="w"> </span>ticket<span class="w"> </span>tickets<span class="w"> </span>handling
<span class="w"> </span>invitation<span class="w"> </span>invitation<span class="w"> </span>of<span class="w"> </span>user<span class="o">(</span>s<span class="o">)</span><span class="w"> </span>without<span class="w"> </span>XMPP<span class="w"> </span>account
<span class="w"> </span>profile<span class="w"> </span>profile<span class="w"> </span>commands
<span class="w"> </span>shell<span class="w"> </span>launch<span class="w"> </span>jp<span class="w"> </span><span class="k">in</span><span class="w"> </span>shell<span class="w"> </span><span class="o">(</span>REPL<span class="o">)</span><span class="w"> </span>mode
<span class="w"> </span>avatar<span class="w"> </span>avatar<span class="w"> </span>uploading/retrieving
<span class="w"> </span>pipe<span class="w"> </span>stream<span class="w"> </span>piping<span class="w"> </span>through<span class="w"> </span>XMPP
<span class="w"> </span>pubsub<span class="w"> </span>PubSub<span class="w"> </span>nodes/items<span class="w"> </span>management
<span class="w"> </span>bookmarks<span class="w"> </span>manage<span class="w"> </span>bookmarks
<span class="w"> </span>roster<span class="w"> </span>Manage<span class="w"> </span>an<span class="w"> </span>entityʼs<span class="w"> </span>roster
<span class="w"> </span>identity<span class="w"> </span>identity<span class="w"> </span>management
<span class="w"> </span>blog<span class="w"> </span>blog/microblog<span class="w"> </span>management
</code></pre></div>
<h2>Send a message</h2>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Hello World"</span><span class="w"> </span>><span class="w"> </span>filetest
$<span class="w"> </span>jp<span class="w"> </span>message<span class="w"> </span>send<span class="w"> </span>recipient@example.org<span class="w"> </span><<span class="w"> </span>filetest
</code></pre></div>
<p>or</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"test jp"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>jp<span class="w"> </span>message<span class="w"> </span>send<span class="w"> </span>recipient@example.org
</code></pre></div>
<h2>Send files</h2>
<p>The following command allows to send the file <code>file.txt</code> to recipient@example.org.</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>file<span class="w"> </span>send<span class="w"> </span>file.txt<span class="w"> </span>recipient@example.org
</code></pre></div>
<h2>Receive files</h2>
<p>The following command allows to receive a file in the /tmp directory.</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>file<span class="w"> </span>receive<span class="w"> </span>-p<span class="w"> </span>agayon<span class="w"> </span>--path<span class="w"> </span>/tmp
</code></pre></div>
<h2>Get information about a server</h2>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>info<span class="w"> </span>version<span class="w"> </span>agayon.be
Client<span class="w"> </span>name:<span class="w"> </span>Prosody
Client<span class="w"> </span>version:<span class="w"> </span><span class="m">0</span>.10.0
Operating<span class="w"> </span>System:<span class="w"> </span>Linux
</code></pre></div>
<h2>Get disco information</h2>
<h3>Query a Server</h3>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>info<span class="w"> </span>disco<span class="w"> </span>agayon.be
Features
http://jabber.org/protocol/commands
http://jabber.org/protocol/disco#info
http://jabber.org/protocol/disco#items
http://jabber.org/protocol/pubsub#auto-create
http://jabber.org/protocol/pubsub#config-node
http://jabber.org/protocol/pubsub#create-nodes
http://jabber.org/protocol/pubsub#delete-any
http://jabber.org/protocol/pubsub#delete-nodes
http://jabber.org/protocol/pubsub#groupblog
http://jabber.org/protocol/pubsub#instant-nodes
http://jabber.org/protocol/pubsub#item-ids
http://jabber.org/protocol/pubsub#meta-data
http://jabber.org/protocol/pubsub#outcast-affiliation
http://jabber.org/protocol/pubsub#persistent-items
http://jabber.org/protocol/pubsub#publish
http://jabber.org/protocol/pubsub#publish-options
http://jabber.org/protocol/pubsub#publisher-affiliation
http://jabber.org/protocol/pubsub#purge-nodes
http://jabber.org/protocol/pubsub#retract-items
http://jabber.org/protocol/pubsub#retrieve-affiliations
http://jabber.org/protocol/pubsub#retrieve-default
http://jabber.org/protocol/pubsub#retrieve-items
http://jabber.org/protocol/pubsub#retrieve-subscriptions
http://jabber.org/protocol/pubsub#subscribe
https://salut-a-toi.org/spec/pubsub_admin:0
https://salut-a-toi/protocol/schema:0
jabber:iq:auth
jabber:iq:last
jabber:iq:private
jabber:iq:roster
jabber:iq:time
jabber:iq:version
msgoffline
urn:xmpp:blocking
urn:xmpp:carbons:1
urn:xmpp:carbons:2
urn:xmpp:http:upload
urn:xmpp:http:upload:0
urn:xmpp:mam:0
urn:xmpp:order-by:0
urn:xmpp:ping
urn:xmpp:time
vcard-temp
Identities
┌───────┬──────┬─────────────────┐
│catego<span class="w"> </span>│<span class="w"> </span><span class="nb">type</span><span class="w"> </span>│<span class="w"> </span>name<span class="w"> </span>│
├┄┄┄┄┄┄┄┼┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤
│store<span class="w"> </span>│<span class="w"> </span>file<span class="w"> </span>│<span class="w"> </span>HTTP<span class="w"> </span>File<span class="w"> </span>Upload│
│pubsub<span class="w"> </span>│<span class="w"> </span>pep<span class="w"> </span>│<span class="w"> </span>Prosody<span class="w"> </span>│
│server<span class="w"> </span>│<span class="w"> </span>im<span class="w"> </span>│<span class="w"> </span>Prosody<span class="w"> </span>│
└───────┴──────┴─────────────────┘
Extensions
urn:xmpp:http:upload
<span class="w"> </span>type:<span class="w"> </span>text-single
<span class="w"> </span>var:<span class="w"> </span>max-file-size
<span class="w"> </span>value:<span class="w"> </span><span class="m">1048576</span>
urn:xmpp:http:upload:0
<span class="w"> </span>type:<span class="w"> </span>text-single
<span class="w"> </span>var:<span class="w"> </span>max-file-size
<span class="w"> </span>value:<span class="w"> </span><span class="m">1048576</span>
Items
┌──────────────────────┬──┬────────────────────┐
│entity<span class="w"> </span>│<span class="w"> </span>│<span class="w"> </span>name<span class="w"> </span>│
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┼┄┄┼┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤
│test-pubsub.agayon.be<span class="w"> </span>│<span class="w"> </span>│<span class="w"> </span>│
│upload.agayon.be<span class="w"> </span>│<span class="w"> </span>│<span class="w"> </span>│
│auth.agayon.be<span class="w"> </span>│<span class="w"> </span>│<span class="w"> </span>│
│proxy.agayon.be<span class="w"> </span>│<span class="w"> </span>│<span class="w"> </span>│
│pubsub.agayon.be<span class="w"> </span>│<span class="w"> </span>│<span class="w"> </span>│
│chat.agayon.be<span class="w"> </span>│<span class="w"> </span>│<span class="w"> </span>Agayon.be<span class="w"> </span>chatrooms│
└──────────────────────┴──┴────────────────────┘
</code></pre></div>
<h3>Query an account</h3>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>info<span class="w"> </span>disco<span class="w"> </span>info@agayon.be
Items
┌───────────────┬───────────────────────────────────────────────────┬─┐
│entity<span class="w"> </span>│<span class="w"> </span>node<span class="w"> </span>│<span class="w"> </span>│
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┼┄┤
│info@agayon.be<span class="w"> </span>│<span class="w"> </span>eu.siacs.conversations.axolotl.bundles:1948395845<span class="w"> </span>│<span class="w"> </span>│
│info@agayon.be<span class="w"> </span>│<span class="w"> </span>http://jabber.org/protocol/activity<span class="w"> </span>│<span class="w"> </span>│
│info@agayon.be<span class="w"> </span>│<span class="w"> </span>http://jabber.org/protocol/mood<span class="w"> </span>│<span class="w"> </span>│
│info@agayon.be<span class="w"> </span>│<span class="w"> </span>eu.siacs.conversations.axolotl.devicelist<span class="w"> </span>│<span class="w"> </span>│
│info@agayon.be<span class="w"> </span>│<span class="w"> </span>storage:bookmarks<span class="w"> </span>│<span class="w"> </span>│
└───────────────┴───────────────────────────────────────────────────┴─┘
</code></pre></div>
<h2>Manage pubsub nodes</h2>
<p>The following examples show how to manage pubsub nodes on the service <a href="http://pubsub.agayon.be">pubsub.agayon.be</a>.</p>
<h3>Create a node</h3>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>pubsub<span class="w"> </span>node<span class="w"> </span>create<span class="w"> </span>-s<span class="w"> </span>pubsub.agayon.be<span class="w"> </span>-n<span class="w"> </span>node_name
</code></pre></div>
<h3>Subscribe to a node</h3>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>pubsub<span class="w"> </span>subscribe<span class="w"> </span>-s<span class="w"> </span>pubsub.agayon.be<span class="w"> </span>-n<span class="w"> </span>node_name
</code></pre></div>
<h3>Edit</h3>
<p>The edit command allows to edit an item under a node.</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>pubsub<span class="w"> </span>edit<span class="w"> </span>-s<span class="w"> </span>pubsub.agayon.be<span class="w"> </span>-n<span class="w"> </span>node_name
</code></pre></div>
<p>The default text editor is opened. It is possible to directly edit a XML file. This command is useful for debugging purpose.</p>
<p>If you want to edit a post without having to edit xml directly, use <a href="#blog_edit">jp blog edit</a>. </p>
<p>As an example, you can try to edit the following xml file.</p>
<div class="highlight"><pre><span></span><code><span class="nt"><entry</span><span class="w"> </span><span class="na">xmlns=</span><span class="s">"http://www.w3.org/2005/Atom"</span><span class="nt">></span>
<span class="w"> </span><span class="nt"><author></span>
<span class="w"> </span><span class="nt"><name></span>author@example.com<span class="nt"></name></span>
<span class="w"> </span><span class="nt"></author></span>
<span class="w"> </span><span class="nt"><generator></span>JP<span class="w"> </span>(SàT)<span class="nt"></generator></span>
<span class="w"> </span><span class="nt"><title></span>I<span class="w"> </span>am<span class="w"> </span>a<span class="w"> </span>pubsub<span class="w"> </span>post<span class="w"> </span>!<span class="nt"></title></span>
<span class="w"> </span><span class="nt"><content></span>This<span class="w"> </span>is<span class="w"> </span>the<span class="w"> </span>content<span class="w"> </span>of<span class="w"> </span>this<span class="w"> </span>great<span class="w"> </span>post.<span class="nt"></content></span>
<span class="nt"></entry></span>
</code></pre></div>
<p>Once the file is saved, a notification appears in Gajim. For now, the name of the post is a hash.</p>
<p><img alt="pubsub post on Gajim" src="https://blog.agayon.be/images/pubsub_1.png" style="width: 272px; height: auto; max-width: 100%;"/></p>
<p><img alt="pubsub post on Gajim" src="https://blog.agayon.be/images/pubsub_2.png" style="width: 870px; height: auto; max-width: 100%;"/></p>
<h2>Manage your XMPP Blog</h2>
<p>It is possible to manage a post with XMPP. It is based on <a href="https://xmpp.org/extensions/xep-0163.html">PEP</a>, a simplified version of pubsub. If your server support PEP, JP can help you to manage this blog easily.</p>
<h3 id="blog_edit">Publish a post</h3>
<p>First, you need to define your preferred syntax. In this example, I select markdown. This option can also be set in any other frontend (e.g. Primitivus). Whereafter you can edit a new post with the syntax jp blog edit.</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>param<span class="w"> </span><span class="nb">set</span><span class="w"> </span>Composition<span class="w"> </span>Syntax<span class="w"> </span>markdown<span class="w"> </span>-p<span class="w"> </span>agayon
$<span class="w"> </span>jp<span class="w"> </span>blog<span class="w"> </span>edit
</code></pre></div>
<p>Your favorite editor open and you can edit your blog post with markdown syntax. When you save and close it, another file open. You can edit your settings:</p>
<div class="highlight"><pre><span></span><code><span class="o">{</span>
<span class="w"> </span><span class="s2">"allow_comments"</span>:<span class="w"> </span>true,
<span class="o">}</span>
</code></pre></div>
<p>You can verify the accessibility of your post with the following command:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>blog<span class="w"> </span>get<span class="w"> </span>
content:<span class="w"> </span>
Great<span class="w"> </span><span class="nb">test</span><span class="w"> </span>!
Make<span class="w"> </span>testing<span class="w"> </span>great<span class="w"> </span>again<span class="w"> </span>!
Yuuuuuuge<span class="w"> </span>publication.
</code></pre></div>
<p>It is also possible to modify your last blog post simply with <code>jp blog edit --last-item</code>.</p>
<p>Your blog post are also visible on other clients like <a href="https://movim.eu/">Movim</a> (see below) and interfaces like <a href="https://wiki.goffi.org/wiki/Libervia/en">Livervia</a>.</p>
<p><img alt="Post on movim" src="https://blog.agayon.be/images/movim_post.png.webp" style="width: 1158px; height: auto; max-width: 100%;"/></p>
<h2>Use jp shell:</h2>
<p>In order to ease debugging of services, JP comes with a shell interface.
You only need to launch <code>jp shell</code>. You can obtain help by typing <code>?</code>.</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>shell
cmd<span class="w"> </span>pubsub
pubsub><span class="w"> </span>?
Shell<span class="w"> </span>commands:
Documented<span class="w"> </span>commands<span class="w"> </span><span class="o">(</span><span class="nb">type</span><span class="w"> </span><span class="nb">help</span><span class="w"> </span><topic><span class="o">)</span>:
<span class="o">========================================</span>
cmd<span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="nb">help</span><span class="w"> </span>shell<span class="w"> </span>use_clear<span class="w"> </span>version
debug<span class="w"> </span><span class="nb">exit</span><span class="w"> </span>quit<span class="w"> </span>use<span class="w"> </span>verbose<span class="w"> </span>whoami<span class="w"> </span>
Action<span class="w"> </span>commands:
positional<span class="w"> </span>arguments:
<span class="w"> </span><span class="o">{</span>get,delete,edit,subscribe,unsubscribe,subscriptions,node,affiliations,search,hook,uri<span class="o">}</span>
<span class="w"> </span>get<span class="w"> </span>get<span class="w"> </span>pubsub<span class="w"> </span>item<span class="o">(</span>s<span class="o">)</span>
<span class="w"> </span>delete<span class="w"> </span>delete<span class="w"> </span>an<span class="w"> </span>item
<span class="w"> </span>edit<span class="w"> </span>edit<span class="w"> </span>an<span class="w"> </span>existing<span class="w"> </span>or<span class="w"> </span>new<span class="w"> </span>pubsub<span class="w"> </span>item
<span class="w"> </span>subscribe<span class="w"> </span>subscribe<span class="w"> </span>to<span class="w"> </span>a<span class="w"> </span>node
<span class="w"> </span>unsubscribe<span class="w"> </span>unsubscribe<span class="w"> </span>from<span class="w"> </span>a<span class="w"> </span>node
<span class="w"> </span>subscriptions<span class="w"> </span>retrieve<span class="w"> </span>all<span class="w"> </span>subscriptions<span class="w"> </span>on<span class="w"> </span>a<span class="w"> </span>service
<span class="w"> </span>node<span class="w"> </span>node<span class="w"> </span>handling
<span class="w"> </span>affiliations<span class="w"> </span>retrieve<span class="w"> </span>all<span class="w"> </span>affiliations<span class="w"> </span>on<span class="w"> </span>a<span class="w"> </span>service
<span class="w"> </span>search<span class="w"> </span>search<span class="w"> </span>items<span class="w"> </span>corresponding<span class="w"> </span>to<span class="w"> </span>filters
<span class="w"> </span>hook<span class="w"> </span>trigger<span class="w"> </span>action<span class="w"> </span>on<span class="w"> </span>Pubsub<span class="w"> </span>notifications
<span class="w"> </span>uri<span class="w"> </span>build<span class="w"> </span>URI
</code></pre></div>
<h3>Select a command</h3>
<div class="highlight"><pre><span></span><code>><span class="w"> </span>cmd<span class="w"> </span>pubsub
pubsub><span class="w"> </span>use<span class="w"> </span>node<span class="w"> </span>urn:xmpp:microblog:0
</code></pre></div>
<h3>Navigate into commands</h3>
<div class="highlight"><pre><span></span><code>><span class="w"> </span>cmd<span class="w"> </span>bookmarks/list
bookmarks/list><span class="w"> </span>-c
...<span class="w"> </span>CMD<span class="w"> </span>result
bookmarks/list><span class="w"> </span>cmd<span class="w"> </span>..
bookmarks><span class="w"> </span>cmd
>
</code></pre></div>
<h3>Example: List bookmarks</h3>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jp<span class="w"> </span>shell
><span class="w"> </span>cmd<span class="w"> </span>bookmarks
bookmarks><span class="w"> </span>cmd<span class="w"> </span>list
bookmarks/list><span class="w"> </span>?
Shell<span class="w"> </span>commands:
Documented<span class="w"> </span>commands<span class="w"> </span><span class="o">(</span><span class="nb">type</span><span class="w"> </span><span class="nb">help</span><span class="w"> </span><topic><span class="o">)</span>:
<span class="o">========================================</span>
cmd<span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="nb">help</span><span class="w"> </span>shell<span class="w"> </span>use_clear<span class="w"> </span>version
debug<span class="w"> </span><span class="nb">exit</span><span class="w"> </span>quit<span class="w"> </span>use<span class="w"> </span>verbose<span class="w"> </span>whoami<span class="w"> </span>
Action<span class="w"> </span>commands:
optional<span class="w"> </span>arguments:
<span class="w"> </span>-h,<span class="w"> </span>--help<span class="w"> </span>show<span class="w"> </span>this<span class="w"> </span><span class="nb">help</span><span class="w"> </span>message<span class="w"> </span>and<span class="w"> </span><span class="nb">exit</span>
<span class="w"> </span>-p<span class="w"> </span>PROFILE,<span class="w"> </span>--profile<span class="w"> </span>PROFILE
<span class="w"> </span>Use<span class="w"> </span>PROFILE<span class="w"> </span>profile<span class="w"> </span>key<span class="w"> </span><span class="o">(</span>default:<span class="w"> </span>@DEFAULT@<span class="o">)</span>
<span class="w"> </span>--pwd<span class="w"> </span>PASSWORD<span class="w"> </span>Password<span class="w"> </span>used<span class="w"> </span>to<span class="w"> </span>connect<span class="w"> </span>profile,<span class="w"> </span><span class="k">if</span><span class="w"> </span>necessary
<span class="w"> </span>-c,<span class="w"> </span>--connect<span class="w"> </span>Connect<span class="w"> </span>the<span class="w"> </span>profile<span class="w"> </span>before<span class="w"> </span>doing<span class="w"> </span>anything<span class="w"> </span><span class="k">else</span>
<span class="w"> </span>-l<span class="w"> </span><span class="o">{</span>all,local,private,pubsub<span class="o">}</span>,<span class="w"> </span>--location<span class="w"> </span><span class="o">{</span>all,local,private,pubsub<span class="o">}</span>
<span class="w"> </span>storage<span class="w"> </span>location<span class="w"> </span><span class="o">(</span>default:<span class="w"> </span>all<span class="o">)</span>
<span class="w"> </span>-t<span class="w"> </span><span class="o">{</span>muc,url<span class="o">}</span>,<span class="w"> </span>--type<span class="w"> </span><span class="o">{</span>muc,url<span class="o">}</span>
<span class="w"> </span>bookmarks<span class="w"> </span><span class="nb">type</span><span class="w"> </span><span class="o">(</span>default:<span class="w"> </span>muc<span class="o">)</span>
bookmarks/list><span class="w"> </span>-t<span class="w"> </span>muc
private:
<span class="w"> </span>Movim<span class="w"> </span><span class="o">[</span>movim@conference.movim.eu<span class="o">]</span><span class="w"> </span><span class="o">(</span>*<span class="o">)</span>
<span class="w"> </span>Archlinux<span class="w"> </span>-<span class="w"> </span>blah<span class="w"> </span>blah<span class="w"> </span><span class="o">[</span>archlinux-fr@chat.jabberfr.org<span class="o">]</span>
<span class="w"> </span>bot<span class="w"> </span><span class="o">[</span>bot@chat.agayon.be<span class="o">]</span><span class="w"> </span><span class="o">(</span>*<span class="o">)</span>
</code></pre></div>
<h3>Example: get disco information</h3>
<div class="highlight"><pre><span></span><code>><span class="w"> </span>cmd<span class="w"> </span>info
info><span class="w"> </span>use<span class="w"> </span>jid<span class="w"> </span>pubsub.agayon.be<span class="w"> </span>
info><span class="w"> </span>disco
Features
http://jabber.org/protocol/disco#info
http://jabber.org/protocol/disco#items
http://jabber.org/protocol/pubsub
http://jabber.org/protocol/pubsub#create-nodes
http://jabber.org/protocol/pubsub#delete-items
http://jabber.org/protocol/pubsub#delete-nodes
http://jabber.org/protocol/pubsub#instant-nodes
http://jabber.org/protocol/pubsub#item-ids
http://jabber.org/protocol/pubsub#publish
http://jabber.org/protocol/pubsub#publisher-affiliation
http://jabber.org/protocol/pubsub#purge-nodes
http://jabber.org/protocol/pubsub#retract-items
http://jabber.org/protocol/pubsub#retrieve-items
http://jabber.org/protocol/pubsub#retrieve-subscriptions
http://jabber.org/protocol/pubsub#subscribe
Identities
┌───────┬─────────┬───────────────────────┐
│catego<span class="w"> </span>│<span class="w"> </span><span class="nb">type</span><span class="w"> </span>│<span class="w"> </span>name<span class="w"> </span>│
├┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤
│pubsub<span class="w"> </span>│<span class="w"> </span>service<span class="w"> </span>│<span class="w"> </span>Prosody<span class="w"> </span>PubSub<span class="w"> </span>Service│
└───────┴─────────┴───────────────────────┘
</code></pre></div>
<h1>More</h1>
<ul>
<li><a href="https://www.goffi.org/blog/goffi/S%C3%A0T_DOTCLEAR_IMPORT_BLOG_default_goffi_77%3A2013%2F02%2F22%2FExport-command-to-a-contact-%28with-video%29?tag=jabber-xmpp-en">Export command (input/output) to a contact</a></li>
<li><a href="https://www.goffi.org/blog/goffi/S%C3%A0T_DOTCLEAR_IMPORT_BLOG_default_goffi_83%3A2014%2F02%2F18%2FA-universal-remote-for-your-softwares?tag=jabber-xmpp-en">Create a universal remote for VLC (media player)</a></li>
</ul>
<h1>Some alternatives</h1>
<h4>SleekXMPP</h4>
<p>SleekXMPP is a xmpp python library. It provide two examples of pubsub clients. The <a href="https://github.com/fritzy/SleekXMPP/blob/develop/examples/pubsub_client.py">first, <code>pubsub_client.py</code></a> can manage nodes and the <a href="https://github.com/fritzy/SleekXMPP/blob/develop/examples/pubsub_events.py">second one, pubsub_events.py,</a> can manage events.</p>
<div class="highlight"><pre><span></span><code>./pubsub_client.py<span class="w"> </span>-j<span class="w"> </span>jid<span class="w"> </span>--password<span class="o">=</span>passwd<span class="w"> </span>pubsub.agayon.be<span class="w"> </span>create<span class="w"> </span>node_name
</code></pre></div>
<h3>Gajim</h3>
<p><a href="https://gajim.org/">Gajim</a> is a great desktop client. It can be used to post on pubsub nodes too.</p>
<p><img alt="pubsub post on Gajim" src="https://blog.agayon.be/images/pubsub_3.png.webp" style="width: 450px; height: auto; max-width: 100%;"/></p>
<h3>Movim</h3>
<p><a href="https://movim.eu/">Movim</a> is a social network platform based on XMPP. It massively use pubsub to allow users to interact.</p>
<h1>Conclusions</h1>
<p>Salut-à-Toi is a great XMPP client. JP, its command-line interface, is a powerful tool. It can be useful to debug services, pubsub nodes and play with 'social' capacities of XMPP.
It is actively developed and new features are coming. We will be soon able to make todolist or fill a bug ticket on a XMPP based system.</p>
<h1>Links</h1>
<ul>
<li><a href="https://salut-a-toi.org/">Salut à toi</a></li>
<li>SàT room: <a href="xmpp:sat@chat.jabberfr.org?join">sat@chat.jabberfr.org</a></li>
<li><a href="https://wiki.goffi.org/wiki/Jp/en">JP</a></li>
<li><a href="https://repos.goffi.org/sat/">SàT repository</a></li>
<li><a href="https://aur.archlinux.org/packages/sat-xmpp/">Archlinux package</a></li>
<li><a href="https://gajim.org/">Gajim</a></li>
<li><a href="https://movim.eu/">Movim</a></li>
</ul>Authentication without password using XMPP on a Django website2017-01-11T19:00:00+01:002017-02-09T19:00:00+01:00Arnaudtag:blog.agayon.be,2017-01-11:/xmpp_auth_django.html<p>This article describes the authentication with XMPP on a Django powered website. When you authenticate on a website, the domain validate your identity before letting you access confidential information. They are several ways perform this validation and the use of passwords is the most popular. Another method is the use of a token generator i.e. a small device that generate a secret passphrase that you copy on a website. Today I will present you another authentication method without password using XMPP.</p><p>This article describes the authentication with XMPP on a Django powered website.</p>
<h1>Authentication without password</h1>
<p>When you authenticate on a website, the domain validate your identity before letting you access confidential information. They are several ways perform this
validation and the use of passwords is the most popular. Another method is the use of a token generator i.e. a small device that generate a secret passphrase that you
copy on a website. Today I will present you another authentication method without password using XMPP.</p>
<h2>XMPP authentication</h2>
<p>XMPP has a nice authentication mechanism. It is normalized in the XMPP extension <a href="https://xmpp.org/extensions/xep-0070.html">XEP-0070</a>. It may be used on website.
There are 4 steps.</p>
<ol>
<li>The user visits its favorite website and go to the login section.</li>
<li>The user enter its jid (XMPP address) in a form and click on a button to authenticate.</li>
<li>The website send a XMPP request to the user asking if he wants to login on the website. The request display also a code that must be identical on the website and
the XMPP client in order to validate the request.</li>
<li>The user validate the request on its XMPP client and therefore he is login on the website.</li>
</ol>
<p>There are plenty XMPP clients: <a href="https://gajim.org">Gajim</a>, <a href="https://salut-a-toi.org/">Salut-à-toi</a>, <a href="https://movim.eu/">Movim</a>, <a href="https://conversations.im/">Conversation</a>, <a href="http://poez.io">Poezio</a>, <a href="https://pidgin.im/">Pidgin</a>, <a href="http://psi-im.org/">Psi</a> etc. Several of them work on mobile, on webpage or on Desktop. Therefore, it is
possible to authenticate easily on a website using your smartphone, Desktop or another platform easily without password.</p>
<p>Note: if the client does not support the XEP-0070, there is a fallback mechanism where the user send back the validation code in a chat window. Therefore, it is possible to authenticate with all XMPP clients.</p>
<h2>Examples</h2>
<h3>Gajim</h3>
<p><img alt="Gajim XEP-0070" src="https://blog.agayon.be/images/XEP-0070-Gajim.png" style="width: 514px; height: auto; max-width: 100%;"/></p>
<h3>Salut à toi (Primitivus)</h3>
<p><img alt="Primitivus XEP-0070" src="https://blog.agayon.be/images/XEP-0070-primitivus.png.webp" style="width: 658px; height: auto; max-width: 100%;"/></p>
<p>The following section presents the implementation of this mechanism on a Django website.</p>
<h1>Use XMPP authentification mechanism with Django</h1>
<h2>Make it easy with HTTPAuthenticationOverXMPP</h2>
<p>In this section, the XMPP part is managed by a component written by "Chteufleur". This <a href="https://git.kingpenguin.tk/chteufleur/HTTPAuthentificationOverXMPP">component</a>
is easy to use. It manage the XMPP session and the web developeur just have to make a request to the component and it sends a return code:</p>
<ul>
<li>200 : User accepts the request</li>
<li>400 : One or more mandatory parameter(s) is missing</li>
<li>401 : User denies the request or timeout</li>
<li>520 : Unknown error appends</li>
<li>523 : Server is unreachable</li>
</ul>
<p>The installation procedure is described in the Readme file of the project
(<a href="https://git.kingpenguin.tk/chteufleur/HTTPAuthentificationOverXMPP">https://git.kingpenguin.tk/chteufleur/HTTPAuthentificationOverXMPP</a>).</p>
<h2>Django files</h2>
<p>The view manage the form fields and send the jid and validation code (<code>transaction_id</code>) to a module called <code>XmppBackend</code>. The <code>transaction_id</code> is generated when the form is accessed. Its value is kept in memory by using the session mechanism of Django (see section <a href="https://blog.agayon.be/xmpp_auth_django.html#settings.py">Settings.py</a>).</p>
<p>Several files are needed to obtained the desired result. The following sections describes them.</p>
<h3>Forms.py</h3>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">django</span> <span class="kn">import</span> <span class="n">forms</span>
<span class="k">class</span> <span class="nc">AuthForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>
<span class="n">username</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">100</span><span class="p">,</span> <span class="n">help_text</span><span class="o">=</span><span class="s2">"(XMPP jid)"</span><span class="p">)</span>
</code></pre></div>
<h3>HTML template</h3>
<div class="highlight"><pre><span></span><code>{% extends "base.html" %}
{% block content %}
{% if form.errors %}
<span class="p"><</span><span class="nt">p</span><span class="p">></span>Your username is invalid. Please try again.<span class="p"></</span><span class="nt">p</span><span class="p">></span>
{% endif %}
<span class="p"><</span><span class="nt">form</span> <span class="na">method</span><span class="o">=</span><span class="s">"post"</span> <span class="na">action</span><span class="o">=</span><span class="s">"{% url 'login' %}"</span><span class="p">></span>
{% csrf_token %}
<span class="p"><</span><span class="nt">table</span><span class="p">></span>
{{form.as_p}}
<span class="p"></</span><span class="nt">table</span><span class="p">></span>
<span class="p"><</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">"submit"</span> <span class="na">value</span><span class="o">=</span><span class="s">"Login"</span> <span class="na">id</span><span class="o">=</span><span class="s">"Login"</span> <span class="na">name</span><span class="o">=</span><span class="s">"login"</span><span class="p">/></span>
<span class="p"></</span><span class="nt">form</span><span class="p">></span>
Your validation code: {{ transaction_id|linebreaks }}
<span class="p"><</span><span class="nt">strong</span><span class="p">></span>{{ status_msg|linebreaks }}<span class="p"></</span><span class="nt">strong</span><span class="p">></span>
{% endblock %}
</code></pre></div>
<h3>Views.py</h3>
<p><code>views.py</code> reads the content of the POST and sends the result to <code>xmpp_auth</code>. It also handles the session and the <code>transaction_id</code> generation.</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="kn">import</span> <span class="n">render</span>
<span class="kn">from</span> <span class="nn">django.contrib.auth</span> <span class="kn">import</span> <span class="n">login</span>
<span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">HttpResponse</span>
<span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">xmpp_auth</span>
<span class="kn">from</span> <span class="nn">.forms</span> <span class="kn">import</span> <span class="n">AuthForm</span>
<span class="k">def</span> <span class="nf">index</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">'index.html'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">xmpp_authentification</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="n">xb</span> <span class="o">=</span> <span class="n">xmpp_auth</span><span class="o">.</span><span class="n">XmppBackend</span><span class="p">()</span>
<span class="n">transaction_id</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">status_msg</span> <span class="o">=</span> <span class="s2">""</span>
<span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s1">'POST'</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">transaction_id</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'transaction_id'</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
<span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="s1">'user_logged_in'</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">'fail.html'</span><span class="p">)</span>
<span class="n">form</span> <span class="o">=</span> <span class="n">AuthForm</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">)</span>
<span class="c1"># check whether it's valid:</span>
<span class="k">if</span> <span class="n">form</span><span class="o">.</span><span class="n">is_valid</span><span class="p">():</span>
<span class="n">username</span> <span class="o">=</span> <span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="s1">'username'</span><span class="p">]</span>
<span class="n">user</span><span class="p">,</span> <span class="n">status_code</span> <span class="o">=</span> <span class="n">xb</span><span class="o">.</span><span class="n">authenticate</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="n">username</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">transaction_id</span><span class="o">=</span><span class="n">transaction_id</span><span class="p">)</span>
<span class="k">if</span> <span class="n">user</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">login</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">user</span><span class="p">)</span>
<span class="c1"># Redirect to a success page.</span>
<span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="s1">'user_logged_in'</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">'success.html'</span><span class="p">)</span>
<span class="k">if</span> <span class="n">status_code</span> <span class="o">==</span> <span class="mi">401</span><span class="p">:</span>
<span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="s1">'user_logged_in'</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">status_msg</span> <span class="o">=</span> <span class="s2">"User </span><span class="si">{}</span><span class="s2"> refused to authenticate."</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">username</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="s1">'user_logged_in'</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">'fail.html'</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="s1">'user_logged_in'</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">transaction_id</span> <span class="o">=</span> <span class="n">xb</span><span class="o">.</span><span class="n">id_generator</span><span class="p">(</span><span class="mi">6</span><span class="p">)</span>
<span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="s1">'transaction_id'</span><span class="p">]</span> <span class="o">=</span> <span class="n">transaction_id</span>
<span class="n">form</span> <span class="o">=</span> <span class="n">AuthForm</span><span class="p">()</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">'registration/login.html'</span><span class="p">,</span> <span class="p">{</span><span class="s1">'form'</span><span class="p">:</span> <span class="n">form</span> <span class="p">,</span> <span class="s1">'transaction_id'</span> <span class="p">:</span> <span class="n">transaction_id</span><span class="p">,</span>
<span class="s1">'status_msg'</span><span class="p">:</span> <span class="n">status_msg</span><span class="p">})</span>
</code></pre></div>
<h3>xmpp_auth.py</h3>
<p>This module makes the following request to the component:</p>
<div class="highlight"><pre><span></span><code><span class="nf">GET</span> <span class="nn">/auth?jid=user%40host%2fresource;domain=example.net;method=POST;transaction_id=what_you_want;timeout=120</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
</code></pre></div>
<p>The component send back a return code. In case of success, the system try to find the user in the database. If this user does not exist, it is created. The system described here is simple and the code must be adapted for more complex website (profile creation, additionnal data etc).</p>
<p><code>id_generator</code> is called by <code>views.py</code> and by default, it send a code made of 8 characters (both letters and digits) but it is possible to adapt easily this behavior.</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">requests</span>
<span class="kn">import</span> <span class="nn">string</span>
<span class="kn">import</span> <span class="nn">random</span>
<span class="kn">from</span> <span class="nn">django.contrib.auth.models</span> <span class="kn">import</span> <span class="n">User</span>
<span class="k">class</span> <span class="nc">XmppBackend</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Authenticate with the XMPP 00-70 XEP</span>
<span class="sd"> """</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">transaction_id</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">def</span> <span class="nf">get_transaction_id</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">transaction_id</span>
<span class="k">def</span> <span class="nf">set_transaction_id</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">transaction_id</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">transaction_id</span> <span class="o">=</span> <span class="n">transaction_id</span>
<span class="k">def</span> <span class="nf">authenticate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">username</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">transaction_id</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span>
<span class="c1"># Check the token and return a user.</span>
<span class="n">timeout</span> <span class="o">=</span> <span class="mi">300</span>
<span class="n">payload</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'jid'</span><span class="p">:</span> <span class="n">username</span><span class="p">,</span> <span class="s1">'domain'</span><span class="p">:</span> <span class="s1">'agayon.be'</span><span class="p">,</span> <span class="s1">'method'</span><span class="p">:</span> <span class="s1">'POST'</span><span class="p">,</span> <span class="s1">'timeout'</span><span class="p">:</span> <span class="n">timeout</span><span class="p">,</span>
<span class="s1">'transaction_id'</span><span class="p">:</span> <span class="n">transaction_id</span><span class="p">}</span>
<span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'https://auth.agayon.be/auth'</span><span class="p">,</span> <span class="n">params</span><span class="o">=</span><span class="n">payload</span><span class="p">)</span>
<span class="k">if</span> <span class="n">r</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">200</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="n">username</span><span class="p">)</span>
<span class="k">except</span> <span class="n">User</span><span class="o">.</span><span class="n">DoesNotExist</span><span class="p">:</span>
<span class="c1"># Create a new user. There's no need to set a password</span>
<span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="n">username</span><span class="p">)</span>
<span class="n">user</span><span class="o">.</span><span class="n">is_staff</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">user</span><span class="o">.</span><span class="n">is_superuser</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">user</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
<span class="k">return</span> <span class="n">user</span><span class="p">,</span> <span class="n">r</span><span class="o">.</span><span class="n">status_code</span>
<span class="k">if</span> <span class="n">r</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">401</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"User </span><span class="si">{}</span><span class="s2"> refused to authenticate"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">username</span><span class="p">),</span> <span class="n">file</span><span class="o">=</span><span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="n">r</span><span class="o">.</span><span class="n">status_code</span>
<span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="n">r</span><span class="o">.</span><span class="n">status_code</span>
<span class="k">def</span> <span class="nf">id_generator</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">chars</span><span class="o">=</span><span class="n">string</span><span class="o">.</span><span class="n">ascii_letters</span> <span class="o">+</span> <span class="n">string</span><span class="o">.</span><span class="n">digits</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">transaction_id</span> <span class="o">=</span> <span class="s1">''</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">chars</span><span class="p">)</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">size</span><span class="p">))</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">transaction_id</span>
</code></pre></div>
<h3 id="settings.py">Settings.py</h3>
<p>The setting of the website must be adapted to your needs. In this simple example, the sessions must be enabled (it is the case by default). Our example use cached session but you can use cookies or even databases. See the <a href="https://docs.djangoproject.com/en/1.10/topics/auth/default/">excellent documentation of Django</a> for additional information.</p>
<div class="highlight"><pre><span></span><code><span class="n">LOGIN_URL</span> <span class="o">=</span> <span class="s1">'/path/to/login/'</span>
<span class="n">CACHES</span> <span class="o">=</span> <span class="p">{</span>
<span class="s1">'default'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'BACKEND'</span><span class="p">:</span> <span class="s1">'django.core.cache.backends.memcached.MemcachedCache'</span><span class="p">,</span>
<span class="s1">'LOCATION'</span><span class="p">:</span> <span class="s1">'unix:/tmp/memcached.sock'</span><span class="p">,</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<h1>Links</h1>
<ul>
<li><a href="https://xmpp.org/extensions/xep-0070.html">XEP-0070</a></li>
<li><a href="https://git.kingpenguin.tk/chteufleur/HTTPAuthentificationOverXMPP">Authentication component by Chteufleur</a></li>
<li><a href="https://linuxfr.org/news/authentifiez-vous-sans-mot-de-passe-grace-a-xmpp">Description of the mechanism</a> (french)</li>
<li><a href="https://docs.djangoproject.com/en/1.10/topics/auth/default/">Django authentification</a></li>
</ul>
<h1>Credits</h1>
<ul>
<li>The image comes from the post on <a href="https://linuxfr.org/news/authentifiez-vous-sans-mot-de-passe-grace-a-xmpp">Linuxfr</a> (by Chteufleur).</li>
<li>The description of the XMPP component comes from <a href="https://git.kingpenguin.tk/chteufleur/HTTPAuthentificationOverXMPP">its repository</a> (by Chteufleur).</li>
</ul>Chatty Server2017-01-10T19:00:00+01:002017-01-13T18:00:00+01:00Arnaudtag:blog.agayon.be,2017-01-10:/chatty_server.html<p>Chatty server is a XMPP bot programmed to run on a server. It can be used as a dynamic toto list; to provide the travel time by car, foot and public transport between two adresses; to give useful information about the load of the server and to give the status of the server. The status of the account change as a function of the load and memory usage.</p><p>Chatty server is a <a href="http://xmpp.org">XMPP</a> bot programmed to run on a server. It can be used</p>
<ul>
<li>as a dynamic toto list.</li>
<li>to provide the travel time by car, foot and public transport between two adresses.</li>
<li>to give useful information about the load of the server.</li>
<li>to give the status of the server. The status of the account change depending on the load and memory usage.</li>
</ul>
<p>The following sections describes the usage of chatty_server.</p>
<h1>When it start</h1>
<p>At start, the program set a status base on the load and the memory usage.</p>
<div class="highlight"><pre><span></span><code><span class="err"></span><span class="mi">18</span><span class="err">:</span><span class="mi">40</span><span class="err">:</span><span class="mi">29</span><span class="w"> </span><span class="err"></span><span class="n">server</span><span class="err">:</span><span class="w"> </span><span class="n">Agayon</span><span class="p">.</span><span class="n">be</span><span class="w"> </span><span class="n">en</span><span class="w"> </span><span class="n">ligne</span>
<span class="err"></span><span class="mi">18</span><span class="err">:</span><span class="mi">40</span><span class="err">:</span><span class="mi">30</span><span class="w"> </span><span class="err"></span><span class="n">server</span><span class="err">:</span><span class="w"> </span><span class="n">How</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">doin</span><span class="s1">' ? Load: 0.12 0.05 0.05 Memory (Go): 1.08GiB/1.96GiB (35.2%)</span>
<span class="s1">18:40:30 server is now Available (How you doin'</span><span class="w"> </span><span class="vm">?</span><span class="w"> </span><span class="k">Load</span><span class="err">:</span><span class="w"> </span><span class="mf">0.12</span><span class="w"> </span><span class="mf">0.05</span><span class="w"> </span><span class="mf">0.05</span><span class="w"> </span><span class="n">Memory</span><span class="w"> </span><span class="p">(</span><span class="k">Go</span><span class="p">)</span><span class="err">:</span><span class="w"> </span><span class="mf">1.08</span><span class="n">GiB</span><span class="o">/</span><span class="mf">1.96</span><span class="n">GiB</span><span class="w"> </span><span class="p">(</span><span class="mf">35.2</span><span class="o">%</span><span class="p">))</span>
<span class="k">Get</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">list</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="n">available</span><span class="w"> </span><span class="n">commands</span>
</code></pre></div>
<p>The list of command is send whenever the user send a message to the bot.</p>
<div class="highlight"><pre><span></span><code>18:40:58 jnanar: help
18:40:58 server: Available Commands : status, reminder, travel
</code></pre></div>
<h2>Calculate a travel time</h2>
<p>Calculate a travel time is easy and fast. You need to define a Google Maps API key to use this function. You can also, define</p>
<ul>
<li>your address,</li>
<li>the summary key: it is the summary of this travel( a highway, a long road, etc),</li>
<li>the shortest distance between work and home,</li>
<li>as well as the duration of this particular travel.</li>
</ul>
<p>When the distance differs or time differs too much from these data, the bot will remind you to take another road.</p>
<div class="highlight"><pre><span></span><code><span class="mi">18</span><span class="o">:</span><span class="mi">22</span><span class="o">:</span><span class="mi">22</span><span class="w"> </span><span class="err"></span><span class="n">jnanar</span><span class="err"></span><span class="o">:</span><span class="w"> </span><span class="n">travel</span>
<span class="err"></span><span class="mi">18</span><span class="o">:</span><span class="mi">22</span><span class="o">:</span><span class="mi">23</span><span class="w"> </span><span class="err"></span><span class="n">server</span><span class="err"></span><span class="o">:</span><span class="w"> </span><span class="n">Usage</span><span class="o">:</span><span class="w"> </span><span class="n">travel</span><span class="w"> </span><span class="n">car</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="n">stop</span>
<span class="n">conveyance</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">car</span><span class="o">,</span><span class="w"> </span><span class="n">bus</span><span class="o">,</span><span class="w"> </span><span class="n">metro</span><span class="o">,</span><span class="w"> </span><span class="n">tramway</span><span class="w"> </span><span class="n">etc</span><span class="o">.</span>
<span class="n">Example</span><span class="o">:</span><span class="w"> </span><span class="n">travel</span><span class="w"> </span><span class="n">car</span><span class="w"> </span><span class="n">rue</span><span class="w"> </span><span class="n">du</span><span class="w"> </span><span class="n">parc</span><span class="w"> </span><span class="mi">4000</span><span class="w"> </span><span class="n">Liège</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="n">Place</span><span class="w"> </span><span class="n">saint</span><span class="w"> </span><span class="n">Lambert</span><span class="w"> </span><span class="mi">15</span><span class="w"> </span><span class="mi">4000</span><span class="w"> </span><span class="n">Liège</span>
<span class="err"></span>
</code></pre></div>
<h2>Examples</h2>
<div class="highlight"><pre><span></span><code><span class="mi">18</span><span class="o">:</span><span class="mi">42</span><span class="o">:</span><span class="mi">08</span><span class="w"> </span><span class="err"></span><span class="n">jnanar</span><span class="err"></span><span class="o">:</span><span class="w"> </span><span class="n">travel</span><span class="w"> </span><span class="n">car</span><span class="w"> </span><span class="n">rue</span><span class="w"> </span><span class="n">du</span><span class="w"> </span><span class="n">parc</span><span class="w"> </span><span class="mi">4000</span><span class="w"> </span><span class="n">Liège</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="n">Place</span><span class="w"> </span><span class="n">saint</span><span class="w"> </span><span class="n">Lambert</span><span class="w"> </span><span class="mi">15</span><span class="w"> </span><span class="mi">4000</span><span class="w"> </span><span class="n">Liège</span>
<span class="err"></span><span class="mi">18</span><span class="o">:</span><span class="mi">42</span><span class="o">:</span><span class="mi">09</span><span class="w"> </span><span class="err"></span><span class="n">server</span><span class="err"></span><span class="o">:</span><span class="w"> </span><span class="n">travel</span><span class="w"> </span><span class="n">car</span>
<span class="n">travel</span><span class="w"> </span><span class="n">rue</span><span class="w"> </span><span class="n">du</span><span class="w"> </span><span class="n">parc</span><span class="w"> </span><span class="mi">4000</span><span class="w"> </span><span class="n">liège</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">place</span><span class="w"> </span><span class="n">saint</span><span class="w"> </span><span class="n">lambert</span><span class="w"> </span><span class="mi">15</span><span class="w"> </span><span class="mi">4000</span><span class="w"> </span><span class="n">liège</span>
<span class="n">Summary</span><span class="o">:</span><span class="w"> </span><span class="n">Quai</span><span class="w"> </span><span class="n">Orban</span>
<span class="n">Distance</span><span class="o">:</span><span class="w"> </span><span class="mf">2.46</span><span class="w"> </span><span class="n">km</span>
<span class="n">Duration</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">traffic</span><span class="o">:</span><span class="w"> </span><span class="mf">9.22</span><span class="w"> </span><span class="n">min</span>
<span class="n">Duration</span><span class="w"> </span><span class="o">(</span><span class="n">normal</span><span class="o">):</span><span class="w"> </span><span class="mf">8.05</span><span class="w"> </span><span class="n">min</span>
</code></pre></div>
<p>In order to use the travel time function you need to define an API key, a work location and a home location in the file named "libs/credentials.py". Some shortcuts
are available: h2w and w2h for home and work location.</p>
<div class="highlight"><pre><span></span><code><span class="mi">18</span><span class="o">:</span><span class="mi">49</span><span class="o">:</span><span class="mi">10</span><span class="w"> </span><span class="err"></span><span class="n">jnanar</span><span class="err"></span><span class="o">:</span><span class="w"> </span><span class="n">travel</span><span class="w"> </span><span class="n">h2w</span>
<span class="err"></span><span class="mi">18</span><span class="o">:</span><span class="mi">49</span><span class="o">:</span><span class="mi">11</span><span class="w"> </span><span class="err"></span><span class="n">server</span><span class="err"></span><span class="o">:</span><span class="w"> </span><span class="n">home</span><span class="w"> </span><span class="n">address</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">work</span><span class="w"> </span><span class="n">address</span>
<span class="n">Summary</span><span class="o">:</span><span class="w"> </span><span class="n">E42</span>
<span class="n">Distance</span><span class="o">:</span><span class="w"> </span><span class="mf">7.81</span><span class="w"> </span><span class="n">km</span>
<span class="n">Duration</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">traffic</span><span class="o">:</span><span class="w"> </span><span class="mf">11.03</span><span class="w"> </span><span class="n">min</span>
<span class="n">Duration</span><span class="w"> </span><span class="o">(</span><span class="n">normal</span><span class="o">):</span><span class="w"> </span><span class="mf">11.13</span><span class="w"> </span><span class="n">min</span>
</code></pre></div>
<h2>Obtain the status of the server</h2>
<div class="highlight"><pre><span></span><code><span class="mi">18</span><span class="o">:</span><span class="mi">34</span><span class="o">:</span><span class="mi">13</span><span class="w"> </span><span class="err"></span><span class="n">jnanar</span><span class="err"></span><span class="o">:</span><span class="w"> </span><span class="n">status</span>
<span class="err"></span><span class="mi">18</span><span class="o">:</span><span class="mi">34</span><span class="o">:</span><span class="mi">13</span><span class="w"> </span><span class="err"></span><span class="n">server</span><span class="o">:</span>
<span class="n">Load</span><span class="o">:</span><span class="w"> </span><span class="mf">2.12</span><span class="w"> </span><span class="mf">2.26</span><span class="w"> </span><span class="mf">2.31</span><span class="w"> </span><span class="n">Memory</span><span class="w"> </span><span class="o">(</span><span class="n">Go</span><span class="o">):</span><span class="w"> </span><span class="mf">3.94</span><span class="n">GiB</span><span class="o">/</span><span class="mf">11.23</span><span class="n">GiB</span><span class="w"> </span><span class="o">(</span><span class="mf">17.6</span><span class="o">%)</span>
<span class="n">CPUS</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="o">(</span><span class="s1">'14.5%'</span><span class="o">,</span><span class="w"> </span><span class="s1">'11.9%'</span><span class="o">,</span><span class="w"> </span><span class="s1">'19.0%'</span><span class="o">,</span><span class="w"> </span><span class="s1">'10.9%'</span><span class="o">,</span><span class="w"> </span><span class="s1">'35.7%'</span><span class="o">,</span><span class="w"> </span><span class="s1">'7.6%'</span><span class="o">)</span>
<span class="n">Memory</span><span class="w"> </span><span class="o">(</span><span class="n">Go</span><span class="o">):</span><span class="w"> </span><span class="mf">3.94</span><span class="n">GiB</span><span class="o">/</span><span class="mf">11.23</span><span class="n">GiB</span><span class="w"> </span><span class="o">(</span><span class="mf">17.6</span><span class="o">%)</span>
</code></pre></div>
<h2>Use it as a reminder or a TODOlist.</h2>
<div class="highlight"><pre><span></span><code><span class="mi">18</span>:<span class="mi">42</span>:<span class="mi">45</span><span class="w"> </span><span class="nv">jnanar</span>:<span class="w"> </span><span class="nv">reminder</span><span class="w"> </span><span class="nv">list</span>
<span class="mi">18</span>:<span class="mi">42</span>:<span class="mi">45</span><span class="w"> </span><span class="nv">server</span>:<span class="w"> </span><span class="nv">Todo</span><span class="w"> </span><span class="nv">list</span>
<span class="mi">18</span>:<span class="mi">42</span>:<span class="mi">57</span><span class="w"> </span><span class="nv">jnanar</span>:<span class="w"> </span><span class="nv">reminder</span><span class="w"> </span><span class="nv">write</span><span class="w"> </span><span class="nv">a</span><span class="w"> </span><span class="nv">blog</span><span class="w"> </span><span class="nv">article</span><span class="w"> </span><span class="mi">5</span><span class="nv">min</span>
<span class="mi">18</span>:<span class="mi">42</span>:<span class="mi">57</span><span class="w"> </span><span class="nv">server</span>:<span class="w"> </span><span class="nv">Reminder</span>:<span class="w"> </span><span class="nv">write</span><span class="w"> </span><span class="nv">a</span><span class="w"> </span><span class="nv">blog</span><span class="w"> </span><span class="nv">article</span><span class="w"> </span><span class="nv">at</span><span class="w"> </span><span class="mi">2017</span><span class="o">-</span><span class="mi">01</span><span class="o">-</span><span class="mi">04</span><span class="w"> </span><span class="mi">18</span>:<span class="mi">48</span>:<span class="mi">04</span>.<span class="mi">797349</span>
<span class="mi">18</span>:<span class="mi">43</span>:<span class="mi">23</span><span class="w"> </span><span class="nv">jnanar</span>:<span class="w"> </span><span class="nv">reminder</span><span class="w"> </span><span class="mi">2</span><span class="nv">h</span><span class="w"> </span><span class="nv">program</span><span class="w"> </span><span class="nv">my</span><span class="w"> </span><span class="nv">personal</span><span class="w"> </span><span class="nv">robot</span>
<span class="mi">18</span>:<span class="mi">43</span>:<span class="mi">23</span><span class="w"> </span><span class="nv">server</span>:<span class="w"> </span><span class="nv">Reminder</span>:<span class="w"> </span><span class="nv">program</span><span class="w"> </span><span class="nv">my</span><span class="w"> </span><span class="nv">personal</span><span class="w"> </span><span class="nv">robot</span><span class="w"> </span><span class="nv">at</span><span class="w"> </span><span class="mi">2017</span><span class="o">-</span><span class="mi">01</span><span class="o">-</span><span class="mi">04</span><span class="w"> </span><span class="mi">20</span>:<span class="mi">43</span>:<span class="mi">30</span>.<span class="mi">599113</span>
<span class="mi">18</span>:<span class="mi">43</span>:<span class="mi">29</span><span class="w"> </span><span class="nv">jnanar</span>:<span class="w"> </span><span class="nv">reminder</span><span class="w"> </span><span class="nv">list</span>
<span class="mi">18</span>:<span class="mi">43</span>:<span class="mi">29</span><span class="w"> </span><span class="nv">server</span>:<span class="w"> </span><span class="nv">Todo</span><span class="w"> </span><span class="nv">list</span>
<span class="nv">todo</span>:<span class="w"> </span><span class="nv">due</span><span class="w"> </span><span class="nv">write</span><span class="w"> </span><span class="nv">a</span><span class="w"> </span><span class="nv">blog</span><span class="w"> </span><span class="nv">article</span><span class="w"> </span><span class="nv">at</span><span class="w"> </span><span class="mi">2017</span><span class="o">-</span><span class="mi">01</span><span class="o">-</span><span class="mi">04</span><span class="w"> </span><span class="mi">18</span>:<span class="mi">48</span>:<span class="mi">04</span>.<span class="mi">797349</span>
<span class="nv">todo</span>:<span class="w"> </span><span class="nv">due</span><span class="w"> </span><span class="nv">program</span><span class="w"> </span><span class="nv">my</span><span class="w"> </span><span class="nv">personal</span><span class="w"> </span><span class="nv">robot</span><span class="w"> </span><span class="nv">at</span><span class="w"> </span><span class="mi">2017</span><span class="o">-</span><span class="mi">01</span><span class="o">-</span><span class="mi">04</span><span class="w"> </span><span class="mi">20</span>:<span class="mi">43</span>:<span class="mi">30</span>.<span class="mi">599113</span>
<span class="mi">18</span>:<span class="mi">43</span>:<span class="mi">57</span><span class="w"> </span><span class="nv">jnanar</span>:<span class="w"> </span><span class="nv">reminder</span><span class="w"> </span><span class="mi">1</span><span class="nv">min</span><span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="nv">a</span><span class="w"> </span><span class="nv">test</span>
<span class="mi">18</span>:<span class="mi">43</span>:<span class="mi">57</span><span class="w"> </span><span class="nv">server</span>:<span class="w"> </span><span class="nv">Reminder</span>:<span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="nv">a</span><span class="w"> </span><span class="nv">test</span><span class="w"> </span><span class="nv">at</span><span class="w"> </span><span class="mi">2017</span><span class="o">-</span><span class="mi">01</span><span class="o">-</span><span class="mi">04</span><span class="w"> </span><span class="mi">18</span>:<span class="mi">45</span>:<span class="mi">04</span>.<span class="mi">779812</span>
<span class="mi">18</span>:<span class="mi">44</span>:<span class="mi">05</span><span class="w"> </span><span class="nv">jnanar</span>:<span class="w"> </span><span class="nv">reminder</span><span class="w"> </span><span class="nv">list</span>
<span class="mi">18</span>:<span class="mi">44</span>:<span class="mi">05</span><span class="w"> </span><span class="nv">server</span>:<span class="w"> </span><span class="nv">Todo</span><span class="w"> </span><span class="nv">list</span>
<span class="nv">todo</span>:<span class="w"> </span><span class="nv">due</span><span class="w"> </span><span class="nv">write</span><span class="w"> </span><span class="nv">a</span><span class="w"> </span><span class="nv">blog</span><span class="w"> </span><span class="nv">article</span><span class="w"> </span><span class="nv">at</span><span class="w"> </span><span class="mi">2017</span><span class="o">-</span><span class="mi">01</span><span class="o">-</span><span class="mi">04</span><span class="w"> </span><span class="mi">18</span>:<span class="mi">48</span>:<span class="mi">04</span>.<span class="mi">797349</span>
<span class="nv">todo</span>:<span class="w"> </span><span class="nv">due</span><span class="w"> </span><span class="nv">program</span><span class="w"> </span><span class="nv">my</span><span class="w"> </span><span class="nv">personal</span><span class="w"> </span><span class="nv">robot</span><span class="w"> </span><span class="nv">at</span><span class="w"> </span><span class="mi">2017</span><span class="o">-</span><span class="mi">01</span><span class="o">-</span><span class="mi">04</span><span class="w"> </span><span class="mi">20</span>:<span class="mi">43</span>:<span class="mi">30</span>.<span class="mi">599113</span>
<span class="nv">todo</span>:<span class="w"> </span><span class="nv">due</span><span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="nv">a</span><span class="w"> </span><span class="nv">test</span><span class="w"> </span><span class="nv">at</span><span class="w"> </span><span class="mi">2017</span><span class="o">-</span><span class="mi">01</span><span class="o">-</span><span class="mi">04</span><span class="w"> </span><span class="mi">18</span>:<span class="mi">45</span>:<span class="mi">04</span>.<span class="mi">779812</span>
<span class="mi">18</span>:<span class="mi">45</span>:<span class="mi">01</span><span class="w"> </span><span class="nv">server</span>:
<span class="o">---</span>
<span class="nv">Reminder</span>:<span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="nv">a</span><span class="w"> </span><span class="nv">test</span>
<span class="o">---</span>
<span class="mi">18</span>:<span class="mi">45</span>:<span class="mi">10</span><span class="w"> </span><span class="nv">jnanar</span>:<span class="w"> </span><span class="nv">reminder</span><span class="w"> </span><span class="nv">list</span>
<span class="mi">18</span>:<span class="mi">45</span>:<span class="mi">10</span><span class="w"> </span><span class="nv">server</span>:<span class="w"> </span><span class="nv">Todo</span><span class="w"> </span><span class="nv">list</span>
<span class="nv">todo</span>:<span class="w"> </span><span class="nv">due</span><span class="w"> </span><span class="nv">write</span><span class="w"> </span><span class="nv">a</span><span class="w"> </span><span class="nv">blog</span><span class="w"> </span><span class="nv">article</span><span class="w"> </span><span class="nv">at</span><span class="w"> </span><span class="mi">2017</span><span class="o">-</span><span class="mi">01</span><span class="o">-</span><span class="mi">04</span><span class="w"> </span><span class="mi">18</span>:<span class="mi">48</span>:<span class="mi">04</span>.<span class="mi">797349</span>
<span class="nv">todo</span>:<span class="w"> </span><span class="nv">due</span><span class="w"> </span><span class="nv">program</span><span class="w"> </span><span class="nv">my</span><span class="w"> </span><span class="nv">personal</span><span class="w"> </span><span class="nv">robot</span><span class="w"> </span><span class="nv">at</span><span class="w"> </span><span class="mi">2017</span><span class="o">-</span><span class="mi">01</span><span class="o">-</span><span class="mi">04</span><span class="w"> </span><span class="mi">20</span>:<span class="mi">43</span>:<span class="mi">30</span>.<span class="mi">599113</span>
<span class="nv">todo</span>:<span class="w"> </span><span class="nv">done</span><span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="nv">a</span><span class="w"> </span><span class="nv">test</span><span class="w"> </span><span class="nv">at</span><span class="w"> </span><span class="mi">2017</span><span class="o">-</span><span class="mi">01</span><span class="o">-</span><span class="mi">04</span><span class="w"> </span><span class="mi">18</span>:<span class="mi">45</span>:<span class="mi">04</span>.<span class="mi">779812</span>
</code></pre></div>
<p>chatty_server is written in python v3 and is licensed under the GPLv3 licence.</p>
<h1>Install</h1>
<h2>Install the dependencies</h2>
<ul>
<li><a href="https://github.com/fritzy/SleekXMPP">SleekXMPP</a></li>
<li><a href="https://github.com/googlemaps/google-maps-services-python">Google Maps python API</a></li>
</ul>
<h2>Clone the repository</h2>
<ul>
<li>git clone git@gitlab.com:r1dScripts/chatty_server.git</li>
<li>Modify libs/credentials.example.py and rename it as libs/credentials.py.</li>
</ul>