Planet Jabber

March 31, 2015

Isode

R16.3: Multi-Master Directory, XMPP Archive/Search & ACP127 support


We’re pleased to announce the availability of Isode’s latest release, R16.3, which can be downloaded now from our website. R16.3 is a major Isode release which adds new capabilities across the entire Isode product range, including:

M-Vault

We’ve introduced a multi-master capability to M-Vault, complementing the single-master approach to replication defined in the X.500 protocols around which M-Vault was developed. M-Vault is the first directory to offer both multi-master and X.500.

M-Link

M-Link gains a new Archive Server for archive of all messages (including 1:1 chat, MUC and PubSub). XMPP clients can access archives using Message Archive Management (MAM) as defined in XEP-0313. M-Link also gains three new web applications:

  1. Message Archive Management, allowing browser-based access to information in the archive.
  2. Statistics, a lightweight monitoring alternative to the M-Link Console GUI.
  3. Forms Discovery and Publishing, for end-user publishing and display of FDP forms.
M-Link Statistics Web App

M-Link Statistics Web App

M-Switch

We’ve added gateway support for text based organisational message protocols, which we’re collectively describing as “ACP127”. The first release of this capability supports ACP127 and DOI 103S, a popular US variant, and enables conversion with STANAG 4406 (compliant to STANAG 4406 Annex D) and SMTP (following the MMHS over SMTP extensions).

In addition we’ve made extensive improvements to MConsole and M-Link Console to support the new M-Switch and M-Link family capabilities. For a full run-down of new capabilities in R16.3, please see the Product Release page. We’ll be publishing further blog posts over the coming weeks focusing on some of the new R16.3 capabilities.

by Will Sheward at March 31, 2015 11:30

March 29, 2015

Ignite Realtime Blog

Smack 4.1.0 released

The Ignite Realtime community is very happy and proud to announce the release of Smack 4.1.0, our open source XMPP client library. Since Smack 4.1 is not binary compatible with Smack 4.0, i.e. it is not a drop-in replacement, make sure to have a look at the "Smack 4.1 Readme and Upgrade Guide".

 

Smack 4.1 marks a milestone in the development history of Smack, as its obsoletes aSmack, the build environment formerly required to port Smack to Android. Starting with 4.1, Smack is able to run natively and unmodified on Android.

 

A further release highlight, among many others, is the support for XEP-198: Stream Management. Note that like every new big feature, Stream Management is disabled by default.

 

The full changelog can be found at https://www.igniterealtime.org/builds/smack/docs/4.1.0/changelog.html, the javadoc is available accessible via https://www.igniterealtime.org/builds/smack/docs/4.1.0/javadoc/ and the documentation available at https://www.igniterealtime.org/builds/smack/docs/4.1.0/documentation/

 

We would like to thank everyone who provided feedback, bug reports and contributed. The developers and contributors for the 4.1.0 release, since 4.0.0 are:

 

$ git shortlog -sn 4.0.0..4.1.0

   631  Florian Schmaus

     4  Vyacheslav Blinov

     3  Anno van Vliet

     3  Daniele Ricci

     2  Georg Lukas

     2  Júlio Cesar Bueno Cotta

     2  lucastucchi

     2  vito-c

     1  Abmar Barros

     1  Anno

     1  Chris Deering

     1  Christoph Fiehe

     1  Gilles Cornu

     1  Gligor Selimovic

     1  Jae Jang

     1  Luke GB

     1  atsykholyas

 

The signed tag used to upload the 4.1.0 artifacts to Maven Central points to 4bb8aea2815ceaab4224d1e2c3d80ba70c1f3803. As always, Smack 4.1.0 is available via Maven Central.

 

Now go ahead and implement a open source XMPP client with Smack. Be it for Android or one of the many platforms supported by Java. But even more importantly, provide feedback and help to improve Smack. We try our best to make Smack one of the best, stable and reliable open source libraries for XMPP, but it's far from being perfect. Join #smack (freenode) and discuss with us how Smack could be improved.

 

Happy Hacking.

by Ignite Realtime Blog (igniterealtime@jiveon.com) at March 29, 2015 14:23

March 26, 2015

buddycloud

10 Day Challenge: Build a mobile social network

Tomorrow morning some of the Buddycloud team departs from Berlin, Germany, for Johannesburg, South Africa.

We’re excited to build a production-ready mobile social network for Project Isizwe, including user and group communication: backend, frontend, message synchronisation in just 10 days. This is amazingly fast and we’re up against a very tight schedule.

image

Background

Project Isizwe provides free WiFi to township residents and has 500K users on their free wifi service. Now they want to help their users communicate, help and share information with each other. And more…  

Project Isizwe identified a big problem with how their users are being ignored by the government. They noticed two things:

  • there is no effective forum for feedback and debate between residents and the Government and,
  • the younger residents don’t feel they are heard through traditional government channels.

For example, younger residents never attend town-hall meetings and this leads to their voice being lost in the decision making.

The Project Isizwe team designed a solution called Wifi Chat and asked Buddycloud to help them with in-app messaging and social infrastructure to power this.

image

Wifi Chat will provide a real-time, secure and easy to use set of channels and site for informing citizens of new developments or topics and receiving feedback, input and comments.

Because messaging is really important to Project Isizwe’s strategy, they wanted to build wifi-chat as open source using open standards. This will enable their developers  to extend the Buddycloud to new in-house apps. For example, various city Governments could integrate their own communication channels into one service.

They had us at “open and extensible” and we offered to jump in and help and learn about their requirements.

Deciding to use a ready-made backend like Buddycloud has immediately saved at least a year of development time. That means our time in SA can be used to just spin-up a ready-made Buddycloud stack on their network and leaves us free to focus on developing the frontend.

And so to the frontend: we’re up against some interesting challenges:

  • lots of low end devices
  • web only

To give you an idea of the devices we’re dealing with here’s a selection:

Phone modelShareOSVersionScreen size
Huawei Y220-U0011.3%Android2.3320x480
Samsung GT-S5280 Galaxy Star4.5%Android4.1.2240x320
Vodafone VF685 Smart Kicka4.3%Android4.4320x480
Nokia Lumia 5204.2%Windows Phone8@2_240x400
Samsung GT-S5301 Galaxy Pocket Plus3.7%Android4240x320
ZTE V7953.2%Android2.3320x480
BlackBerry Z102.8%BlackBerry10@2_384x640

This week we’ve been thinking about how to best create a realtime messaging solution on resource constrained devices. We’ve been going backwards and forwards on Angular, Backbone and other Javascript frameworks to work out what will best suit this project and enable us to ship in 10 days.

We’re going to work some magic

For quick spin-up of the backend, we’ll be using the Buddycloud-vm project to generate and orchestrate new server images for testing and production servers.

For the next 10 days we’ll be posting a daily development report covering the the technical challenges. You can start following our code progress starting on Monday as we push to https://github.com/project-isizwe/wifi-chat

Felix has already started working his interface magic and we’ll be posting more images as they fly off his machine.

See you on Monday!

by imaginator at March 26, 2015 19:43

Prosodical Thoughts

Prosody 0.9.8 released

We are pleased to announce a new minor release from our stable branch. This release contains mainly bug fixes, including an important security fix.

A summary of changes in this release, by importance:

High:

  • Ensure only valid UTF-8 is passed to libidn. It was found (CVE-2015-2059) that libidn can read beyond the boundaries of the provided buffer when an input string contains invalid UTF-8 sequences.

Systems where Prosody is compiled with libICU are not affected by this issue.

Medium:

  • DNS: Fix traceback caused when DNS server IP is unroutable (issue 473)
  • HTTP client: More robust handling of chunked encoding across packet boundaries
  • Stanza router: Fix handling of 'error' <iq>'s with multiple children

Low:

  • c2s: Fix error reply when clients try to bind multiple resources on the same stream (issue 484)
  • s2s: Ensure to/from attributes are always present on stream headers, even if empty (issue 468)
  • Build scripts: Add --libdir option to ./configure to simplify building on some platforms
  • Fix traceback in datamanager when used outside of Prosody (e.g. in some migration tools)
  • mod_admin_telnet: Fix potential traceback in server:memory() command (issue 471)
  • HTTP server: Improved debug logging

Download

As usual, download instructions for many platforms can be found on our download page

If you have any questions, comments or other issues with this release, let us know!

by The Prosody Team at March 26, 2015 15:59

March 25, 2015

Tigase Blog

Tigase Server 7.0.1 Release

A maintenance version of Tigase XMPP Server (7.0.1) has been released. Binaries are available for download in the files section on the project tracking system.

by eric at March 25, 2015 17:49

ProcessOne

Elixir Sips: ejabberd with Elixir – Part 1

Elixir Sips is an Elixir screencast website providing great tutorials to learn Elixir but also to help you build extraordinary pieces of code quickly with Elixir.

They produced a great series of videos on programming ejabberd with Elixir. Here is the material for the first part. We will publish more material on ProcessOne blog soon. Stay tuned !

Most of all, please, give us feedback in the comments on what you would like to see covered regarding ejabberd and Elixir… Or even better, come to see us live at upcoming ejabberd San Francisco Bay Area Meetup !

Here is the first ejabberd / Elixir tutorial (Part 1�) �by Josh Adams.�
Please note that part 2 of this tutorial is also available: Extending ejabberd with Elixir – Part 2.

Introduction

ejabberd is an XMPP server that is widely used to power either vanilla XMPP installs or XMPP-backed applications. It’s one of Erlang’s success stories, and it recently added Elixir support. Here is the blog post announcing Elixir support: ejabberd joins the Elixir revolution�.

Setup

I followed the blog post regarding compiling ejabberd with Elixir support.
Let’s see the support in action:

cd ~/my-ejabberd
./sbin/ejabberdctl iexlive
iex(ejabberd@localhost)1> IO.puts "ejabberdSips!"
ejabberdSips!
:ok
iex(ejabberd@localhost)2> :ejabberd_auth.try_register("elixirsips", "localhost", "mypass")
{:atomic, :ok}

Alright, so we’ve registered a elixirsips user locally. Let’s see if our XMPP client can connect:

((( open up gajim, add account )))

So there, we’ve connected to the account with the user we added from Elixir.
Now the blog post says for us to build the smallest possible module, but they have already provided it for us.

cd ~/erlang/ejabberd
vim lib/mod_presence_demo.ex
defmodule ModPresenceDemo do
  import Ejabberd.Logger # this allow using info, error, etc for logging
  @behaviour :gen_mod

  def start(host, _opts) do
    info('Starting ejabberd module Presence Demo')
    Ejabberd.Hooks.add(:set_presence_hook, host, __ENV__.module, :on_presence, 50)
    :ok
  end

  def stop(host) do
    info('Stopping ejabberd module Presence Demo')
    Ejabberd.Hooks.delete(:set_presence_hook, host, __ENV__.module, :on_presence, 50)
    :ok
  end

  def on_presence(user, _server, _resource, _packet) do
    info('Receive presence for #{user}')
    :none
  end
end

Here you can see that, when enabled, this will announce presence for every user when they change presence. We didn’t see that happen when I connected, so it must not be enabled. Let’s open up the yaml configuration file:

cd ~/my-ejabberd
vim etc/ejabberd/ejabberd.yml

In the modules section, add:

ModPresenceDemo: {}

Now we’ll restart and connect again. Now every time we change presence, an update gets logged.

This is the end of the introductory blog post. Let’s see if we can take it a little bit further. Open up the module again:

  def on_presence(user, _server, _resource, packet) do
    info('Receive presence for #{user}')
    # We'll inspect the packet that we're sent in this event
    info(inspect packet)
    :none
  end

Now recompile everything and reinstall, and start it back up. Now I’ll connect again with my client and we’ll see what a presence packet looks like.

((( connect, mark yourself away with a given status )))

19:54:04.160 [info] Receive presence for elixirsips
19:54:04.161 [info] {:xmlel, "presence", [{"xml:lang", "en"}, {"id", "56"}], [{:xmlel, "priority", [], [xmlcdata: "40"]}, {:xmlel, "show", [], [xmlcdata: "away"]}, {:xmlel, "x", [{"xmlns", "vcard-temp:x:update"}], [{:xmlel, "photo", [], []}]}, {:xmlel, "c", [{"xmlns", "http://jabber.org/protocol/caps"}, {"node", "http://gajim.org"}, {"ver", "47EPEmSc9oqPGwcrbNtpKcYyJcE="}, {"hash", "sha-1"}], []}, {:xmlel, "status", [], [xmlcdata: "asdf"]}]}

So here we can see what an away presence message with a status looks like.
Let’s log it a bit nicer:

  def on_presence(user, _server, _resource, packet) do
    info('Receive presence for #{user}')
    info(inspect(:xml.get_subtag(packet, "show")))
    :none
  end

Now I’ll do my common happy-path “,t” thing and map that key combination to build and install the new plugin, so we can easily do that part, then restart the server every time we want to see a change:

:map ,t :!make && make install<cr>

Let’s use it, and restart the server. Now change our status a few times.

We can see that there’s no “show” subtag when we’re just available, but otherwise it maps to various defined states. Let’s also log the status if it exists:

  def on_presence(user, _server, _resource, packet) do
    info('Receive presence for #{user}')
    info(inspect(:xml.get_subtag(packet, "show")))
    info(inspect(:xml.get_subtag(packet, "status")))
    :none
  end

We could do a bit more, but this shows a decent start. In the next episode, we’ll look at how you can filter packets as they pass through the system. See you soon!

Resources

Learn more about ejabberd development at upcoming ejabberd San Francisco Bay Area Meetup !

by Mickaël Rémond at March 25, 2015 16:26

Elixir Sips: ejabberd with Elixir – Part 2

Elixir Sips is an Elixir screencast website providing great tutorials to learn Elixir but also to help you build extraordinary pieces of code quickly with Elixir.

They produced a great series of videos on programming ejabberd with Elixir. In the first part of that tutorial, you have learned how to set up Elixir support in ejabberd and write your first ejabberd module in Elixir. Here is the material for the second part in which you will learn how to leverage one of the most powerful ejabberd hooks: ejabberd packet filter.

We will publish more material on ProcessOne blog soon. Stay tuned !

Most of all, please, give us feedback in the comments on what you would like to see covered regarding ejabberd and Elixir… Or even better, come to see us live at upcoming ejabberd San Francisco Bay Area Meetup !

Here is the second ejabberd / Elixir tutorial (Part 2) �by Josh Adams.�

Introduction

In the last episode, we saw how to get notified of presence messages from users connected to the ejabberd server. Now we’re going to look at how we can modify messages as they are sent from user to user. Specifically, we’re going to build a module that makes everyone yell all the time.

Project

We’re going to just start where the last episode left off. Let’s add a new module first.

cp lib/mod_presence_demo.ex lib/filter_packet_demo.ex
vim lib/filter_packet_demo.ex
defmodule FilterPacketDemo do
  import Ejabberd.Logger # this allow using info, error, etc for logging
  @behaviour :gen_mod

  def start(_host, _opts) do
    info('Starting ejabberd module Filter Packet Demo')
    # NOTE: The second argument here is global
    Ejabberd.Hooks.add(:filter_packet, :global, __ENV__.module, :on_filter_packet, 50)
    :ok
  end

  def stop(_host) do
    info('Stopping ejabberd module Filter Packet Demo')
    # NOTE: The second argument here is global
    Ejabberd.Hooks.delete(:filter_packet, :global, __ENV__.module, :on_filter_packet, 50)
    :ok
  end

  def on_filter_packet({from, to, xml} = packet) do
    info("Filtering packet: #{inspect {from, to, xml}}")
    packet
  end
end

Now I’ll compile it and install it with my ,t mapping.

Now let’s enable this module in our server. Open up the config in ~/my-ejabberd and add our new module.

Next let’s just start the ejabberd server:

./sbin/ejabberdctl iexlive

We’ll connect with two users and chat between them, and we’ll see all the packets that flow through ejabberd. Of course, we only really want to do anything to messages, so let’s restrict our hook to only catch those:

defmodule FilterPacketDemo do
  def on_filter_packet({from, to, xml={:xmlel, "message", _attributes, _children}} = packet) do
    info("Filtering message: #{inspect packet}")
    body = :xml.get_subtag(xml, "body")
    info(inspect body)
    packet
  end
  def on_filter_packet(packet), do: packet
end

Compile and restart, send some messages, and now we only see info logs on our actual messages…You’ll note there’s an empty message sent every time we send one with a body as well. I believe this is just the confirmation of receipt of a given message.

We want to just write a filter that will upcase all of these messages, to begin with. To do that, all we would have to do is replace the body with the upcased body. Let’s think about how to do that. Basically, we would just want to map the children tags of the message, modifying the cdata if they match a certain tag name, and then use the mapped result as the children of the packet that we pass along. Let’s try that.

defmodule FilterPacketDemo do
  import Ejabberd.Logger # this allow using info, error, etc for logging
  @behaviour :gen_mod

  def start(host, _opts) do
    info('Starting ejabberd module Filter Packet Demo')
    Ejabberd.Hooks.add(:filter_packet, :global, __ENV__.module, :on_filter_packet, 50)
    :ok
  end

  def stop(host) do
    info('Stopping ejabberd module Filter Packet Demo')
    Ejabberd.Hooks.delete(:filter_packet, :global, __ENV__.module, :on_filter_packet, 50)
    :ok
  end

  def on_filter_packet({from, to, xml={:xmlel, "message", attributes, children}} = packet) do
    info("Filtering message: #{inspect packet}")

    new_children = Enum.map(children, fn(child) ->
      case child do
        {:xmlel, "body", [], [xmlcdata: text]} ->
          {:xmlel, "body", [], [xmlcdata: String.upcase(text)]}
        _ -> child
      end
    end)

    {from, to, {:xmlel, "message", attributes, new_children}}
  end
  def on_filter_packet(packet), do: packet
end

Go ahead and compile it and restart the server, and let’s send some messages.

(( do that, note they are upcased ))

Summary

With that little bit of code, we’re able to modify the behaviour of this ejabberd server with respect to messages being sent. Obviously you could imagine how to do more interesting things here, but this was a pretty simple introduction into packet filtering with ejabberd. See you soon!

Resources

by Mickaël Rémond at March 25, 2015 15:44

buddycloud

Announcing Buddycloud-VM: everything you need to run Buddycloud on premises.

The Buddycloud virtual machine helps developers test and deploy Buddycloud.

While Buddycloud hosting is a great way to start building and testing in-app communication, sometimes you need more flexibility than cloud hosting.

The buddycloud-vm is a good way to spin-up your own on-premises messaging stack.

We have designed the buddycloud-vm to be flexible enough to build and deploy into your workstation or to deploy remotely into your own datacenter/ Amazon/Google/Digital Ocean servers.

Grab the latest version off Github. Community support is always available in the Buddycloud chatroom.

by imaginator at March 25, 2015 13:49

March 23, 2015

The XMPP Standards Foundation

Board goals for 2015

When our newest Board of Directors were elected, they decided that they wanted to set some goals against which their achievements as Board members could be measured.

And so this journey began…

We started by asking the community what THEY cared about and what they wanted the Board to focus on.

We took this information, turned it into measurable objectives and then asked the community to vote – what did they think the most important areas to focus on? There was a lot of debate here, and we listened – the measurables could have been something else, there are other ways of looking at this etc – but, we had to commit to something or a year on we would still be working how to measure what we were doing!

And this is what got decided (the meeting minutes can be found here.)

% based goals

 percentage copy.jpg

We recognised that there were two top scorers – website traffic and membership engagement. While membership engagement is of obvious importance, the Board felt that engagement would be covered by other activities and was possibly too inwardly focussed.

  • Decision: Website traffic
Binary goals
binary copy.jpg
For our binary goal, there was a clear leader, although a difficult goal! How we achieve this goal needs more discussion, but the decision was unanimous.
  • Decision: IOT strategy
Soft goals
soft copy.jpg
While the ‘Benefits of federation’ was clearly the highest rated objective for our “soft goal”, the Board recognised that this was simply an aspect of XMPP positioning.
  • Decision: XMPP positioning

And that is where we are at. The % based goal and XMPP positioning are both being worked on at the moment, through the development of our new website.

We will keep you posted with our progress…

by laura at March 23, 2015 09:51

March 20, 2015

ProcessOne

ejabberd 15.03

ejabberd 15.03 is yet another important release. We have added fixes and some major improvements.

You can learn more about the changes and roadmap by meeting part of the team in upcoming ejabberd San Francisco Meetup.

New features

Websocket

Websocket support is among the major new features introduced in this release. You can write speedy XMPP web clients. This web support has been tested on large deployments and is extremely fast, with very low latency.

More details on ejabberd Guide – Websocket

Customizable session backends

We have introduced a new major feature to give more flexibility in the way sessions are managed in ejabberd. In the past, session were managed in Mnesia because it was the best compromise between speed, latency and scalability. However, ejabberd is deployed on a large variety of usage patterns and platform types and sizes. We thus have decided to provide more flexibility to accommodate with various use cases. For most deployments Mnesia is still the default choice and best backend to store sessions. For corporate deployments that need to get easy access to online users and status from other components, we provide a SQL backend for live sessions storage. Finally, if you want to avoid duplicating session across nodes to deploy a larger cluster, you can store your session information in a central, fast, in-memory backend like redis.

This improves scalability or flexibility depending on your platform type.

Security improvement: SCRAM support for SQL authentication backend

If you use the default ejabberd SQL authentication backend, you can now enable password encryption in the database using the standard SCRAM approach. We also provide a tool to migrate your existing authentication database to the new SCRAM secure scheme.

Development community and Elixir improvements

ejabberd 15.03 is also the continuation of 15.02 in the way it simplifies the development and management of contributed modules. The community is growing with more code being contributed by third party developers. You can already find many modules contributed by the community. And now you can even install contributed modules without having developer skills or module compilation.

Interest around ejabberd has been accelerating with the introduction of Elixir. This release improves Elixir support. Moreover, you can now write ejabberd tests in Elixir and they are ran transparently with the rest of the test suite.

Package management

This feature allows you to install easily ejabberd contributed module, with a simple command like:

$ ejabberdctl module_install modulename

You can find more details on this blog post: Easy installer and structure for ejabberd contributed modules

Simple add cluster command

With our constant desire to simplify deployment we added a new ejabberdctl command to add a node in a cluster in a single command. Those who went to the process of setting up a cluster will certainly love this new command:

$ ejabberdctl join_cluster ejabberd@existingnode

More details here: Adding a node in a cluster

Changelog overview

As a summary, here is the high level changelog:

  • Add support for WebSocket
  • Flexible session management with multiple backends: Mnesia/SQL/Redis or custom backend for session manager
  • Security improvement with SCRAM based password encryption in SQL authentication backends.
  • Package management for ejabberd contributed modules.
  • Improved Elixir experience
  • Automatic clustering scripts
  • Added missing index on database
  • Important updates on the documentation, with the launch of a new documentation site: docs.ejabberd.im
  • Several other bugfixes

MySQL database structure improvement

We were missing an index on privacy list in the default MySQL schema. The database schema has been updated.
If you want to apply the changes on a running instance, here is the SQL command to issue:

CREATE INDEX i_privacy_list_data_id USING BTREE ON privacy_list_data(id);

Feedback

As usual, the release is tagged in the Git source code repository on Github.

The source package and binary installers are available at ProcessOne.

If you suspect you found a bug, please search or fill a bug report on Github.

by Christophe Romain at March 20, 2015 18:32

The XMPP Standards Foundation

Summit 17 – the presentations

A slightly tardy share, but we have the presentations from Summit 17 in Brussels starting to trickle in!

As more come in, this post will get longer (and hopefully have a more permanent home on the new site) but here we go:

XMPP Research

With their active blog xmppresearch.org, researchers from RWTH Aachen University and TU Dresden are contributing to an ongoing collection of academic works around XMPP, including a high-quality bibliography, demos and reviews. Domink Renzel presented their work and their goals to the Summit members.

Blogging via XMPP

Sergey Dobrov walked us through federated blogging and a combination of XMPP & PubSub/PEP. The presentation includes a call-out for help, and hwo you can get involved.

 

We would love to showcase more of the presentations, so if you have anything from the Summit you would like to share, please get in touch!

by laura at March 20, 2015 10:23

March 19, 2015

buddycloud

In-app messaging: what’s next?

image

(photo credit: Doc Searls - silos)

Benedict Evans writes that the three phases of messaging were always about unbundling expensive services based on price arbitrage. But what comes next?

Phase 1: Unbundling International voice calling. Remember how prohibitive calls across a border were? Skype won this!

Phase 2: Unbundling Mobile-based messaging. SMS was squeezed by BBM and similar services. The competing services force operators to compete: 10c/SMS collapses to “unlimited SMS” packages. Line, WhatsApp and a hundred others messaging services bloom.

We are now at Phase 3

Phase 3: The generic data layer. “Why can’t we just communicate between services?” To use Benedict’s example, “Why is it that if I use a cab service app I can only talk to the driver by a PSTN voice call or SMS? Why does a restaurant booking app send me out to the phone dialer?” Phase 3 will play out with Apps just as WhatsApp will, but with  live voice and SMS, being unbundled. WebRTC goes some way to providing a data layer between devices. WebRTC is the a BYOS (bring your own signalling) transport.

Messaging is quite hard to get right which is why tools like Facebook Developer tools, Layer, ChatCenter and Buddycloud exist; they help developers add messaging to apps.

When every mobile and web developer can easily add messaging to their app, the power of WhatsApp’s et al.’s ad-hoc messaging communities will shift to specialist apps. 

The next unbundling will start on the long tail of messaging: if the fat head of messaging is WhatsApp and Line, the long tail is the tens of thousands of apps that include a way for users to communicate. The long tail includes the AirBnB app where a guest communicates with their host, the Uber app that connects the driver with the passenger and the kidney-disease-support-group app where patients message each other. And thousands more.

The unbundling, as with the previous two phases, will be bottom-up: developers experimenting on weekend projects, apps emerging from studios, and the “fat-head” of mainstream messaging apps being replaced.

Messaging is now free

Now we’re in a world where messaging is essentially free (both to use and to run) and we’re also in a world where every developer likes to invent their own messaging service. There’s also a race to offer ever cheaper messaging backends to developers. With WebRTC built into every browser, we can assume we’ve reached free. If one subscribes to Peter Thiel’s Zero to One thinking: this would be the globalisation stage of messaging.

What’s coming next

Phase 4: unbundling the silos

To understand how the next stage plays out, it’s useful to look 30-odd years ago at the roots of, arguably the world’s most successful app, email.

Back in, Eric Allman's sendmail pulled together email from the UUCP network, ARPAnet mail and BerkNet mail systems into one unified system. Users no longer needed to switch between systems to contact other users outside of their mail silo.  Eric created a flattened namespace and service to route messages between silos: he federated incompatible messaging silos. And while some of the addressing looked odd (domain!user), users didn't have to log in and out of different systems to communicate. Eric's design also meant that organisations could easily join the mail network simply by using an agreed-upon protocol.

The ecosystem of email succeeded because it was an open protocol, implementable by others (sendmail was open source) and most importantly it federated between sites. Back in the pre-cloud days it was also “on-premises”.

Applying this sea change from 30 years ago to messaging: messaging will be apps built on a flat namespace with backend services that interconnect. The specialised silos will still exist but interconnect (Compuserve mail eventually interconnected with AOL mail and even SMTP based email).

No more: I’m greg99 on this service but if you want to reach me on Wire then I’m greg.watson and on this other service I’m known by my phone number. The future will be just greg@example.com everywhere: greg@example.com  on Future-instagram(tm), greg@example.com on future-twitter(tm) and  greg@example.com  on cat-social-network(tm).  Some might call this “bring your own identity” (BYOI).

Summary: The fourth phase of messaging will be federation of the silos using an open protocol with a flat user namespace.

Working on the Fourth Phase

At Buddycloud we’re trying to work on this fourth phase, a “generic data layer” and signaling for messaging. Developers can add the stack to their apps and save development time. Moreover they plug into a larger ecosystem of existing users and services.

If Buddycloud does its job well, we help other companies grow the ecosystem too (for example Surevine Ltd produces a really nice Buddycloud frontend for security-sensitive customers).

From working with customers, we have noticed is that it’s really important for customers to be able to extend messaging.  Developers seek more than one-size-fits-all messaging. For example we find that developers each want different message formats and different application logic on the backend.

We also notice that, security is really important - this usually plays out as customers wanting on-premises deployments (for example, the finance or healthcare industries).

Another thing that we have discovered: communication needs to extend beyond the firewall of each enterprise: Imagine only being able to email people inside your organisation. (Remember only being able to email other uses on compuserve - never outside?) It’s quite conceivable to need to communicate with a supplier. When viewed like this network federation is a natural extension of any communication network.

We’re working on Building the fourth phase of communication at Buddycloud. Realtime messaging and video calling between users on any network, anywhere in the world should become as natural as email.

PS: we’re looking for smart engineers to join the team.

by imaginator at March 19, 2015 07:07

March 16, 2015

Peter Saint-Andre

Self-Patronage

A friend recently pointed me to a fascinating essay over at the Atlantic entitled The Death of the Artist — and the Birth of the Creative Entrepreneur by William Deresiewicz. After exploring the major financial models for artistic creation over the centuries (classic patronage, aristocratic independence, the never-popular starving artist, twentieth-century credentialed professionalism, and just recently a kind of hustling entrepreneurship), the author wonders if the artist as entrepreneur provides a model under which it is possible to create art that can serve as as a "vessel for our inner life" (since artists who are hustling for a living might tend more toward entertainment than deep and lasting art).

March 16, 2015 00:00

March 13, 2015

ProcessOne

Easy installer and structure for ejabberd contributed modules

Ejabberd comes with a lot of modules, but sometimes you may need an unsupported feature from the official sources or maybe you need to write your own custom implementation for your very special needs.

For many years, such contributed modules are stored on ejabberd-contrib repository.

However, these modules required manual compilation. This means having Erlang/OTP installed, a base knowledge of how to compile ejabberd modules and manual maintenance when ejabberd’s api is updated over time.

Complex operations to manage ejabberd contributed modules is now behind us. ejabberd is now able to fetch module sources by itself, compile with correct flags and install in a local repository, without any external dependencies. You now longer need to know Erlang and have it installed in order to use the contributed modules. This works with ejabberd modules written in Erlang and will also support new Elixir modules.

ejabberdctl module_install

Before getting started, you need to use ejabberd official repository on Github. We are gathering feedback before you see that command in the next stable release. It will work with ejabberd HEAD, starting from version 15.02.77 (aa1250a). Once you have an ejabberd compiled from source installed, you can start playing with the commands.

As a user, this is how it works:

First you need to get/update the list of available modules:
$ ejabberdctl modules_update_specs

Then you can list available modules
$ ejabberdctl modules_available
...
mod_admin_extra Additional ejabberd commands
mod_archive Supports almost all the XEP-0136 version 0.6 except otr
mod_cron Execute scheduled commands
mod_log_chat Logging chat messages in text files
...

Let’s give mod_cron a try:
$ ejabberdctl module_install mod_cron
ok

This command installs mod_cron from ejabberd-contrib repository. An example default configuration is installed in:

$HOME/.ejabberd-modules/mod_cron/conf/mod_cron.yml

All you have to do is to copy paste the module and add the values in there in the proper place in your ejabberd.yml config file. Be careful, the snippet can include ACLs, listeners and module configuration, that you have to put in the right place in your config file.

Now, check your new module is installed:
$ ejabberdctl modules_installed
mod_cron

And finally, you can remove it:
$ ejabberdctl module_uninstall mod_cron
ok

What’s next

Please note this is provided as a beta version. We want the work in progress to be released early to gather feedback from developers and users.

For now, you need to edit the configuration snippet provided in module’s conf directory and copy it into your ejabberd’s main configuration. Then you’ll need to restart ejabberd or manually start the module.

However, our plan is to keep iterating on the tool and to make our best to make module installation as easy as possible and avoid need to change main configuration: ejabberd should be able to include module configuration snippets on the fly in a near future.

As a developer, how can you provide an ejabberd contribution ?

As a developper, you still need Erlang and Ejabberd if you install everything from sources, but you can even not need Erlang if you installed ejabberd from official ProcesOne installer. The official installer includes everything needed to build ejabberd modules on its own.

First you can work on your own module by creating a repository in $HOME/.ejabberd-modules/sources/mod_mysupermodule, and creating a specification file in YAML format as mod_mysupermodule.spec (see examples from ejabberd-contrib). From that point you should see it as available module.

Before commiting your code, you should check if your module follows the policy and if it compiles correctly:
$ ejabberdctl module_check mod_mysupermodule
ok

if all is OK, your’re done ! Else, just follow the warning/error messages to fix the issues.

You can keep your repository private in this location, ejabberd see it as an available module, or you can publish it as a tgz/zip archive or git repository, and send your spec file for integration in ejabberd-contrib repository. ejabberd-contrib will only host a copy of your spec file and does not need your code to make it available to all ejabberd users.

Conclusion

We have a bright vision for the ejabberd modules ecosystem and this is just the first step. We are waiting to hear from you. With your feedback, your ejabberd installation with instantly become much much more powerful.

by Christophe Romain at March 13, 2015 17:16

March 12, 2015

ProcessOne

Archipel introduction at ejabberd San Francisco Meetup

The nice guys from the Archipel project will be introducing the project on march 25th at ejabberd San Francisco Meetup.

If you do not yet know Archipel, you should give it a look as it is one of the killer project running on top of ejabberd. Every sysadmin using XMPP as a chat client had a dream at some point: Wouldn’t it be cool to be able to control all the servers of my organisation by chatting with them, getting status update, etc.

Archipel makes that dream come true and much more. Archipel is a solution to manage and supervise virtual machines. It is fully based on XMPP for the realtime component and thus make an heavy use of ejabberd nicest features.

Here is a teaser video about Archipel:

If you are in the Bay Area on the 25th, do not miss the opportunity to meet them. You can register for the meetup here: ejabberd San Francisco Meetup #1.

by Mickaël Rémond at March 12, 2015 12:20

March 11, 2015

Tigase Blog

Tigase JaXMPP 3.0.0 Release

Tigase JaXMPP 3.0.0 Client Library has been released! This release includes many major changes, as well as numerous bug fixes. Binaries are available from the project's files section.

by wojtek at March 11, 2015 08:42

March 10, 2015

ProcessOne

ejabberd and dependencies: major set of open source repositories

Since 2002, ejabberd established itself as a major Erlang project. People learn Erlang because of ejabberd. For this reason alone, ProcessOne is one of the major contributors in the open source Erlang community, along with Erlang OTP itself (heavy investment from Ericsson), Elixir mainly from Plataformatec, Riak from Basho, Cowboy from NineNines, ChicagoBoss and Zotonic.

However, ejabberd is just the tips of the iceberg. When we decide to make ejabberd more modular in 2013, we split the code base into small reusable components. They are now “ejabberd dependencies”, but of course count as major contribution from ProcessOne as well and can be reused and improved independently.

This post is a walkthrough all ejabberd dependencies, as multiple spin-off effort of ejabberd development process:

ejabberd dependencies

ejabberd code based is split among several repositories so effectively ejabberd code is much more than what is in its primary repository.

Required dependencies

The main ejabberd repository is processone/ejabberd

There is hundreds of forks, but we actively maintain ejabberd to make it the most reliable and up to date version. This is thus your best starting point.

When you build ejabberd yourself, the build chain will download a few Erlang dependencies:

  • processone/cache_tab: Flexible in-memory Erlang caching module.
  • processone/eiconv: Native iconv driver for Erlang. This is use for fast character encoding conversion.
  • processone/xml: Fast native Expat based Erlang XML parsing library. XML is the core of XMPP so we needed to provide the fast and more robust XML parsing stack as possible. It means that if you are looking for a great XML parser, reusing p1_xml is probably a great idea.
  • processone/stringprep: Fast and efficient Erlang Stringprep native driver. Stringprep is heavily used in XMPP to define encoding rules of various XMPP objects.
  • processone/p1_yaml: Native Erlang interface to libyaml, for fast robust YAML parsing. This is needed by our new config file format.
  • processone/zlib: Native zlib driver for Erlang. Used for fast / efficient stream compression.
  • processone/tls: Erlang native driver for TLS / SSL. It is build for performance and is more scalable that Erlang SSL driver. If your Erlang server is handling heavy load and is using TLS, we strongly recommand you check / compare with this driver.
  • processone/p1_sip: ProcessOne SIP protocol support to add SIP-based voice capabilities to ejabberd. If you have ever studied SIP, you know this is huge :)
  • processone/stun: Implementation of Session Traversal Utilities for NAT. It is used for XMPP and SIP media capabilities, to help client discover their visible IP address and allow them to get in touch through NAT. This is basically useful for voice and file transfers.
  • processone/p1_utils: This is extra Erlang modules developed for ejabberd but that can be useful in other Erlang applications.
  • processone/p1_logger: Logger wrapper to allow selecting your prefered logger at build time.
  • basho/lager: Erlang logger module.
  • DeadZen/goldrush: Small Erlang app that provides fast event stream processing. It is used by lager.
  • vaxelfel/eHyperLogLog: HyperLogLog, a distinct values estimator, in Erlang. Used for analytics.

Optional dependencies

Then, we use a few other dependant repositories that may be used if you have enables support in the configure script.

Here are the dependancies for relational database support:

Here are the dependencies for Elixir support:

Here are the dependencies for Riak support:

Conclusion

This is just a taste of what ProcessOne has been building over the past 13 years. I could also mention other major contribution as Tsung, the most scalable and affordable benchmarking platform available. That can be used for testing large scale web or XMPP platforms.

by Mickaël Rémond at March 10, 2015 15:02

March 09, 2015

Ignite Realtime Blog

Smack and Openfire at GSOC 2015 -- Smack 4.1.0-rc3 available -- First preview alpha of Smack 4.2 available

The Ignite Realtime community is participating, as part of the XMPP Standards Foundation (XSF) GSOC organization, in this year's Google Summer of Code. Besides various Openfire projects, there are two Smack related ones:

 

All XMPP project ideas can be found at the XSF wiki: Summer of Code 2015 - XMPP WIKI

 

 

Furthermore we are proud to announce the availability of Smack 4.1.0-rc3, which should fix the last outstanding issues with Stream Management (XEP-198).

 

 

Also the first alpha version of Smack 4.2 has been released. Smack 4.2.0-alpha1 is basically Smack 4.1.0-rc3 with two major modifications that introduce the first big API changes in Smack 4.2:

  • Smack is now interruptible, which means that most methods throw a InterruptedException. This allows users to cancel (long-running) blocking I/O operations by just interrupting the thread performing those actions.
  • Smack uses now the Jid type (from jxmpp-jid) everywhere a Jid is expected. This prevents programming and users errors caused by an invalid JID String, since JIDs have pretty strict requirements regarding their String representation. Also jxmpp-jid does cache the result of the expensive String operations required to perform on JID Strings, which results in increased performance.

by Ignite Realtime Blog (igniterealtime@jiveon.com) at March 09, 2015 07:20

Fanout Blog

Stateless WebSockets with Express and Pushpin

One of the most interesting features of the Pushpin proxy is its ability to gateway between WebSocket clients and plain HTTP backend servers. In this article, we'll demonstrate how to build a WebSocket service using Express as the HTTP backend behind Pushpin.

...

by justin at March 09, 2015 05:17

March 06, 2015

ProcessOne

ejabberd San Francisco Bay Area Meetup

We have a very large number of users in San Francisco Bay Area. ejabberd scalability and flexibility is a perfect fit for startup and we are proud to be powering realtime messaging in the Silicon Valley. As such we have been asked many time to host an event where people working on ejabberd, XMPP, Erlang and Elixir for realtime messaging can meet each other and discuss.

That’s now done and we are very happy to be able to launch ejabberd San Francisco Bay Area Meetup. The first meetup will take place on the 25th of march 2015 in San Francisco. Registration is free and you are welcome to join: ejabberd SF Bay area Meetup #1

ejabberd_sanFrancisco

If you attend it would be very good if you could have a slide ready to introduce your project in a few minutes. That’s a great way to get exposure and feedback on your architecture, design and features. If you just come to learn and discover, do not be shy, that’s fine as well and you are welcome.

I (Mickaël Rémond, Founder of ProcessOne, ejabberd Lead), will introduce the new features introduce in ejabberd v15.02 and v15.03. I will present the roadmap to show what is the next frontier for ejabberd project. I am also preparing a surprise announcement with the team, so be sure not to miss the event.

See you in a while in San Francisco !

by Mickaël Rémond at March 06, 2015 15:38

Ejabberd available as a buildroot package

Johan Oudinet contributed a new ejabberd package in buildroot
sponsored by Green Communications.

Buildroot can generate any or all of a cross-compilation toolchain, a root filesystem, a kernel image and a boot loader image. The generated root filesystem contains a libc (uClibc, glib, eglibc or musl), busybox and some extra packages. Now buildroot allows to include Erlang and ejabberd in the generated root filesystem.

This makes very easy to build a custom and robust xmpp server for your embedded hardware, router or appliance, as buildroot is designed with simplicity in mind.

by Christophe Romain at March 06, 2015 08:05

March 04, 2015

ProcessOne

ejabberd and the Google Summer of Code 2015

ejabberd project and developers are involved as mentors in Google Summer of Code 2015 initiative. This article explains what it could mean for you as a student wanting to contribute to our project.

What is Google Summer of Code ?

Google Summer of Code (GSoC) is an annual program in which Google awards stipends (US$5,500) to all students who successfully complete a requested free and open-source software coding project during the summer.

We have been contributing ideas and will be helping students enrolled in two distinct mentoring organisations:

Students are free to get involved in suggested ideas, but can also propose new project ideas on their own.

Why get involved in GSoC, working on ejabberd ?

For a student, GSoC is a great opportunity to learn new skills, learn to work with a team of experienced developers, help open source projects and get a fair compensation.

ejabberd is one of the most used XMPP server in the world, deployed on huge scale deployments in large corporations. This is a unique chance to get your code running for tens of millions users and have a real impact with your code.

The suggested ideas should be quite interesting and challenging but still manageable to be completed during the summer. Of course, we are open to your own suggestions.

Here are a few of the idea we have put together, in no particular order:

So, what is the process ?

You will need to submit a proposal on GSoC website, for either XSF or Beam Community. Students should pick their projects and submit proposals from 16th to 27th March. Do not be afraid, you are not alone and, as experienced mentors, we are here to help. You can get in touch with our team (On XMPP groupchat, of course), in the chat room ejabberd@conference.process-one.net.

Please, make sure that you are eligible before investing time on the project. Details are available on Google Summer of Code 2015 Student Participant Agreement.

All the ejabberd community is looking forward working with you !

by Mickaël Rémond at March 04, 2015 11:18

March 03, 2015

The XMPP Standards Foundation

XMPP in Google Summer of Code 2015

We’ve just had the great news that Google have again accepted the XSF to mentor XMPP-related projects in the Google Summer of Code this year. GSoC is a programme whereby Google pays students a stipend to work on open source projects for the summer, and when we’re able to participate in this it’s a highlight of the year for us. If you are, or know any, talented students with an interest in realtime communication systems we’ve got a selection of interesting projects at http://wiki.xmpp.org/web/Summer_of_Code_2015. Our page on the GSoC site is at https://www.google-melange.com/gsoc/org2/google/gsoc2015/xmpp, and for more information on GSoC in general please see the Google site at https://www.google-melange.com/gsoc/homepage/google/gsoc2015. Student applications open on March 16th but that’s no reason to delay – come and chat with us about our possible projects with the contact venues listed on http://wiki.xmpp.org/web/Summer_of_Code_2015.

We’ve got the ideas, we’ve got the mentors, all we need are a few students to turn this into a great summer for XMPP.

by Kev at March 03, 2015 11:28

ProcessOne

Radio, News and Sport notifications on a huge scale at the BBC

Mickaël Rémond explains how the BBC have been using large scale push notification service Boxcar to distribute radio content, breaking news and sport football alerts on a huge scale.

Thanks to BBC News and Sport teams for providing many of the slides and other material.

by Mickaël Rémond at March 03, 2015 10:39

buddycloud

Setting up Your "Office Stack"

Open Source Principles versus Getting Things Done

Imagine you are starting a new company: you have a team in-house and around others scattered around the world.

I set up the tools for another company 6 years ago.  And was doing it again recently for Buddycloud. And how times have changed.

In light of recent spying events, code developed in a transparent manner (usually open source) is increasingly important. Being free both in dollar terms and in time spent talking to a sales team is also a huge win. But setting up and managing an open source office stack can quickly become a time-sink.

Here’s a quick retrospective to how we used to (about 6 years ago) set up team collaboration. And how we’ve done it today at Buddycloud HQ.

Source Code and Issue Tracking

Then: Apache+SVN+LDAP+WebSVN+Trac

Details are sketchy, but I remember the pain level was high. “Back in the day” one rolled with  subversion <shudder if you will>, fronted by Apache and some kind of LDAP authentication. That got you source control.

For bonus points and to view your code, you’d install WebSVN. Oh, dark days! Of course, you’d want to track bugs: Trac was the go-to tool for this. And came with a whole new set of dependencies. These were all cutting edge back then.

Now: 

image

Let’s be clear - we weren’t going near SVN for source code wrangling. All of the Buddycloud repositories are based on GitHub. It’s hard to remember the pre-GitHub existence. As one of the best platforms to share code, GitHub offers us the chance to share all of our projects online, forming a straightforward flow to collaborate together in solving issues, commenting proposals and improving the code of our projects. And there’s no need to configure apache virtual hosts or buy SSL certificates for svn.example.com.

Currently, we have nearly 40 repositories. And almost zero admin overhead.

Team Organisation

Then: Hire a project manager

Just a few years ago one would hire full-time cat-herders^WW project managers to look after a product team. Their task was to help the team answer “what should I do next?”, “what’s the big picture?”, “what are my colleague working on?”

To answer these questions would take lots of meetings. Some of the worldwide team would be waking up early to jump on team calls. And some would be staying up late to synchronise plans. Add in meetings digging into deep-hack-mode time and you quickly have a non-developer friendly environment.

Now:

image

Trello tasks are added to different topic boards, you tag your work colleagues to them, set up due dates so you get reminded when you have to get your tasks finished and get notifications according to your interests, amongst many other features.

There’s 101 organisation tools out there: We use Trello because of its simple, but effective approach as an agile task tracking/planning tool [and it’s free].

I also highly recommend using Trello on your phone to get into a GTD-type workflow and free up your mind: quickly capture thoughts and tasks for when you are back at your desk.

Email, Calendaring and Documents

Then: roll it yourself: Postfix, Cyrus, Amavisd, OpenOffice and trying new open-source calendaring apps every week.

There was a day when setting up an office involved: Order server from Dell, Install Linux, Setup Postfix, hope you weren’t on a DNSBL, configure something else in /etc that you kinda understood but could never be totally sure about, tweak, configure some more.

And then you’d wonder when there was going to be a good calendering solution released as open source. And be sorely reminded that the solution was called Exchange. Then you’d hope you could get by without calendaring.

Now:

image

We like open source: the Buddycloud stack is all released as open source. But we’re also keen to spend our time on adding value to Buddycloud. Not tweaking spam-rules. Or looking at Exchange CAL costs. So we switched over to Google Apps: Gmail for email. Calendar for planning our meetings and organizing our schedules. Drive for storing and sharing files amongst the team. Hangouts to communicate with far away team members or developers of our community.

We’d rather be using open source. But we’d rather-more be spending our time on shipping Buddycloud code.

(BTW: We started having a Hangout Buddycloud’s Developer Call every Tuesday at 2:30pm GMT+1. This is aimed at bringing other Buddycloud developers and integrators together to share and get help from the dev-team and each other.)

Mailing Lists

There are two uses for mailing lists:

  • discussions: we do a lot of consensus building on buddycloud-dev. A good mailing list helps us work through an issue knowing that the solution is well crafted.
  • announcements: [strangely] a bunch of people seem to still want to get news updates through email. And we are not going to judge them for that.

Then: Mailman + Postfix

Over the years, mailman was the way to power mailing lists. It’s good software. But installing Mailman involved debugging messages like “Premature end of script headers” or “Mailman CGI error!!!” And things always felt fragile. I’d tip-toe around our email stack with the through “perhaps I’ll hold off upgrading Postfix incase Mailman stops working”.

I’d have paid for a branded-hosted solution. It would have been nice to have someone else looking after this for us.

Now:

image

To solve the discussion list problem - we used Google Groups. Our asynchronous communication means we can work without interruption. Developers can also sign-up on a modern web page. And others can just chip in their 2c through the website without needing to join a mailing list. Yes, I feel like a sell-out to the pure open source solution. Yes, I enjoy my free time. As I age I value the latter more.

image

And for announcements-only lists, MailChimp helps us manage lists of users, Buddycloud-integrators and fans. And shoots off emails to them with updates. List is here if you are interested in a more read-only relationship.

Social Media

Then: We’d go down to the pub or beer garden and tell our friends what we were building. They’d tell their friends and the physical “social graph” would relay the message. Or we’d make a post on Slashdot.

Now:

image

Everyone has their own flavour of social network. Buffer spools up announcements and pushes them out to each network. Right now, one Buffer post = a post on Twitter, Facebook, LinkedIn and Google+. And it gives us metrics on reach that keep Mizar in Marketing happy.


A lot has changed in just 5 years: complexity has increased and we’re pushed towards solutions that wrap up the complexity in hosted offerings. Us developers and open source advocates like our principles. And tinkering with new software is a great procrastination technique.

But we also like hosted solutions that let get on with tasks further up the stack.

BTW, Buddycloud builds a hosted messaging stack. Build on open source. Released as open source. And you can install it yourself and tinker with settings. Or just use our hosted option and do something else with your free time.

What are you using for your “office stack”?

by mizarf at March 03, 2015 08:55