diff --git a/LICENSES b/LICENSES
index 3c8a7237a..9d371c410 100644
--- a/LICENSES
+++ b/LICENSES
@@ -43,6 +43,7 @@ otherwise.
- static/themes/default/img/network-internet.svg :: [[http://tango.freedesktop.org/][Public Domain]]
- static/themes/default/img/network-wireless.svg :: [[http://tango.freedesktop.org/][Public Domain]]
- static/themes/default/icons/deluge.png :: [[https://upload.wikimedia.org/wikipedia/commons/thumb/8/85//Deluge-Logo.svg/2000px-Deluge-Logo.svg.png][GPL]]
+- static/themes/default/icons/diaspora.png :: [[https://upload.wikimedia.org/wikipedia/commons/thumb/8/85//Deluge-Logo.svg/2000px-Deluge-Logo.svg.png][Publc Domain]]
- static/themes/default/icons/infinoted.png :: [[https://github.com/gobby/gobby/blob/master/COPYING][ISC]]
- static/themes/default/icons/ikiwiki.png :: [[https://ikiwiki.info/][GPL-2+]]
- static/themes/default/icons/jsxc.png :: -
diff --git a/actions/diaspora b/actions/diaspora
new file mode 100644
index 000000000..0714a64a3
--- /dev/null
+++ b/actions/diaspora
@@ -0,0 +1,61 @@
+#!/usr/bin/python3
+# -*- mode: python -*-
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+Configuration helper for diaspora* web client.
+"""
+
+import argparse
+
+from plinth import action_utils
+
+
+def parse_arguments():
+ """Return parsed command line arguments as dictionary."""
+ parser = argparse.ArgumentParser()
+ subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
+
+ subparsers.add_parser('enable', help='Enable diaspora*')
+ subparsers.add_parser('disable', help='Disable diaspora*')
+
+ return parser.parse_args()
+
+
+def subcommand_enable(_):
+ """Enable web configuration and reload."""
+ action_utils.webserver_enable('diaspora')
+
+
+def subcommand_disable(_):
+ """Disable web configuration and reload."""
+ action_utils.webserver_disable('diaspora')
+
+
+def main():
+ """Parse arguments and perform all duties."""
+ arguments = parse_arguments()
+
+ subcommand = arguments.subcommand.replace('-', '_')
+ subcommand_method = globals()['subcommand_' + subcommand]
+ subcommand_method(arguments)
+
+
+if __name__ == '__main__':
+ main()
+
diff --git a/data/etc/plinth/modules-enabled/diaspora b/data/etc/plinth/modules-enabled/diaspora
new file mode 100644
index 000000000..1ae682dfd
--- /dev/null
+++ b/data/etc/plinth/modules-enabled/diaspora
@@ -0,0 +1,2 @@
+plinth.modules.diaspora
+
diff --git a/plinth/modules/diaspora/__init__.py b/plinth/modules/diaspora/__init__.py
new file mode 100644
index 000000000..ea101be03
--- /dev/null
+++ b/plinth/modules/diaspora/__init__.py
@@ -0,0 +1,106 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+from django.utils.translation import ugettext_lazy as _
+
+from plinth import actions, action_utils, cfg, frontpage, service as service_module
+
+version = 1
+
+title_en = 'Federated Social Network (diaspora*)'
+
+title = _(title_en)
+
+depends = ['apps']
+
+service = None
+
+managed_services = ['diaspora']
+
+managed_packages = ['diaspora']
+
+description = [
+ _('diaspora* is a decentralized social network where you can store and control your own data.'),
+
+ _('When enabled, the diaspora* pod will be available from '
+ '/diaspora path on the web server.')
+]
+
+
+def init():
+ """Initialize the Diaspora module."""
+ menu = cfg.main_menu.get('apps:index')
+ menu.add_urlname(title, 'glyphicon-thumbs-up', 'diaspora:index')
+
+ global service
+ setup_helper = globals()['setup_helper']
+ if setup_helper.get_state() != 'needs-setup':
+ service = service_module.Service(
+ managed_services[0], title, ports=['http', 'https'],
+ is_external=True, is_enabled=is_enabled, enable=enable,
+ disable=disable)
+
+ if is_enabled():
+ add_shortcut()
+
+
+def setup(helper, old_version=None):
+ """Install and configure the module."""
+ helper.install(managed_packages)
+ helper.call('post', actions.superuser_run, 'diaspora', ['enable'])
+ global service
+ if service is None:
+ service = service_module.Service(
+ managed_services[0], title, ports=['http', 'https'],
+ is_external=True, is_enabled=is_enabled, enable=enable,
+ disable=disable)
+ helper.call('post', service.notify_enabled, None, True)
+ helper.call('post', add_shortcut)
+
+
+def add_shortcut():
+ frontpage.add_shortcut('diaspora', title, url='/diaspora',
+ login_required=True)
+
+
+def is_enabled():
+ """Return whether the module is enabled."""
+ return action_utils.webserver_is_enabled('diaspora-plinth')
+
+
+def enable():
+ """Enable the module."""
+ actions.superuser_run('diaspora', ['enable'])
+ add_shortcut()
+
+
+def disable():
+ """Disable the module."""
+ actions.superuser_run('diaspora', ['disable'])
+ frontpage.remove_shortcut('diaspora')
+
+
+def diagnose():
+ """Run diagnostics and return the results."""
+ results = []
+
+ results.append(action_utils.diagnose_port_listening(8112, 'tcp4'))
+ results.append(action_utils.diagnose_port_listening(8112, 'tcp6'))
+ results.extend(action_utils.diagnose_url_on_all(
+ 'https://{host}/diaspora', check_certificate=False))
+
+ return results
diff --git a/plinth/modules/diaspora/forms.py b/plinth/modules/diaspora/forms.py
new file mode 100644
index 000000000..3d11f163c
--- /dev/null
+++ b/plinth/modules/diaspora/forms.py
@@ -0,0 +1,25 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+from django import forms
+
+class DiasporaForm(forms.Form):
+ """diaspora* configuration form."""
+ enabled = forms.BooleanField(
+ label='Enable diaspora',
+ required=False)
+
diff --git a/plinth/modules/diaspora/tests/__init__.py b/plinth/modules/diaspora/tests/__init__.py
new file mode 100644
index 000000000..e784d0bf1
--- /dev/null
+++ b/plinth/modules/diaspora/tests/__init__.py
@@ -0,0 +1,16 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
diff --git a/plinth/modules/diaspora/urls.py b/plinth/modules/diaspora/urls.py
new file mode 100644
index 000000000..4c2b51b20
--- /dev/null
+++ b/plinth/modules/diaspora/urls.py
@@ -0,0 +1,34 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+URLs for the Diaspora module.
+"""
+
+from django.conf.urls import url
+
+from plinth.modules import diaspora
+from plinth.views import ServiceView
+
+
+urlpatterns = [
+ url(r'^apps/diaspora/$', ServiceView.as_view(
+ description=diaspora.description,
+ diagnostics_module_name="diaspora",
+ service_id=diaspora.managed_services[0]
+ ), name='index'),
+]
diff --git a/plinth/modules/diaspora/views.py b/plinth/modules/diaspora/views.py
new file mode 100644
index 000000000..cda4a04f4
--- /dev/null
+++ b/plinth/modules/diaspora/views.py
@@ -0,0 +1,71 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+from .forms import DiasporaForm
+from plinth.modules import diaspora
+from plinth import actions, package
+
+from django.utils.translation import ugettext as _
+from django.template.response import TemplateResponse
+from django.contrib import messages
+
+def get_status():
+ """Get the current status"""
+ return {'enabled': diaspora.is_enabled()}
+
+
+def _apply_changes(request, old_status, new_status):
+ """Apply the changes."""
+ modified = False
+
+ if old_status['enabled'] != new_status['enabled']:
+ sub_command = 'enable' if new_status['enabled'] else 'disable'
+ actions.superuser_run('diaspora', [sub_command])
+ modified = True
+
+ if modified:
+ messages.success(request, 'Configuration updated')
+ else:
+ messages.info(request, 'Setting unchanged')
+
+
+# TODO
+# If there are configuration tasks to be performed immediately before or after the package installation, Plinth provides hooks for it. The before_install= and
+# on_install= parameters to the @package.required decorator take a callback methods that are called before installation of packages and after installation of
+# packages respectively. See the reference section of this manual or the plinth.package module for details. Other modules in Plinth that use this feature provided
+# example usage.
+@package.required(['diaspora'])
+def index(request):
+ """Serve configuration page."""
+ status = get_status()
+
+ form = None
+
+ if request.method == 'POST':
+ form = DiasporaForm(request.POST, prefix='diaspora')
+ if form.is_valid():
+ _apply_changes(request, status, form.cleaned_data)
+ status = get_status()
+ form = DiasporaForm(initial=status, prefix='diaspora')
+ else:
+ form = DiasporaForm(initial=status, prefix='diaspora')
+
+ return TemplateResponse(request, 'diaspora.html',
+ {'title': _(diaspora.title_en),
+ 'status': status,
+ 'form': form})
+
diff --git a/static/themes/default/icons/diaspora.png b/static/themes/default/icons/diaspora.png
new file mode 100644
index 000000000..0aac946d0
Binary files /dev/null and b/static/themes/default/icons/diaspora.png differ