From 145e11bc3af88258d588f8a21c394bafce40a27f Mon Sep 17 00:00:00 2001
From: Peter Lemenkov <lemenkov(a)gmail.com>
Date: Sun, 31 Aug 2014 18:52:59 +0400
Subject: Ejabberd ver. 14.07
Signed-off-by: Peter Lemenkov <lemenkov(a)gmail.com>
---
.gitignore | 2 +
...-service-example-name-to-match-actual-one.patch | 33 +-
...berd-0002-Fixed-delays-in-s2s-connections.patch | 53 -
ejabberd-0002-Introducing-mod_admin_extra.patch | 1608 ++++++++++++++++++++
...03-Fedora-specific-changes-to-ejabberdctl.patch | 19 +
ejabberd-0003-Introducing-mod_admin_extra.patch | 1607 -------------------
...04-Fedora-specific-changes-to-ejabberdctl.patch | 48 -
...Install-.so-objects-with-0755-permissions.patch | 19 +
...berd-0005-Clean-up-false-security-measure.patch | 19 +
...Install-.so-objects-with-0755-permissions.patch | 26 -
ejabberd-0006-Enable-polkit-support.patch | 16 +
...L-GSSAPI-authentication-thanks-to-Mikael-.patch | 505 ------
...07-Disable-INET_DIST_INTERFACE-by-default.patch | 26 -
...07-Install-into-BINDIR-instead-of-SBINDIR.patch | 45 +
...berd-0008-Clean-up-false-security-measure.patch | 26 -
ejabberd-0008-Disable-Erlang-version-check.patch | 38 +
ejabberd-0009-Enable-polkit-support.patch | 23 -
...d-0009-Fix-permissions-for-captcha-script.patch | 19 +
...-Enable-systemd-notification-if-available.patch | 18 +
...10-Install-into-BINDIR-instead-of-SBINDIR.patch | 50 -
ejabberd.init | 111 --
ejabberd.logrotate | 2 +-
ejabberd.service | 9 +-
ejabberd.spec | 280 +---
ejabberd.sysconfig | 13 -
ejabberdctl.apps | 5 -
sources | 3 +-
27 files changed, 1901 insertions(+), 2722 deletions(-)
delete mode 100644 ejabberd-0002-Fixed-delays-in-s2s-connections.patch
create mode 100644 ejabberd-0002-Introducing-mod_admin_extra.patch
create mode 100644 ejabberd-0003-Fedora-specific-changes-to-ejabberdctl.patch
delete mode 100644 ejabberd-0003-Introducing-mod_admin_extra.patch
delete mode 100644 ejabberd-0004-Fedora-specific-changes-to-ejabberdctl.patch
create mode 100644 ejabberd-0004-Install-.so-objects-with-0755-permissions.patch
create mode 100644 ejabberd-0005-Clean-up-false-security-measure.patch
delete mode 100644 ejabberd-0005-Install-.so-objects-with-0755-permissions.patch
create mode 100644 ejabberd-0006-Enable-polkit-support.patch
delete mode 100644
ejabberd-0006-Support-SASL-GSSAPI-authentication-thanks-to-Mikael-.patch
delete mode 100644 ejabberd-0007-Disable-INET_DIST_INTERFACE-by-default.patch
create mode 100644 ejabberd-0007-Install-into-BINDIR-instead-of-SBINDIR.patch
delete mode 100644 ejabberd-0008-Clean-up-false-security-measure.patch
create mode 100644 ejabberd-0008-Disable-Erlang-version-check.patch
delete mode 100644 ejabberd-0009-Enable-polkit-support.patch
create mode 100644 ejabberd-0009-Fix-permissions-for-captcha-script.patch
create mode 100644 ejabberd-0010-Enable-systemd-notification-if-available.patch
delete mode 100644 ejabberd-0010-Install-into-BINDIR-instead-of-SBINDIR.patch
delete mode 100644 ejabberd.init
delete mode 100644 ejabberd.sysconfig
delete mode 100644 ejabberdctl.apps
diff --git a/.gitignore b/.gitignore
index b2b84eb..157f4d1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,5 @@ ejabberd-2.1.5.tar.gz
/processone-ejabberd-v2.1.12-0-gc058687.tar.gz
/processone-ejabberd-v2.1.13-0-g5feeacf.tar.gz
/ejabberd-v2.1.13.tar.gz
+/ejabberd-14.07.tar.gz
+/ejabberd-src-deps.tar
diff --git a/ejabberd-0001-Fix-PAM-service-example-name-to-match-actual-one.patch
b/ejabberd-0001-Fix-PAM-service-example-name-to-match-actual-one.patch
index 8883f15..1816b94 100644
--- a/ejabberd-0001-Fix-PAM-service-example-name-to-match-actual-one.patch
+++ b/ejabberd-0001-Fix-PAM-service-example-name-to-match-actual-one.patch
@@ -1,26 +1,19 @@
-From b3a61330f7328507e1608e437a152e806ef520d1 Mon Sep 17 00:00:00 2001
From: Peter Lemenkov <lemenkov(a)gmail.com>
Date: Tue, 16 Feb 2010 16:03:38 +0300
-Subject: [PATCH 01/10] Fix PAM service example name to match actual one
+Subject: [PATCH] Fix PAM service example name to match actual one
Signed-off-by: Peter Lemenkov <lemenkov(a)gmail.com>
----
- src/ejabberd.cfg.example | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example
-index a4068ad..9b24a4a 100644
---- a/src/ejabberd.cfg.example
-+++ b/src/ejabberd.cfg.example
-@@ -243,7 +243,7 @@
- %% Authentication using PAM
- %%
- %%{auth_method, pam}.
--%%{pam_service, "pamservicename"}.
-+%%{pam_service, "ejabberd"}.
+diff --git a/ejabberd.yml.example b/ejabberd.yml.example
+index ad5ca9e..028704b 100644
+--- a/ejabberd.yml.example
++++ b/ejabberd.yml.example
+@@ -245,7 +245,7 @@ auth_method: internal
+ ## Authentication using PAM
+ ##
+ ## auth_method: pam
+-## pam_service: "pamservicename"
++## pam_service: "ejabberd"
- %%
- %% Authentication using LDAP
---
-1.8.3.1
-
+ ##
+ ## Authentication using LDAP
diff --git a/ejabberd-0002-Fixed-delays-in-s2s-connections.patch
b/ejabberd-0002-Fixed-delays-in-s2s-connections.patch
deleted file mode 100644
index 8572111..0000000
--- a/ejabberd-0002-Fixed-delays-in-s2s-connections.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-From ec26218c6f2374f4e39e50c194150065cc5da275 Mon Sep 17 00:00:00 2001
-From: Sergei Golovan <sgolovan(a)nes.ru>
-Date: Tue, 16 Feb 2010 16:07:37 +0300
-Subject: [PATCH 02/10] Fixed delays in s2s connections.
-
-Patch by Sergei Golovan increases timeouts in S2S and removes horrible 5-minute
-delay between remote server connection attempts after a falure (in case of
-server is down it would be reasonable, but what happens much more often is a
-network split when the delay is inadmissible).
----
- src/ejabberd_s2s_in.erl | 2 +-
- src/ejabberd_s2s_out.erl | 5 +++--
- 2 files changed, 4 insertions(+), 3 deletions(-)
-
-diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl
-index 6ae4f34..a54e9ab 100644
---- a/src/ejabberd_s2s_in.erl
-+++ b/src/ejabberd_s2s_in.erl
-@@ -414,7 +414,7 @@ stream_established({xmlstreamelement, El}, StateData) ->
- case {ejabberd_s2s:allow_host(LTo, LFrom),
- lists:member(LTo, ejabberd_router:dirty_get_all_domains())} of
- {true, true} ->
-- ejabberd_s2s_out:terminate_if_waiting_delay(LTo, LFrom),
-+ %%ejabberd_s2s_out:terminate_if_waiting_delay(LTo, LFrom),
- ejabberd_s2s_out:start(LTo, LFrom,
- {verify, self(),
- Key, StateData#state.streamid}),
-diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl
-index 0dedb4c..9376d16 100644
---- a/src/ejabberd_s2s_out.erl
-+++ b/src/ejabberd_s2s_out.erl
-@@ -93,7 +93,7 @@
- [From, Host, Type])).
- -endif.
-
---define(FSMTIMEOUT, 30000).
-+-define(FSMTIMEOUT, 60000).
-
- %% We do not block on send anymore.
- -define(TCP_SEND_TIMEOUT, 15000).
-@@ -245,7 +245,8 @@ open_socket(init, StateData) ->
- NewStateData = StateData#state{bridge={Mod, Fun}},
- {next_state, relay_to_bridge, NewStateData};
- _ ->
-- wait_before_reconnect(StateData)
-+ %%wait_before_reconnect(StateData)
-+ {stop, normal, StateData}
- end
- end;
- open_socket(closed, StateData) ->
---
-1.8.3.1
-
diff --git a/ejabberd-0002-Introducing-mod_admin_extra.patch
b/ejabberd-0002-Introducing-mod_admin_extra.patch
new file mode 100644
index 0000000..586cefb
--- /dev/null
+++ b/ejabberd-0002-Introducing-mod_admin_extra.patch
@@ -0,0 +1,1608 @@
+From: Badlop <badlop(a)process-one.net>
+Date: Tue, 16 Feb 2010 16:12:17 +0300
+Subject: [PATCH] Introducing mod_admin_extra
+
+Adds the mod_admin_extra module to ejabberd.
+This module extends the functionality provided by ejabberdctl
+by adding several new commands.
+
+The code is taken from the ProcessOne repository:
+
+wget
https://raw.githubusercontent.com/processone/ejabberd-contrib/e23bf94/mod...
+
+diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl
+new file mode 100644
+index 0000000..63703ec
+--- /dev/null
++++ b/src/mod_admin_extra.erl
+@@ -0,0 +1,1590 @@
++%%%-------------------------------------------------------------------
++%%% File : mod_admin_extra.erl
++%%% Author : Badlop <badlop(a)process-one.net>
++%%% Purpose : Contributed administrative functions and commands
++%%% Created : 10 Aug 2008 by Badlop <badlop(a)process-one.net>
++%%%
++%%%
++%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
++%%%
++%%% This program is free software; you can redistribute it and/or
++%%% modify it under the terms of the GNU General Public License as
++%%% published by the Free Software Foundation; either version 2 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
++%%% General Public License for more details.
++%%%
++%%% You should have received a copy of the GNU General Public License
++%%% along with this program; if not, write to the Free Software
++%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++%%% 02111-1307 USA
++%%%
++%%%-------------------------------------------------------------------
++
++-module(mod_admin_extra).
++-author('badlop(a)process-one.net').
++
++-behaviour(gen_mod).
++
++-export([start/2, stop/1,
++ %% Node
++ compile/1,
++ load_config/1,
++ get_cookie/0,
++ remove_node/1,
++ export2odbc/2,
++ %% Accounts
++ set_password/3,
++ check_password_hash/4,
++ delete_old_users/1,
++ delete_old_users_vhost/2,
++ ban_account/3,
++ num_active_users/2,
++ %% Sessions
++ num_resources/2,
++ resource_num/3,
++ kick_session/4,
++ status_num/2, status_num/1,
++ status_list/2, status_list/1,
++ connected_users_info/0,
++ connected_users_vhost/1,
++ set_presence/7,
++ user_sessions_info/2,
++ %% Vcard
++ set_nickname/3,
++ get_vcard/3,
++ get_vcard/4,
++ get_vcard_multi/4,
++ set_vcard/4,
++ set_vcard/5,
++ %% Roster
++ add_rosteritem/7,
++ delete_rosteritem/4,
++ process_rosteritems/5,
++ get_roster/2,
++ push_roster/3,
++ push_roster_all/1,
++ push_alltoall/2,
++ %% mod_last
++ get_last/2,
++ set_last/4,
++ %% mod_private
++ private_get/4,
++ private_set/3,
++ %% mod_shared_roster
++ srg_create/5,
++ srg_delete/2,
++ srg_list/1,
++ srg_get_info/2,
++ srg_get_members/2,
++ srg_user_add/4,
++ srg_user_del/4,
++ %% Stanza
++ send_message_headline/4,
++ send_message_chat/3,
++ send_stanza_c2s/4,
++ privacy_set/3,
++ %% Stats
++ stats/1, stats/2
++ ]).
++
++-include("ejabberd.hrl").
++-include("ejabberd_commands.hrl").
++-include("mod_roster.hrl").
++-include("jlib.hrl").
++
++%% Copied from ejabberd_sm.erl
++-record(session, {sid, usr, us, priority, info}).
++
++
++%%%
++%%% gen_mod
++%%%
++
++start(_Host, _Opts) ->
++ ejabberd_commands:register_commands(commands()).
++
++stop(_Host) ->
++ ejabberd_commands:unregister_commands(commands()).
++
++
++%%%
++%%% Register commands
++%%%
++
++commands() ->
++ Vcard1FieldsString = "Some vcard field names in get/set_vcard are:\n"
++ " FN - Full Name\n"
++ " NICKNAME - Nickname\n"
++ " BDAY - Birthday\n"
++ " TITLE - Work: Position\n"
++ " ROLE - Work: Role",
++
++ Vcard2FieldsString = "Some vcard field names and subnames in get/set_vcard2
are:\n"
++ " N FAMILY - Family name\n"
++ " N GIVEN - Given name\n"
++ " N MIDDLE - Middle name\n"
++ " ADR CTRY - Address: Country\n"
++ " ADR LOCALITY - Address: City\n"
++ " EMAIL USERID - E-Mail Address\n"
++ " ORG ORGNAME - Work: Company\n"
++ " ORG ORGUNIT - Work: Department",
++
++ VcardXEP = "For a full list of vCard fields check XEP-0054: vcard-temp at
"
++ "http://www.xmpp.org/extensions/xep-0054.html",
++
++ [
++ #ejabberd_commands{name = compile, tags = [erlang],
++ desc = "Recompile and reload Erlang source code file",
++ module = ?MODULE, function = compile,
++ args = [{file, string}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = load_config, tags = [server],
++ desc = "Load ejabberd configuration file",
++ module = ?MODULE, function = load_config,
++ args = [{file, string}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = get_cookie, tags = [erlang],
++ desc = "Get the Erlang cookie of this node",
++ module = ?MODULE, function = get_cookie,
++ args = [],
++ result = {cookie, string}},
++ #ejabberd_commands{name = remove_node, tags = [erlang],
++ desc = "Remove an ejabberd node from Mnesia clustering config",
++ module = ?MODULE, function = remove_node,
++ args = [{node, string}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = export2odbc, tags = [mnesia], %% Copied to ejabberd 2.1.x
after 11
++ desc = "Export Mnesia tables to files in directory",
++ module = ?MODULE, function = export2odbc,
++ args = [{host, string}, {path, string}],
++ result = {res, rescode}},
++
++ #ejabberd_commands{name = num_active_users, tags = [accounts, stats],
++ desc = "Get number of users active in the last days",
++ module = ?MODULE, function = num_active_users,
++ args = [{host, binary}, {days, integer}],
++ result = {users, integer}},
++ #ejabberd_commands{name = delete_old_users, tags = [accounts, purge],
++ desc = "Delete users that didn't log in last days, or that never
logged",
++ module = ?MODULE, function = delete_old_users,
++ args = [{days, integer}],
++ result = {res, restuple}},
++ #ejabberd_commands{name = delete_old_users_vhost, tags = [accounts, purge],
++ desc = "Delete users that didn't log in last days in vhost, or that never
logged",
++ module = ?MODULE, function = delete_old_users_vhost,
++ args = [{host, binary}, {days, integer}],
++ result = {res, restuple}},
++
++ #ejabberd_commands{name = check_account, tags = [accounts],
++ desc = "Check if an account exists or not",
++ module = ejabberd_auth, function = is_user_exists,
++ args = [{user, binary}, {host, binary}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = check_password, tags = [accounts],
++ desc = "Check if a password is correct",
++ module = ejabberd_auth, function = check_password,
++ args = [{user, binary}, {host, binary}, {password, binary}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = check_password_hash, tags = [accounts],
++ desc = "Check if the password hash is correct",
++ longdesc = "Allowed hash methods: md5, sha.",
++ module = ?MODULE, function = check_password_hash,
++ args = [{user, binary}, {host, binary}, {passwordhash, binary}, {hashmethod,
binary}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = change_password, tags = [accounts],
++ desc = "Change the password of an account",
++ module = ?MODULE, function = set_password,
++ args = [{user, binary}, {host, binary}, {newpass, binary}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = ban_account, tags = [accounts],
++ desc = "Ban an account: kick sessions and set random password",
++ module = ?MODULE, function = ban_account,
++ args = [{user, binary}, {host, binary}, {reason, binary}],
++ result = {res, rescode}},
++
++ #ejabberd_commands{name = num_resources, tags = [session],
++ desc = "Get the number of resources of a user",
++ module = ?MODULE, function = num_resources,
++ args = [{user, binary}, {host, binary}],
++ result = {resources, integer}},
++ #ejabberd_commands{name = resource_num, tags = [session],
++ desc = "Resource string of a session number",
++ module = ?MODULE, function = resource_num,
++ args = [{user, binary}, {host, binary}, {num, integer}],
++ result = {resource, string}},
++ #ejabberd_commands{name = kick_session, tags = [session],
++ desc = "Kick a user session",
++ module = ?MODULE, function = kick_session,
++ args = [{user, binary}, {host, binary}, {resource, binary}, {reason, binary}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = status_num_host, tags = [session, stats],
++ desc = "Number of logged users with this status in host",
++ module = ?MODULE, function = status_num,
++ args = [{host, binary}, {status, binary}],
++ result = {users, integer}},
++ #ejabberd_commands{name = status_num, tags = [session, stats],
++ desc = "Number of logged users with this status",
++ module = ?MODULE, function = status_num,
++ args = [{status, binary}],
++ result = {users, integer}},
++ #ejabberd_commands{name = status_list_host, tags = [session],
++ desc = "List of users logged in host with their statuses",
++ module = ?MODULE, function = status_list,
++ args = [{host, binary}, {status, binary}],
++ result = {users, {list,
++ {userstatus, {tuple, [
++ {user, string},
++ {host, string},
++ {resource, string},
++ {priority, integer},
++ {status, string}
++ ]}}
++ }}},
++ #ejabberd_commands{name = status_list, tags = [session],
++ desc = "List of logged users with this status",
++ module = ?MODULE, function = status_list,
++ args = [{status, binary}],
++ result = {users, {list,
++ {userstatus, {tuple, [
++ {user, string},
++ {host, string},
++ {resource, string},
++ {priority, integer},
++ {status, string}
++ ]}}
++ }}},
++ #ejabberd_commands{name = connected_users_info,
++ tags = [session],
++ desc = "List all established sessions and their information",
++ module = ?MODULE, function = connected_users_info,
++ args = [],
++ result = {connected_users_info,
++ {list,
++ {sessions, {tuple,
++ [{jid, string},
++ {connection, string},
++ {ip, string},
++ {port, integer},
++ {priority, integer},
++ {node, string},
++ {uptime, integer}
++ ]}}
++ }}},
++ #ejabberd_commands{name = connected_users_vhost,
++ tags = [session],
++ desc = "Get the list of established sessions in a
vhost",
++ module = ?MODULE, function = connected_users_vhost,
++ args = [{host, string}],
++ result = {connected_users_vhost, {list, {sessions, string}}}},
++ #ejabberd_commands{name = user_sessions_info,
++ tags = [session],
++ desc = "Get information about all sessions of a user",
++ module = ?MODULE, function = user_sessions_info,
++ args = [{user, string}, {host, string}],
++ result = {sessions_info,
++ {list,
++ {session, {tuple,
++ [{connection, string},
++ {ip, string},
++ {port, integer},
++ {priority, integer},
++ {node, string},
++ {uptime, integer},
++ {status, string},
++ {resource, string},
++ {statustext, string}
++ ]}}
++ }}},
++
++ #ejabberd_commands{name = set_presence,
++ tags = [session],
++ desc = "Set presence of a session",
++ module = ?MODULE, function = set_presence,
++ args = [{user, string}, {host, string},
++ {resource, string}, {type, string},
++ {show, string}, {status, string},
++ {priority, string}],
++ result = {res, rescode}},
++
++ #ejabberd_commands{name = set_nickname, tags = [vcard],
++ desc = "Set nickname in a user's vCard",
++ module = ?MODULE, function = set_nickname,
++ args = [{user, string}, {host, string}, {nickname, string}],
++ result = {res, rescode}},
++
++ #ejabberd_commands{name = get_vcard, tags = [vcard],
++ desc = "Get content from a vCard field",
++ longdesc = Vcard1FieldsString ++ "\n" ++ Vcard2FieldsString ++
"\n\n" ++ VcardXEP,
++ module = ?MODULE, function = get_vcard,
++ args = [{user, binary}, {host, binary}, {name, binary}],
++ result = {content, string}},
++ #ejabberd_commands{name = get_vcard2, tags = [vcard],
++ desc = "Get content from a vCard field",
++ longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++
"\n" ++ VcardXEP,
++ module = ?MODULE, function = get_vcard,
++ args = [{user, binary}, {host, binary}, {name, binary}, {subname, binary}],
++ result = {content, string}},
++ #ejabberd_commands{name = get_vcard2_multi, tags = [vcard],
++ desc = "Get multiple contents from a vCard field (requires exmpp
installed)",
++ longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++
"\n" ++ VcardXEP,
++ module = ?MODULE, function = get_vcard_multi,
++ args = [{user, binary}, {host, binary}, {name, binary}, {subname, binary}],
++ result = {contents, {list, string}}},
++
++ #ejabberd_commands{name = set_vcard, tags = [vcard],
++ desc = "Set content in a vCard field",
++ longdesc = Vcard1FieldsString ++ "\n" ++ Vcard2FieldsString ++
"\n\n" ++ VcardXEP,
++ module = ?MODULE, function = set_vcard,
++ args = [{user, binary}, {host, binary}, {name, binary}, {content, binary}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = set_vcard2, tags = [vcard],
++ desc = "Set content in a vCard subfield",
++ longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++
"\n" ++ VcardXEP,
++ module = ?MODULE, function = set_vcard,
++ args = [{user, binary}, {host, binary}, {name, binary}, {subname, binary}, {content,
binary}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = set_vcard2_multi, tags = [vcard],
++ desc = "Set multiple contents in a vCard subfield",
++ longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++
"\n" ++ VcardXEP,
++ module = ?MODULE, function = set_vcard,
++ args = [{user, binary}, {host, binary}, {name, binary}, {subname, binary}, {contents,
{list, binary}}],
++ result = {res, rescode}},
++
++ #ejabberd_commands{name = add_rosteritem, tags = [roster],
++ desc = "Add an item to a user's roster (supports ODBC)",
++ module = ?MODULE, function = add_rosteritem,
++ args = [{localuser, binary}, {localserver, binary},
++ {user, binary}, {server, binary},
++ {nick, binary}, {group, binary},
++ {subs, binary}],
++ result = {res, rescode}},
++ %%{"", "subs= none, from, to or both"},
++ %%{"", "example: add-roster peter localhost mike
server.com MiKe
Employees both"},
++ %%{"", "will add mike(a)server.com to peter@localhost roster"},
++ #ejabberd_commands{name = delete_rosteritem, tags = [roster],
++ desc = "Delete an item from a user's roster (supports ODBC)",
++ module = ?MODULE, function = delete_rosteritem,
++ args = [{localuser, binary}, {localserver, binary},
++ {user, binary}, {server, binary}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = process_rosteritems, tags = [roster],
++ desc = "List or delete rosteritems that match filtering options",
++ longdesc = "Explanation of each argument:\n"
++ " - action: what to do with each rosteritem that "
++ "matches all the filtering options\n"
++ " - subs: subscription type\n"
++ " - asks: pending subscription\n"
++ " - users: the JIDs of the local user\n"
++ " - contacts: the JIDs of the contact in the roster\n"
++ "\n"
++ "Allowed values in the arguments:\n"
++ " ACTION = list | delete\n"
++ " SUBS = SUB[:SUB]* | any\n"
++ " SUB = none | from | to | both\n"
++ " ASKS = ASK[:ASK]* | any\n"
++ " ASK = none | out | in\n"
++ " USERS = JID[:JID]* | any\n"
++ " CONTACTS = JID[:JID]* | any\n"
++ " JID = characters valid in a JID, and can use the "
++ "globs: *, ?, ! and [...]\n"
++ "\n"
++ "This example will list roster items with subscription "
++ "'none', 'from' or 'to' that have any ask property, of
"
++ "local users which JID is in the virtual host "
++ "'example.org' and that the contact JID is either a "
++ "bare server name (without user part) or that has a "
++ "user part and the server part contains the word 'icq'"
++ ":\n list none:from:to any *(a)example.org *:*@*icq*",
++ module = ?MODULE, function = process_rosteritems,
++ args = [{action, string}, {subs, string},
++ {asks, string}, {users, string},
++ {contacts, string}],
++ result = {response,
++ {list,
++ {pairs, {tuple,
++ [{user, string},
++ {contact, string}
++ ]}}
++ }}},
++ #ejabberd_commands{name = get_roster, tags = [roster],
++ desc = "Get roster of a local user",
++ module = ?MODULE, function = get_roster,
++ args = [{user, binary}, {host, binary}],
++ result = {contacts, {list, {contact, {tuple, [
++ {jid, string},
++ {nick, string},
++ {subscription, string},
++ {ask, string},
++ {group, string}
++ ]}}}}},
++ #ejabberd_commands{name = push_roster, tags = [roster],
++ desc = "Push template roster from file to a user",
++ module = ?MODULE, function = push_roster,
++ args = [{file, string}, {user, string}, {host, string}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = push_roster_all, tags = [roster],
++ desc = "Push template roster from file to all those users",
++ module = ?MODULE, function = push_roster_all,
++ args = [{file, string}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = push_alltoall, tags = [roster],
++ desc = "Add all the users to all the users of Host in Group",
++ module = ?MODULE, function = push_alltoall,
++ args = [{host, string}, {group, string}],
++ result = {res, rescode}},
++
++ #ejabberd_commands{name = get_last, tags = [last],
++ desc = "Get last activity information",
++ longdesc = "Timestamp is the seconds since"
++ "1970-01-01 00:00:00 UTC, for example: date +%s",
++ module = ?MODULE, function = get_last,
++ args = [{user, binary}, {host, binary}],
++ result = {last_activity, string}},
++ #ejabberd_commands{name = set_last, tags = [last],
++ desc = "Set last activity information",
++ longdesc = "Timestamp is the seconds since"
++ "1970-01-01 00:00:00 UTC, for example: date +%s",
++ module = ?MODULE, function = set_last,
++ args = [{user, string}, {host, string}, {timestamp, integer}, {status, string}],
++ result = {res, rescode}},
++
++ #ejabberd_commands{name = private_get, tags = [private],
++ desc = "Get some information from a user private storage",
++ module = ?MODULE, function = private_get,
++ args = [{user, string}, {host, string}, {element, string}, {ns, string}],
++ result = {res, string}},
++ #ejabberd_commands{name = private_set, tags = [private],
++ desc = "Set to the user private storage",
++ module = ?MODULE, function = private_set,
++ args = [{user, string}, {host, string}, {element, string}],
++ result = {res, rescode}},
++
++ #ejabberd_commands{name = srg_create, tags = [shared_roster_group],
++ desc = "Create a Shared Roster Group",
++ longdesc = "If you want to specify several group "
++ "identifiers in the Display argument,\n"
++ "put \\ \" around the argument and\nseparate the "
++ "identifiers with \\ \\ n\n"
++ "For example:\n"
++ " ejabberdctl srg_create group3 localhost "
++ "name desc \\\"group1\\\\ngroup2\\\"",
++ module = ?MODULE, function = srg_create,
++ args = [{group, binary}, {host, binary},
++ {name, binary}, {description, binary}, {display, binary}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = srg_delete, tags = [shared_roster_group],
++ desc = "Delete a Shared Roster Group",
++ module = ?MODULE, function = srg_delete,
++ args = [{group, binary}, {host, binary}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = srg_list, tags = [shared_roster_group],
++ desc = "List the Shared Roster Groups in Host",
++ module = ?MODULE, function = srg_list,
++ args = [{host, binary}],
++ result = {groups, {list, {id, string}}}},
++ #ejabberd_commands{name = srg_get_info, tags = [shared_roster_group],
++ desc = "Get info of a Shared Roster Group",
++ module = ?MODULE, function = srg_get_info,
++ args = [{group, binary}, {host, binary}],
++ result = {informations, {list, {information, {tuple, [{key, string}, {value,
string}]}}}}},
++ #ejabberd_commands{name = srg_get_members, tags = [shared_roster_group],
++ desc = "Get members of a Shared Roster Group",
++ module = ?MODULE, function = srg_get_members,
++ args = [{group, binary}, {host, binary}],
++ result = {members, {list, {member, string}}}},
++ #ejabberd_commands{name = srg_user_add, tags = [shared_roster_group],
++ desc = "Add the JID user@host to the Shared Roster Group",
++ module = ?MODULE, function = srg_user_add,
++ args = [{user, binary}, {host, binary}, {group, binary}, {grouphost, binary}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = srg_user_del, tags = [shared_roster_group],
++ desc = "Delete this JID user@host from the Shared Roster Group",
++ module = ?MODULE, function = srg_user_del,
++ args = [{user, binary}, {host, binary}, {group, binary}, {grouphost, binary}],
++ result = {res, rescode}},
++
++ #ejabberd_commands{name = send_message_chat, tags = [stanza],
++ desc = "Send a chat message to a local or remote bare of full JID",
++ module = ?MODULE, function = send_message_chat,
++ args = [{from, binary}, {to, binary}, {body, binary}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = send_message_headline, tags = [stanza],
++ desc = "Send a headline message to a local or remote bare of full JID",
++ module = ?MODULE, function = send_message_headline,
++ args = [{from, binary}, {to, binary},
++ {subject, binary}, {body, binary}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = send_stanza_c2s, tags = [stanza],
++ desc = "Send a stanza as if sent from a c2s session",
++ module = ?MODULE, function = send_stanza_c2s,
++ args = [{user, binary}, {host, binary}, {resource, binary}, {stanza, binary}],
++ result = {res, rescode}},
++ #ejabberd_commands{name = privacy_set, tags = [stanza],
++ desc = "Send a IQ set privacy stanza for a local account",
++ module = ?MODULE, function = privacy_set,
++ args = [{user, binary}, {host, binary}, {xmlquery, binary}],
++ result = {res, rescode}},
++
++ #ejabberd_commands{name = stats, tags = [stats],
++ desc = "Get statistical value: registeredusers onlineusers onlineusersnode
uptimeseconds",
++ module = ?MODULE, function = stats,
++ args = [{name, binary}],
++ result = {stat, integer}},
++ #ejabberd_commands{name = stats_host, tags = [stats],
++ desc = "Get statistical value for this host: registeredusers onlineusers",
++ module = ?MODULE, function = stats,
++ args = [{name, binary}, {host, binary}],
++ result = {stat, integer}}
++ ].
++
++
++%%%
++%%% Node
++%%%
++
++compile(File) ->
++ case compile:file(File) of
++ ok -> ok;
++ _ -> error
++ end.
++
++load_config(Path) ->
++ ok = ejabberd_config:load_file(Path).
++
++get_cookie() ->
++ atom_to_list(erlang:get_cookie()).
++
++remove_node(Node) ->
++ mnesia:del_table_copy(schema, list_to_atom(Node)),
++ ok.
++
++export2odbc(Host, Directory) ->
++ Tables = [
++ {export_last, last},
++ {export_offline, offline},
++ {export_passwd, passwd},
++ {export_private_storage, private_storage},
++ {export_roster, roster},
++ {export_vcard, vcard},
++ {export_vcard_search, vcard_search}],
++ Export = fun({TableFun, Table}) ->
++ Filename = filename:join([Directory, atom_to_list(Table)++".txt"]),
++ io:format("Trying to export Mnesia table '~p' on Host '~s'
to file '~s'~n", [Table, Host, Filename]),
++ Res = (catch ejd2odbc:TableFun(Host, Filename)),
++ io:format(" Result: ~p~n", [Res])
++ end,
++ lists:foreach(Export, Tables),
++ ok.
++
++
++%%%
++%%% Accounts
++%%%
++
++set_password(User, Host, Password) ->
++ case ejabberd_auth:set_password(User, Host, Password) of
++ ok ->
++ ok;
++ _ ->
++ error
++ end.
++
++%% Copied some code from ejabberd_commands.erl
++check_password_hash(User, Host, PasswordHash, HashMethod) ->
++ AccountPass = ejabberd_auth:get_password_s(User, Host),
++ AccountPassHash = case HashMethod of
++ "md5" -> get_md5(AccountPass);
++ "sha" -> get_sha(AccountPass);
++ _ -> undefined
++ end,
++ case AccountPassHash of
++ undefined -> error;
++ PasswordHash -> ok;
++ _ -> error
++ end.
++get_md5(AccountPass) ->
++ lists:flatten([io_lib:format("~.16B", [X])
++ || X <- binary_to_list(crypto:md5(AccountPass))]).
++get_sha(AccountPass) ->
++ lists:flatten([io_lib:format("~.16B", [X])
++ || X <- binary_to_list(crypto:sha(AccountPass))]).
++
++num_active_users(Host, Days) ->
++ list_last_activity(Host, true, Days).
++
++%% Code based on ejabberd/src/web/ejabberd_web_admin.erl
++list_last_activity(Host, Integral, Days) ->
++ {MegaSecs, Secs, _MicroSecs} = now(),
++ TimeStamp = MegaSecs * 1000000 + Secs,
++ TS = TimeStamp - Days * 86400,
++ case catch mnesia:dirty_select(
++ last_activity, [{{last_activity, {'_', Host}, '$1', '_'},
++ [{'>', '$1', TS}],
++ [{'trunc', {'/',
++ {'-', TimeStamp, '$1'},
++ 86400}}]}]) of
++ {'EXIT', _Reason} ->
++ [];
++ Vals ->
++ Hist = histogram(Vals, Integral),
++ if
++ Hist == [] ->
++ 0;
++ true ->
++ Left = Days - length(Hist),
++ Tail = if
++ Integral ->
++ lists:duplicate(Left, lists:last(Hist));
++ true ->
++ lists:duplicate(Left, 0)
++ end,
++ lists:nth(Days, Hist ++ Tail)
++ end
++ end.
++histogram(Values, Integral) ->
++ histogram(lists:sort(Values), Integral, 0, 0, []).
++histogram([H | T], Integral, Current, Count, Hist) when Current == H ->
++ histogram(T, Integral, Current, Count + 1, Hist);
++histogram([H | _] = Values, Integral, Current, Count, Hist) when Current < H ->
++ if
++ Integral ->
++ histogram(Values, Integral, Current + 1, Count, [Count | Hist]);
++ true ->
++ histogram(Values, Integral, Current + 1, 0, [Count | Hist])
++ end;
++histogram([], _Integral, _Current, Count, Hist) ->
++ if
++ Count > 0 ->
++ lists:reverse([Count | Hist]);
++ true ->
++ lists:reverse(Hist)
++ end.
++
++
++delete_old_users(Days) ->
++ %% Get the list of registered users
++ Users = ejabberd_auth:dirty_get_registered_users(),
++
++ {removed, N, UR} = delete_old_users(Days, Users),
++ {ok, io_lib:format("Deleted ~p users: ~p", [N, UR])}.
++
++delete_old_users_vhost(Host, Days) ->
++ %% Get the list of registered users
++ Users = ejabberd_auth:get_vh_registered_users(Host),
++
++ {removed, N, UR} = delete_old_users(Days, Users),
++ {ok, io_lib:format("Deleted ~p users: ~p", [N, UR])}.
++
++delete_old_users(Days, Users) ->
++ %% Convert older time
++ SecOlder = Days*24*60*60,
++
++ %% Get current time
++ {MegaSecs, Secs, _MicroSecs} = now(),
++ TimeStamp_now = MegaSecs * 1000000 + Secs,
++
++ %% For a user, remove if required and answer true
++ F = fun({LUser, LServer}) ->
++ %% Check if the user is logged
++ case ejabberd_sm:get_user_resources(LUser, LServer) of
++ %% If it isnt
++ [] ->
++ %% Look for his last_activity
++ case (get_lastactivity_module(LServer)):get_last_info(LUser, LServer) of
++ %% If it is
++ %% existent:
++ {ok, TimeStamp, _Status} ->
++ %% get his age
++ Sec = TimeStamp_now - TimeStamp,
++ %% If he is
++ if
++ %% younger than SecOlder:
++ Sec < SecOlder ->
++ %% do nothing
++ false;
++ %% older:
++ true ->
++ %% remove the user
++ ejabberd_auth:remove_user(LUser, LServer),
++ true
++ end;
++ %% nonexistent:
++ not_found ->
++ %% remove the user
++ ejabberd_auth:remove_user(LUser, LServer),
++ true
++ end;
++ %% Else
++ _ ->
++ %% do nothing
++ false
++ end
++ end,
++ %% Apply the function to every user in the list
++ Users_removed = lists:filter(F, Users),
++ {removed, length(Users_removed), Users_removed}.
++
++get_lastactivity_module(Server) ->
++ case lists:member(mod_last, gen_mod:loaded_modules(Server)) of
++ true -> mod_last;
++ _ -> mod_last_odbc
++ end.
++
++
++%%
++%% Ban account
++
++ban_account(User, Host, ReasonText) ->
++ Reason = prepare_reason(ReasonText),
++ kick_sessions(User, Host, Reason),
++ set_random_password(User, Host, Reason),
++ ok.
++
++kick_sessions(User, Server, Reason) ->
++ lists:map(
++ fun(Resource) ->
++ kick_this_session(User, Server, Resource, Reason)
++ end,
++ get_resources(User, Server)).
++
++get_resources(User, Server) ->
++ lists:map(
++ fun(Session) ->
++ element(3, Session#session.usr)
++ end,
++ get_sessions(User, Server)).
++
++get_sessions(User, Server) ->
++ LUser = jlib:nodeprep(User),
++ LServer = jlib:nameprep(Server),
++ Sessions = mnesia:dirty_index_read(session, {LUser, LServer}, #session.us),
++ true = is_list(Sessions),
++ Sessions.
++
++set_random_password(User, Server, Reason) ->
++ NewPass = build_random_password(Reason),
++ set_password_auth(User, Server, NewPass).
++
++build_random_password(Reason) ->
++ Date = jlib:timestamp_to_iso(calendar:universal_time()),
++ RandomString = randoms:get_string(),
++ "BANNED_ACCOUNT--" ++ Date ++ "--" ++ RandomString ++
"--" ++ Reason.
++
++set_password_auth(User, Server, Password) ->
++ ok = ejabberd_auth:set_password(User, Server, Password).
++
++prepare_reason([]) ->
++ <<"Kicked by administrator">>;
++prepare_reason([Reason]) ->
++ Reason;
++prepare_reason(Reason) when is_binary(Reason) ->
++ Reason.
++
++%%%
++%%% Sessions
++%%%
++
++num_resources(User, Host) ->
++ length(ejabberd_sm:get_user_resources(User, Host)).
++
++resource_num(User, Host, Num) ->
++ Resources = ejabberd_sm:get_user_resources(User, Host),
++ case (0<Num) and (Num=<length(Resources)) of
++ true ->
++ lists:nth(Num, Resources);
++ false ->
++ lists:flatten(io_lib:format("Error: Wrong resource number: ~p", [Num]))
++ end.
++
++kick_session(User, Server, Resource, ReasonText) ->
++ kick_this_session(User, Server, Resource, prepare_reason(ReasonText)),
++ ok.
++
++kick_this_session(User, Server, Resource, Reason) ->
++ ejabberd_router:route(
++ jlib:make_jid(<<>>, <<>>, <<>>),
++ jlib:make_jid(User, Server, Resource),
++ {broadcast, {exit, Reason}}).
++
++
++status_num(Host, Status) ->
++ length(get_status_list(Host, Status)).
++status_num(Status) ->
++ status_num(<<"all">>, Status).
++status_list(Host, Status) ->
++ Res = get_status_list(Host, Status),
++ [{U, S, R, P, St} || {U, S, R, P, St} <- Res].
++status_list(Status) ->
++ status_list(<<"all">>, Status).
++
++
++get_status_list(Host, Status_required) ->
++ %% Get list of all logged users
++ Sessions = ejabberd_sm:dirty_get_my_sessions_list(),
++ %% Reformat the list
++ Sessions2 = [ {Session#session.usr, Session#session.sid, Session#session.priority}
|| Session <- Sessions],
++ Fhost = case Host of
++ <<"all">> ->
++ %% All hosts are requested, so dont filter at all
++ fun(_, _) -> true end;
++ _ ->
++ %% Filter the list, only Host is interesting
++ fun(A, B) -> A == B end
++ end,
++ Sessions3 = [ {Pid, Server, Priority} || {{_User, Server, _Resource}, {_, Pid},
Priority} <- Sessions2, apply(Fhost, [Server, Host])],
++ %% For each Pid, get its presence
++ Sessions4 = [ {ejabberd_c2s:get_presence(Pid), Server, Priority} || {Pid, Server,
Priority} <- Sessions3],
++ %% Filter by status
++ Fstatus = case Status_required of
++ <<"all">> ->
++ fun(_, _) -> true end;
++ _ ->
++ fun(A, B) -> A == B end
++ end,
++ [{User, Server, Resource, Priority, stringize(Status_text)}
++ || {{User, Resource, Status, Status_text}, Server, Priority} <- Sessions4,
++ apply(Fstatus, [Status, Status_required])].
++
++connected_users_info() ->
++ USRIs = dirty_get_sessions_list2(),
++ CurrentSec = calendar:datetime_to_gregorian_seconds({date(), time()}),
++ lists:map(
++ fun([{U, S, R}, {Now, Pid}, Priority, Info]) ->
++ Conn = proplists:get_value(conn, Info),
++ {Ip, Port} = proplists:get_value(ip, Info),
++ IPS = inet_parse:ntoa(Ip),
++ NodeS = atom_to_list(node(Pid)),
++ Uptime = CurrentSec - calendar:datetime_to_gregorian_seconds(
++ calendar:now_to_local_time(Now)),
++ {[U, $@, S, $/, R], atom_to_list(Conn), IPS, Port, Priority, NodeS, Uptime}
++ end,
++ USRIs).
++
++connected_users_vhost(Host) ->
++ USRs = ejabberd_sm:get_vh_session_list(Host),
++ [ [U, $@, S, $/, R] || {U, S, R} <- USRs].
++
++%% Code copied from ejabberd_sm.erl and customized
++dirty_get_sessions_list2() ->
++ mnesia:dirty_select(
++ session,
++ [{#session{usr = '$1', sid = '$2', priority = '$3', info =
'$4', _ = '_'},
++ [],
++ [['$1', '$2', '$3', '$4']]}]).
++
++%% Make string more print-friendly
++stringize(String) ->
++ %% Replace newline characters with other code
++ ejabberd_regexp:greplace(String, <<"\n">>,
<<"\\n">>).
++
++set_presence(User, Host, Resource, Type, Show, Status, Priority) ->
++ Pid = ejabberd_sm:get_session_pid(User, Host, Resource),
++ USR = User ++ "@" ++ Host ++ "/" ++ Resource,
++ US = User ++ "@" ++ Host,
++ Message = {route_xmlstreamelement,
++ {xmlel, <<"presence">>,
++ [{<<"from">>, USR}, {<<"to">>, US},
{<<"type">>, Type}],
++ [{xmlel, <<"show">>, [], [{xmlcdata, Show}]},
++ {xmlel, <<"status">>, [], [{xmlcdata, Status}]},
++ {xmlel, <<"priority">>, [], [{xmlcdata, Priority}]}]}},
++ Pid ! Message.
++
++user_sessions_info(User, Host) ->
++ CurrentSec = calendar:datetime_to_gregorian_seconds({date(), time()}),
++ US = {User, Host},
++ Sessions = case catch mnesia:dirty_index_read(session, US, #session.us) of
++ {'EXIT', _Reason} ->
++ [];
++ Ss ->
++ Ss
++ end,
++ lists:map(
++ fun(Session) ->
++ {_U, _S, Resource} = Session#session.usr,
++ {Now, Pid} = Session#session.sid,
++ {_U, _Resource, Status, StatusText} = ejabberd_c2s:get_presence(Pid),
++ Info = Session#session.info,
++ Priority = Session#session.priority,
++ Conn = proplists:get_value(conn, Info),
++ {Ip, Port} = proplists:get_value(ip, Info),
++ IPS = inet_parse:ntoa(Ip),
++ NodeS = atom_to_list(node(Pid)),
++ Uptime = CurrentSec - calendar:datetime_to_gregorian_seconds(
++ calendar:now_to_local_time(Now)),
++ {atom_to_list(Conn), IPS, Port, Priority, NodeS, Uptime, Status, Resource,
StatusText}
++ end,
++ Sessions).
++
++
++%%%
++%%% Vcard
++%%%
++
++set_nickname(User, Host, Nickname) ->
++ R = mod_vcard:process_sm_iq(
++ {jid, User, Host, <<>>, User, Host, <<>>},
++ {jid, User, Host, <<>>, User, Host, <<>>},
++ {iq, <<>>, set, <<>>, <<"en">>,
++ {xmlel, <<"vCard">>, [
++ {<<"xmlns">>, <<"vcard-temp">>}], [
++ {xmlel, <<"NICKNAME">>, [], [{xmlcdata, Nickname}]}
++ ]
++ }}),
++ case R of
++ {iq, [], result, [], _L, []} ->
++ ok;
++ _ ->
++ error
++ end.
++
++get_vcard(User, Host, Name) ->
++ [Res | _] = get_vcard_content(User, Host, [Name]),
++ Res.
++
++get_vcard(User, Host, Name, Subname) ->
++ [Res | _] = get_vcard_content(User, Host, [Name, Subname]),
++ Res.
++
++get_vcard_multi(User, Host, Name, Subname) ->
++ get_vcard_content(User, Host, [Name, Subname]).
++
++set_vcard(User, Host, Name, SomeContent) ->
++ set_vcard_content(User, Host, [Name], SomeContent).
++
++set_vcard(User, Host, Name, Subname, SomeContent) ->
++ set_vcard_content(User, Host, [Name, Subname], SomeContent).
++
++
++%%
++%% Internal vcard
++
++get_module_resource(Server) ->
++ case gen_mod:get_module_opt(Server, ?MODULE, module_resource, fun(A) -> A end,
none) of
++ none -> list_to_binary(atom_to_list(?MODULE));
++ R when is_binary(R) -> R
++ end.
++
++get_vcard_content(User, Server, Data) ->
++ [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}),
++ JID = jlib:make_jid(User, Server, get_module_resource(Server)),
++ IQ = #iq{type = get, xmlns = ?NS_VCARD},
++ IQr = Module:Function(JID, JID, IQ),
++ case IQr#iq.sub_el of
++ [A1] ->
++ case get_vcard(Data, A1) of
++ [] -> throw(error_no_value_found_in_vcard);
++ ElemList -> [xml:get_tag_cdata(Elem) || Elem <- ElemList]
++ end;
++ [] ->
++ throw(error_no_vcard_found)
++ end.
++
++get_vcard([Data1, Data2], A1) ->
++ case get_subtag(A1, Data1) of
++ false -> false;
++ A2List -> lists:flatten([get_vcard([Data2], A2) || A2 <- A2List])
++ end;
++
++get_vcard([Data], A1) ->
++ get_subtag(A1, Data).
++
++get_subtag(Xmlelement, Name) ->
++ case code:ensure_loaded(exmpp_xml) of
++ {error, _} ->
++ [get_subtag_xml(Xmlelement, Name)];
++ {module, exmpp_xml} ->
++ get_subtag_exmpp(Xmlelement, Name)
++ end.
++
++get_subtag_xml(Xmlelement, Name) ->
++ xml:get_subtag(Xmlelement, Name).
++
++get_subtag_exmpp(Xmlelement, Name) ->
++ Xmlel = exmpp_xml:xmlelement_to_xmlel(Xmlelement),
++ XmlelList = exmpp_xml:get_elements(Xmlel, Name),
++ [exmpp_xml:xmlel_to_xmlelement(Xmlel2) || Xmlel2 <- XmlelList].
++
++set_vcard_content(User, Server, Data, SomeContent) ->
++ ContentList = case SomeContent of
++ [Bin | _] when is_binary(Bin) -> SomeContent;
++ Bin when is_binary(Bin) -> [SomeContent]
++ end,
++ [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}),
++ JID = jlib:make_jid(User, Server, get_module_resource(Server)),
++ IQ = #iq{type = get, xmlns = ?NS_VCARD},
++ IQr = Module:Function(JID, JID, IQ),
++
++ %% Get old vcard
++ A4 = case IQr#iq.sub_el of
++ [A1] ->
++ {_, _, _, A2} = A1,
++ update_vcard_els(Data, ContentList, A2);
++ [] ->
++ update_vcard_els(Data, ContentList, [])
++ end,
++
++ %% Build new vcard
++ SubEl = {xmlel, <<"vCard">>,
[{<<"xmlns">>,<<"vcard-temp">>}], A4},
++ IQ2 = #iq{type=set, sub_el = SubEl},
++
++ Module:Function(JID, JID, IQ2),
++ ok.
++
++update_vcard_els(Data, ContentList, Els1) ->
++ Els2 = lists:keysort(2, Els1),
++ [Data1 | Data2] = Data,
++ NewEls = case Data2 of
++ [] ->
++ [{xmlel, Data1, [], [{xmlcdata,Content}]} || Content <- ContentList];
++ [D2] ->
++ OldEl = case lists:keysearch(Data1, 2, Els2) of
++ {value, A} -> A;
++ false -> {xmlel, Data1, [], []}
++ end,
++ {xmlel, _, _, ContentOld1} = OldEl,
++ Content2 = [{xmlel, D2, [], [{xmlcdata,Content}]} || Content <- ContentList],
++ ContentOld2 = [A || {_, X, _, _} = A <- ContentOld1, X/=D2],
++ ContentOld3 = lists:keysort(2, ContentOld2),
++ ContentNew = lists:keymerge(2, Content2, ContentOld3),
++ [{xmlel, Data1, [], ContentNew}]
++ end,
++ Els3 = lists:keydelete(Data1, 2, Els2),
++ lists:keymerge(2, NewEls, Els3).
++
++
++%%%
++%%% Roster
++%%%
++
++add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group, Subs) ->
++ case add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group, Subs, []) of
++ {atomic, ok} ->
++ push_roster_item(LocalUser, LocalServer, User, Server, {add, Nick, Subs, Group}),
++ ok;
++ _ ->
++ error
++ end.
++
++add_rosteritem(LU, LS, User, Server, Nick, Group, Subscription, Xattrs) ->
++ subscribe(LU, LS, User, Server, Nick, Group, Subscription, Xattrs).
++
++subscribe(LU, LS, User, Server, Nick, Group, Subscription, _Xattrs) ->
++ ItemEl = build_roster_item(User, Server, {add, Nick, Subscription, Group}),
++ mod_roster:set_items(
++ LU, LS,
++ {xmlel, <<"query">>,
++ [{<<"xmlns">>,
<<"jabber:iq:roster">>}],
++ [ItemEl]}).
++
++delete_rosteritem(LocalUser, LocalServer, User, Server) ->
++ case unsubscribe(LocalUser, LocalServer, User, Server) of
++ {atomic, ok} ->
++ push_roster_item(LocalUser, LocalServer, User, Server, remove),
++ ok;
++ _ ->
++ error
++ end.
++
++unsubscribe(LU, LS, User, Server) ->
++ ItemEl = build_roster_item(User, Server, remove),
++ mod_roster:set_items(
++ LU, LS,
++ {xmlel, <<"query">>,
++ [{<<"xmlns">>,
<<"jabber:iq:roster">>}],
++ [ItemEl]}).
++
++%% -----------------------------
++%% Get Roster
++%% -----------------------------
++
++get_roster(User, Server) ->
++ Items = ejabberd_hooks:run_fold(roster_get, Server, [], [{User, Server}]),
++ make_roster_xmlrpc(Items).
++
++%% Note: if a contact is in several groups, the contact is returned
++%% several times, each one in a different group.
++make_roster_xmlrpc(Roster) ->
++ lists:foldl(
++ fun(Item, Res) ->
++ JIDS = jlib:jid_to_string(Item#roster.jid),
++ Nick = Item#roster.name,
++ Subs = atom_to_list(Item#roster.subscription),
++ Ask = atom_to_list(Item#roster.ask),
++ Groups = case Item#roster.groups of
++ [] -> [<<>>];
++ Gs -> Gs
++ end,
++ ItemsX = [{JIDS, Nick, Subs, Ask, Group} || Group <- Groups],
++ ItemsX ++ Res
++ end,
++ [],
++ Roster).
++
++
++%%-----------------------------
++%% Push Roster from file
++%%-----------------------------
++
++push_roster(File, User, Server) ->
++ {ok, [Roster]} = file:consult(File),
++ subscribe_roster({User, Server, <<>>, User}, Roster).
++
++push_roster_all(File) ->
++ {ok, [Roster]} = file:consult(File),
++ subscribe_all(Roster).
++
++subscribe_all(Roster) ->
++ subscribe_all(Roster, Roster).
++subscribe_all([], _) ->
++ ok;
++subscribe_all([User1 | Users], Roster) ->
++ subscribe_roster(User1, Roster),
++ subscribe_all(Users, Roster).
++
++subscribe_roster(_, []) ->
++ ok;
++%% Do not subscribe a user to itself
++subscribe_roster({Name, Server, Group, Nick}, [{Name, Server, _, _} | Roster]) ->
++ subscribe_roster({Name, Server, Group, Nick}, Roster);
++%% Subscribe Name2 to Name1
++subscribe_roster({Name1, Server1, Group1, Nick1}, [{Name2, Server2, Group2, Nick2} |
Roster]) ->
++ subscribe(Name1, Server1, Name2, Server2, Nick2, Group2,
<<"both">>, []),
++ subscribe_roster({Name1, Server1, Group1, Nick1}, Roster).
++
++push_alltoall(S, G) ->
++ Users = ejabberd_auth:get_vh_registered_users(S),
++ Users2 = build_list_users(G, Users, []),
++ subscribe_all(Users2),
++ ok.
++
++build_list_users(_Group, [], Res) ->
++ Res;
++build_list_users(Group, [{User, Server}|Users], Res) ->
++ build_list_users(Group, Users, [{User, Server, Group, User}|Res]).
++
++%% @spec(LU, LS, U, S, Action) -> ok
++%% Action = {add, Nick, Subs, Group} | remove
++%% @doc Push to the roster of account LU@LS the contact U@S.
++%% The specific action to perform is defined in Action.
++push_roster_item(LU, LS, U, S, Action) ->
++ lists:foreach(fun(R) ->
++ push_roster_item(LU, LS, R, U, S, Action)
++ end, ejabberd_sm:get_user_resources(LU, LS)).
++
++push_roster_item(LU, LS, R, U, S, Action) ->
++ LJID = jlib:make_jid(LU, LS, R),
++ BroadcastEl = build_broadcast(U, S, Action),
++ ejabberd_router:route(LJID, LJID, BroadcastEl),
++ Item = build_roster_item(U, S, Action),
++ ResIQ = build_iq_roster_push(Item),
++ ejabberd_router:route(LJID, LJID, ResIQ).
++
++build_roster_item(U, S, {add, Nick, Subs, Group}) ->
++ {xmlel, <<"item">>,
++ [{<<"jid">>, jlib:jid_to_string(jlib:make_jid(U, S,
<<>>))},
++ {<<"name">>, Nick},
++ {<<"subscription">>, Subs}],
++ [{xmlel, <<"group">>, [], [{xmlcdata, Group}]}]
++ };
++build_roster_item(U, S, remove) ->
++ {xmlel, <<"item">>,
++ [{<<"jid">>, jlib:jid_to_string(jlib:make_jid(U, S,
<<>>))},
++ {<<"subscription">>, <<"remove">>}],
++ []
++ }.
++
++build_iq_roster_push(Item) ->
++ {xmlel, <<"iq">>,
++ [{<<"type">>, <<"set">>},
{<<"id">>, <<"push">>}],
++ [{xmlel, <<"query">>,
++ [{<<"xmlns">>, ?NS_ROSTER}],
++ [Item]
++ }
++ ]
++ }.
++
++build_broadcast(U, S, {add, _Nick, Subs, _Group}) ->
++ build_broadcast(U, S, list_to_atom(binary_to_list(Subs)));
++build_broadcast(U, S, remove) ->
++ build_broadcast(U, S, none);
++%% @spec (U::binary(), S::binary(), Subs::atom()) -> any()
++%% Subs = both | from | to | none
++build_broadcast(U, S, SubsAtom) when is_atom(SubsAtom) ->
++ {broadcast, {item, {U, S, <<>>}, SubsAtom}}.
++
++%%%
++%%% Last Activity
++%%%
++
++get_last(User, Server) ->
++ Mod = get_lastactivity_module(Server),
++ case ejabberd_sm:get_user_resources(User, Server) of
++ [] ->
++ case Mod:get_last_info(User, Server) of
++ not_found ->
++ "Never";
++ {ok, Shift, _Status} ->
++ TimeStamp = {Shift div 1000000,
++ Shift rem 1000000,
++ 0},
++ {{Year, Month, Day}, {Hour, Minute, Second}} =
++ calendar:now_to_local_time(TimeStamp),
++ lists:flatten(
++ io_lib:format(
++ "~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w",
++ [Year, Month, Day, Hour, Minute, Second]))
++ end;
++ _ ->
++ "Online"
++ end.
++
++set_last(User, Server, Timestamp, Status) ->
++ Mod = get_lastactivity_module(Server),
++ Mod:store_last_info(User, Server, Timestamp, Status).
++
++%%%
++%%% Private Storage
++%%%
++
++%% Example usage:
++%% $ ejabberdctl private_set badlop localhost "\<aa\
xmlns=\'bb\'\>Cluth\</aa\>"
++%% $ ejabberdctl private_get badlop localhost aa bb
++%% <aa xmlns='bb'>Cluth</aa>
++
++private_get(Username, Host, Element, Ns) ->
++ From = jlib:make_jid(Username, Host, <<>>),
++ To = jlib:make_jid(Username, Host, <<>>),
++ IQ = {iq, <<>>, get, ?NS_PRIVATE, <<>>,
++ {xmlel, <<"query">>,
++ [{<<"xmlns">>,?NS_PRIVATE}],
++ [{xmlel, Element, [{<<"xmlns">>, Ns}], []}]}},
++ ResIq = mod_private:process_sm_iq(From, To, IQ),
++ [{xmlel, <<"query">>,
++ [{<<"xmlns">>,
<<"jabber:iq:private">>}],
++ [SubEl]}] = ResIq#iq.sub_el,
++ xml:element_to_string(SubEl).
++
++private_set(Username, Host, ElementString) ->
++ case xml_stream:parse_element(ElementString) of
++ {error, Error} ->
++ io:format("Error found parsing the element:~n ~p~nError: ~p~n",
++ [ElementString, Error]),
++ error;
++ Xml ->
++ private_set2(Username, Host, Xml)
++ end.
++
++private_set2(Username, Host, Xml) ->
++ From = jlib:make_jid(Username, Host, <<>>),
++ To = jlib:make_jid(Username, Host, <<>>),
++ IQ = {iq, <<>>, set, ?NS_PRIVATE, <<>>,
++ {xmlel, <<"query">>,
++ [{<<"xmlns">>, ?NS_PRIVATE}],
++ [Xml]}},
++ mod_private:process_sm_iq(From, To, IQ),
++ ok.
++
++%%%
++%%% Shared Roster Groups
++%%%
++
++srg_create(Group, Host, Name, Description, Display) ->
++ DisplayList = case Display of
++ [] -> [];
++ _ -> ejabberd_regexp:split(Display, <<"\\\\n">>)
++ end,
++ Opts = [{name, Name},
++ {displayed_groups, DisplayList},
++ {description, Description}],
++ {atomic, ok} = mod_shared_roster:create_group(Host, Group, Opts),
++ ok.
++
++srg_delete(Group, Host) ->
++ {atomic, ok} = mod_shared_roster:delete_group(Host, Group),
++ ok.
++
++srg_list(Host) ->
++ lists:sort(mod_shared_roster:list_groups(Host)).
++
++srg_get_info(Group, Host) ->
++ Opts = case mod_shared_roster:get_group_opts(Host,Group) of
++ Os when is_list(Os) -> Os;
++ error -> []
++ end,
++ [{io_lib:format("~p", [Title]),
++ io_lib:format("~p", [Value])} || {Title, Value} <- Opts].
++
++srg_get_members(Group, Host) ->
++ Members = mod_shared_roster:get_group_explicit_users(Host,Group),
++ [jlib:jid_to_string(jlib:make_jid(MUser, MServer, <<>>))
++ || {MUser, MServer} <- Members].
++
++srg_user_add(User, Host, Group, GroupHost) ->
++ {atomic, ok} = mod_shared_roster:add_user_to_group(GroupHost, {User, Host}, Group),
++ ok.
++
++srg_user_del(User, Host, Group, GroupHost) ->
++ {atomic, ok} = mod_shared_roster:remove_user_from_group(GroupHost, {User, Host},
Group),
++ ok.
++
++
++%%%
++%%% Stanza
++%%%
++
++%% @doc Send a chat message to a Jabber account.
++%% @spec (From::binary(), To::binary(), Body::binary()) -> ok
++send_message_chat(From, To, Body) ->
++ Packet = build_packet(message_chat, [Body]),
++ send_packet_all_resources(From, To, Packet).
++
++%% @doc Send a headline message to a Jabber account.
++%% @spec (From::binary(), To::binary(), Subject::binary(), Body::binary()) -> ok
++send_message_headline(From, To, Subject, Body) ->
++ Packet = build_packet(message_headline, [Subject, Body]),
++ send_packet_all_resources(From, To, Packet).
++
++%% @doc Send a packet to a Jabber account.
++%% If a resource was specified in the JID,
++%% the packet is sent only to that specific resource.
++%% If no resource was specified in the JID,
++%% and the user is remote or local but offline,
++%% the packet is sent to the bare JID.
++%% If the user is local and is online in several resources,
++%% the packet is sent to all its resources.
++send_packet_all_resources(FromJIDString, ToJIDString, Packet) ->
++ FromJID = jlib:string_to_jid(FromJIDString),
++ ToJID = jlib:string_to_jid(ToJIDString),
++ ToUser = ToJID#jid.user,
++ ToServer = ToJID#jid.server,
++ case ToJID#jid.resource of
++ <<>> ->
++ send_packet_all_resources(FromJID, ToUser, ToServer, Packet);
++ Res ->
++ send_packet_all_resources(FromJID, ToUser, ToServer, Res, Packet)
++ end.
++
++send_packet_all_resources(FromJID, ToUser, ToServer, Packet) ->
++ case ejabberd_sm:get_user_resources(ToUser, ToServer) of
++ [] ->
++ send_packet_all_resources(FromJID, ToUser, ToServer, <<>>, Packet);
++ ToResources ->
++ lists:foreach(
++ fun(ToResource) ->
++ send_packet_all_resources(FromJID, ToUser, ToServer,
++ ToResource, Packet)
++ end,
++ ToResources)
++ end.
++
++send_packet_all_resources(FromJID, ToU, ToS, ToR, Packet) ->
++ ToJID = jlib:make_jid(ToU, ToS, ToR),
++ ejabberd_router:route(FromJID, ToJID, Packet).
++
++
++build_packet(message_chat, [Body]) ->
++ {xmlel, <<"message">>,
++ [{<<"type">>, <<"chat">>},
{<<"id">>, randoms:get_string()}],
++ [{xmlel, <<"body">>, [], [{xmlcdata, Body}]}]
++ };
++build_packet(message_headline, [Subject, Body]) ->
++ {xmlel, <<"message">>,
++ [{<<"type">>, <<"headline">>},
{<<"id">>, randoms:get_string()}],
++ [{xmlel, <<"subject">>, [], [{xmlcdata, Subject}]},
++ {xmlel, <<"body">>, [], [{xmlcdata, Body}]}
++ ]
++ }.
++
++send_stanza_c2s(Username, Host, Resource, Stanza) ->
++ C2sPid = ejabberd_sm:get_session_pid(Username, Host, Resource),
++ XmlEl = xml_stream:parse_element(Stanza),
++ p1_fsm:send_event(C2sPid, {xmlstreamelement, XmlEl}).
++
++privacy_set(Username, Host, QueryS) ->
++ From = jlib:string_to_jid(Username ++ "@" ++ Host),
++ To = jlib:string_to_jid(Host),
++ QueryEl = xml_stream:parse_element(QueryS),
++ StanzaEl = {xmlel, <<"iq">>,
[{<<"type">>, <<"set">>}], [QueryEl]},
++ IQ = jlib:iq_query_info(StanzaEl),
++ ejabberd_hooks:run_fold(
++ privacy_iq_set,
++ Host,
++ {error, ?ERR_FEATURE_NOT_IMPLEMENTED},
++ [From, To, IQ]
++ ),
++ ok.
++
++%%%
++%%% Stats
++%%%
++
++stats(Name) ->
++ case Name of
++ <<"uptimeseconds">> -> trunc(element(1,
erlang:statistics(wall_clock))/1000);
++ <<"registeredusers">> ->
length(ejabberd_auth:dirty_get_registered_users());
++ <<"onlineusersnode">> ->
length(ejabberd_sm:dirty_get_my_sessions_list());
++ <<"onlineusers">> ->
length(ejabberd_sm:dirty_get_sessions_list())
++ end.
++
++stats(Name, Host) ->
++ case Name of
++ <<"registeredusers">> ->
length(ejabberd_auth:get_vh_registered_users(Host));
++ <<"onlineusers">> ->
length(ejabberd_sm:get_vh_session_list(Host))
++ end.
++
++
++
++%%-----------------------------
++%% Purge roster items
++%%-----------------------------
++
++process_rosteritems(ActionS, SubsS, AsksS, UsersS, ContactsS) ->
++ Action = case ActionS of
++ "list" -> list;
++ "delete" -> delete
++ end,
++
++ Subs = lists:foldl(
++ fun(any, _) -> [none, from, to, both];
++ (Sub, Subs) -> [Sub | Subs]
++ end,
++ [],
++ [list_to_atom(S) || S <- string:tokens(SubsS, ":")]
++ ),
++
++ Asks = lists:foldl(
++ fun(any, _) -> [none, out, in];
++ (Ask, Asks) -> [Ask | Asks]
++ end,
++ [],
++ [list_to_atom(S) || S <- string:tokens(AsksS, ":")]
++ ),
++
++ Users = lists:foldl(
++ fun("any", _) -> ["*", "*@*"];
++ (U, Us) -> [U | Us]
++ end,
++ [],
++ [S || S <- string:tokens(UsersS, ":")]
++ ),
++
++ Contacts = lists:foldl(
++ fun("any", _) -> ["*", "*@*"];
++ (U, Us) -> [U | Us]
++ end,
++ [],
++ [S || S <- string:tokens(ContactsS, ":")]
++ ),
++
++ case rosteritem_purge({Action, Subs, Asks, Users, Contacts}) of
++ {atomic, Res} ->
++ Res;
++ {error, Reason} ->
++ io:format("Error purging rosteritems: ~p~n", [Reason]),
++ error;
++ {badrpc, Reason} ->
++ io:format("BadRPC purging rosteritems: ~p~n", [Reason]),
++ error
++ end.
++
++%% @spec ({Action::atom(), Subs::[atom()], Asks::[atom()], User::string(),
Contact::string()}) -> {atomic, ok}
++rosteritem_purge(Options) ->
++ Num_rosteritems = mnesia:table_info(roster, size),
++ io:format("There are ~p roster items in total.~n", [Num_rosteritems]),
++ Key = mnesia:dirty_first(roster),
++ Res = rip(Key, Options, {0, Num_rosteritems, 0, 0}, []),
++ {atomic, Res}.
++
++rip('$end_of_table', _Options, Counters, Res) ->
++ print_progress_line(Counters),
++ Res;
++rip(Key, Options, {Pr, NT, NV, ND}, Res) ->
++ Key_next = mnesia:dirty_next(roster, Key),
++ {Action, _, _, _, _} = Options,
++ {ND2, Res2} = case decide_rip(Key, Options) of
++ true ->
++ Jids = apply_action(Action, Key),
++ {ND+1, [Jids | Res]};
++ false ->
++ {ND, Res}
++ end,
++ NV2 = NV+1,
++ Pr2 = print_progress_line({Pr, NT, NV2, ND2}),
++ rip(Key_next, Options, {Pr2, NT, NV2, ND2}, Res2).
++
++apply_action(list, Key) ->
++ {User, Server, JID} = Key,
++ {RUser, RServer, _} = JID,
++ Jid1string = User ++ "@" ++ Server,
++ Jid2string = RUser ++ "@" ++ RServer,
++ io:format("Matches: ~s ~s~n", [Jid1string, Jid2string]),
++ {Jid1string, Jid2string};
++apply_action(delete, Key) ->
++ R = apply_action(list, Key),
++ mnesia:dirty_delete(roster, Key),
++ R.
++
++print_progress_line({Pr, NT, NV, ND}) ->
++ Pr2 = trunc((NV/NT)*100),
++ case Pr == Pr2 of
++ true ->
++ ok;
++ false ->
++ io:format("Progress ~p% - visited ~p - deleted ~p~n", [Pr2, NV, ND])
++ end,
++ Pr2.
++
++decide_rip(Key, {_Action, Subs, Asks, User, Contact}) ->
++ case catch mnesia:dirty_read(roster, Key) of
++ [RI] ->
++ lists:member(RI#roster.subscription, Subs)
++ andalso lists:member(RI#roster.ask, Asks)
++ andalso decide_rip_jid(RI#roster.us, User)
++ andalso decide_rip_jid(RI#roster.jid, Contact);
++ _ ->
++ false
++ end.
++
++%% Returns true if the server of the JID is included in the servers
++decide_rip_jid({UName, UServer, _UResource}, Match_list) ->
++ decide_rip_jid({UName, UServer}, Match_list);
++decide_rip_jid({UName, UServer}, Match_list) ->
++ lists:any(
++ fun(Match_string) ->
++ MJID = jlib:string_to_jid(Match_string),
++ MName = MJID#jid.luser,
++ MServer = MJID#jid.lserver,
++ Is_server = is_glob_match(UServer, MServer),
++ case MName of
++ [] when UName == [] ->
++ Is_server;
++ [] ->
++ false;
++ _ ->
++ Is_server
++ andalso is_glob_match(UName, MName)
++ end
++ end,
++ Match_list).
++
++%% Copied from ejabberd-2.0.0/src/acl.erl
++is_regexp_match(String, RegExp) ->
++ case ejabberd_regexp:run(String, RegExp) of
++ nomatch ->
++ false;
++ match ->
++ true;
++ {error, ErrDesc} ->
++ io:format(
++ "Wrong regexp ~p in ACL: ~p",
++ [RegExp, ErrDesc]),
++ false
++ end.
++is_glob_match(String, [$! | Glob]) ->
++ not is_regexp_match(String, ejabberd_regexp:sh_to_awk(Glob));
++is_glob_match(String, Glob) ->
++ is_regexp_match(String, ejabberd_regexp:sh_to_awk(Glob)).
diff --git a/ejabberd-0003-Fedora-specific-changes-to-ejabberdctl.patch
b/ejabberd-0003-Fedora-specific-changes-to-ejabberdctl.patch
new file mode 100644
index 0000000..f9cf331
--- /dev/null
+++ b/ejabberd-0003-Fedora-specific-changes-to-ejabberdctl.patch
@@ -0,0 +1,19 @@
+From: Peter Lemenkov <lemenkov(a)gmail.com>
+Date: Tue, 16 Feb 2010 16:30:05 +0300
+Subject: [PATCH] Fedora-specific changes to ejabberdctl
+
+Signed-off-by: Peter Lemenkov <lemenkov(a)gmail.com>
+
+diff --git a/ejabberdctl.template b/ejabberdctl.template
+index a86694f..09b9947 100755
+--- a/ejabberdctl.template
++++ b/ejabberdctl.template
+@@ -22,7 +22,7 @@ if [ "$INSTALLUSER" != "" ] ; then
+ EXEC_CMD="false"
+ for GID in `id -G`; do
+ if [ $GID -eq 0 ] ; then
+- EXEC_CMD="su $INSTALLUSER -p -c"
++ EXEC_CMD="/sbin/runuser -s /bin/bash -p ejabberd -c"
+ fi
+ done
+ if [ `id -g` -eq `id -g $INSTALLUSER` ] ; then
diff --git a/ejabberd-0003-Introducing-mod_admin_extra.patch
b/ejabberd-0003-Introducing-mod_admin_extra.patch
deleted file mode 100644
index 3f9d8a7..0000000
--- a/ejabberd-0003-Introducing-mod_admin_extra.patch
+++ /dev/null
@@ -1,1607 +0,0 @@
-From 363bfab713d9267e3186126d2df4162f24969d8c Mon Sep 17 00:00:00 2001
-From: Badlop <badlop(a)process-one.net>
-Date: Tue, 16 Feb 2010 16:12:17 +0300
-Subject: [PATCH 03/10] Introducing mod_admin_extra
-
-Adds the mod_admin_extra module to ejabberd.
-This module extends the functionality provided by ejabberdctl
-by adding several new commands.
-
-The code is taken from the ProcessOne repository:
-
-svn export -r 1125
https://svn.process-one.net/ejabberd-modules/mod_admin_extra/trunk/src/mo...
----
- src/ejabberd.app | 1 +
- src/mod_admin_extra.erl | 1568 +++++++++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 1569 insertions(+)
- create mode 100644 src/mod_admin_extra.erl
-
-diff --git a/src/ejabberd.app b/src/ejabberd.app
-index 1320597..4efc68d 100644
---- a/src/ejabberd.app
-+++ b/src/ejabberd.app
-@@ -99,6 +99,7 @@
- mod_vcard,
- mod_vcard_ldap,
- mod_version,
-+ mod_admin_extra,
- node_buddy,
- node_club,
- node_default,
-diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl
-new file mode 100644
-index 0000000..1cef25a
---- /dev/null
-+++ b/src/mod_admin_extra.erl
-@@ -0,0 +1,1568 @@
-+%%%-------------------------------------------------------------------
-+%%% File : mod_admin_extra.erl
-+%%% Author : Badlop <badlop(a)process-one.net>
-+%%% Purpose : Contributed administrative functions and commands
-+%%% Created : 10 Aug 2008 by Badlop <badlop(a)process-one.net>
-+%%%
-+%%%
-+%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
-+%%%
-+%%% This program is free software; you can redistribute it and/or
-+%%% modify it under the terms of the GNU General Public License as
-+%%% published by the Free Software Foundation; either version 2 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
-+%%% General Public License for more details.
-+%%%
-+%%% You should have received a copy of the GNU General Public License
-+%%% along with this program; if not, write to the Free Software
-+%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-+%%% 02111-1307 USA
-+%%%
-+%%%-------------------------------------------------------------------
-+
-+-module(mod_admin_extra).
-+-author('badlop(a)process-one.net').
-+
-+-behaviour(gen_mod).
-+
-+-export([start/2, stop/1,
-+ %% Node
-+ compile/1,
-+ load_config/1,
-+ get_cookie/0,
-+ remove_node/1,
-+ export2odbc/2,
-+ %% Accounts
-+ set_password/3,
-+ check_password_hash/4,
-+ delete_old_users/1,
-+ delete_old_users_vhost/2,
-+ ban_account/3,
-+ num_active_users/2,
-+ %% Sessions
-+ num_resources/2,
-+ resource_num/3,
-+ kick_session/4,
-+ status_num/2, status_num/1,
-+ status_list/2, status_list/1,
-+ connected_users_info/0,
-+ connected_users_vhost/1,
-+ set_presence/7,
-+ user_sessions_info/2,
-+ %% Vcard
-+ set_nickname/3,
-+ get_vcard/3,
-+ get_vcard/4,
-+ get_vcard_multi/4,
-+ set_vcard/4,
-+ set_vcard/5,
-+ %% Roster
-+ add_rosteritem/7,
-+ delete_rosteritem/4,
-+ process_rosteritems/5,
-+ get_roster/2,
-+ push_roster/3,
-+ push_roster_all/1,
-+ push_alltoall/2,
-+ %% mod_last
-+ set_last/4,
-+ %% mod_private
-+ private_get/4,
-+ private_set/3,
-+ %% mod_shared_roster
-+ srg_create/5,
-+ srg_delete/2,
-+ srg_list/1,
-+ srg_get_info/2,
-+ srg_get_members/2,
-+ srg_user_add/4,
-+ srg_user_del/4,
-+ %% Stanza
-+ send_message_headline/4,
-+ send_message_chat/3,
-+ send_stanza_c2s/4,
-+ privacy_set/3,
-+ %% Stats
-+ stats/1, stats/2
-+ ]).
-+
-+-include("ejabberd.hrl").
-+-include("ejabberd_commands.hrl").
-+-include("mod_roster.hrl").
-+-include("jlib.hrl").
-+
-+%% Copied from ejabberd_sm.erl
-+-record(session, {sid, usr, us, priority, info}).
-+
-+
-+%%%
-+%%% gen_mod
-+%%%
-+
-+start(_Host, _Opts) ->
-+ ejabberd_commands:register_commands(commands()).
-+
-+stop(_Host) ->
-+ ejabberd_commands:unregister_commands(commands()).
-+
-+
-+%%%
-+%%% Register commands
-+%%%
-+
-+commands() ->
-+ Vcard1FieldsString = "Some vcard field names in get/set_vcard are:\n"
-+ " FN - Full Name\n"
-+ " NICKNAME - Nickname\n"
-+ " BDAY - Birthday\n"
-+ " TITLE - Work: Position\n"
-+ " ROLE - Work: Role",
-+
-+ Vcard2FieldsString = "Some vcard field names and subnames in get/set_vcard2
are:\n"
-+ " N FAMILY - Family name\n"
-+ " N GIVEN - Given name\n"
-+ " N MIDDLE - Middle name\n"
-+ " ADR CTRY - Address: Country\n"
-+ " ADR LOCALITY - Address: City\n"
-+ " EMAIL USERID - E-Mail Address\n"
-+ " ORG ORGNAME - Work: Company\n"
-+ " ORG ORGUNIT - Work: Department",
-+
-+ VcardXEP = "For a full list of vCard fields check XEP-0054: vcard-temp at
"
-+ "http://www.xmpp.org/extensions/xep-0054.html",
-+
-+ [
-+ #ejabberd_commands{name = compile, tags = [erlang],
-+ desc = "Recompile and reload Erlang source code file",
-+ module = ?MODULE, function = compile,
-+ args = [{file, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = load_config, tags = [server],
-+ desc = "Load ejabberd configuration file",
-+ module = ?MODULE, function = load_config,
-+ args = [{file, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = get_cookie, tags = [erlang],
-+ desc = "Get the Erlang cookie of this node",
-+ module = ?MODULE, function = get_cookie,
-+ args = [],
-+ result = {cookie, string}},
-+ #ejabberd_commands{name = remove_node, tags = [erlang],
-+ desc = "Remove an ejabberd node from Mnesia clustering config",
-+ module = ?MODULE, function = remove_node,
-+ args = [{node, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = export2odbc, tags = [mnesia],
-+ desc = "Export Mnesia tables to files in directory",
-+ module = ?MODULE, function = export2odbc,
-+ args = [{host, string}, {path, string}],
-+ result = {res, rescode}},
-+
-+ #ejabberd_commands{name = num_active_users, tags = [accounts, stats],
-+ desc = "Get number of users active in the last days",
-+ module = ?MODULE, function = num_active_users,
-+ args = [{host, string}, {days, integer}],
-+ result = {users, integer}},
-+ #ejabberd_commands{name = delete_old_users, tags = [accounts, purge],
-+ desc = "Delete users that didn't log in last days, or that never
logged",
-+ module = ?MODULE, function = delete_old_users,
-+ args = [{days, integer}],
-+ result = {res, restuple}},
-+ #ejabberd_commands{name = delete_old_users_vhost, tags = [accounts, purge],
-+ desc = "Delete users that didn't log in last days in vhost, or that never
logged",
-+ module = ?MODULE, function = delete_old_users_vhost,
-+ args = [{host, string}, {days, integer}],
-+ result = {res, restuple}},
-+
-+ #ejabberd_commands{name = check_account, tags = [accounts],
-+ desc = "Check if an account exists or not",
-+ module = ejabberd_auth, function = is_user_exists,
-+ args = [{user, string}, {host, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = check_password, tags = [accounts],
-+ desc = "Check if a password is correct",
-+ module = ejabberd_auth, function = check_password,
-+ args = [{user, string}, {host, string}, {password, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = check_password_hash, tags = [accounts],
-+ desc = "Check if the password hash is correct",
-+ longdesc = "Allowed hash methods: md5, sha.",
-+ module = ?MODULE, function = check_password_hash,
-+ args = [{user, string}, {host, string}, {passwordhash, string}, {hashmethod,
string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = change_password, tags = [accounts],
-+ desc = "Change the password of an account",
-+ module = ?MODULE, function = set_password,
-+ args = [{user, string}, {host, string}, {newpass, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = ban_account, tags = [accounts],
-+ desc = "Ban an account: kick sessions and set random password",
-+ module = ?MODULE, function = ban_account,
-+ args = [{user, string}, {host, string}, {reason, string}],
-+ result = {res, rescode}},
-+
-+ #ejabberd_commands{name = num_resources, tags = [session],
-+ desc = "Get the number of resources of a user",
-+ module = ?MODULE, function = num_resources,
-+ args = [{user, string}, {host, string}],
-+ result = {resources, integer}},
-+ #ejabberd_commands{name = resource_num, tags = [session],
-+ desc = "Resource string of a session number",
-+ module = ?MODULE, function = resource_num,
-+ args = [{user, string}, {host, string}, {num, integer}],
-+ result = {resource, string}},
-+ #ejabberd_commands{name = kick_session, tags = [session],
-+ desc = "Kick a user session",
-+ module = ?MODULE, function = kick_session,
-+ args = [{user, string}, {host, string}, {resource, string}, {reason, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = status_num_host, tags = [session, stats],
-+ desc = "Number of logged users with this status in host",
-+ module = ?MODULE, function = status_num,
-+ args = [{host, string}, {status, string}],
-+ result = {users, integer}},
-+ #ejabberd_commands{name = status_num, tags = [session, stats],
-+ desc = "Number of logged users with this status",
-+ module = ?MODULE, function = status_num,
-+ args = [{status, string}],
-+ result = {users, integer}},
-+ #ejabberd_commands{name = status_list_host, tags = [session],
-+ desc = "List of users logged in host with their statuses",
-+ module = ?MODULE, function = status_list,
-+ args = [{host, string}, {status, string}],
-+ result = {users, {list,
-+ {userstatus, {tuple, [
-+ {user, string},
-+ {host, string},
-+ {resource, string},
-+ {priority, integer},
-+ {status, string}
-+ ]}}
-+ }}},
-+ #ejabberd_commands{name = status_list, tags = [session],
-+ desc = "List of logged users with this status",
-+ module = ?MODULE, function = status_list,
-+ args = [{status, string}],
-+ result = {users, {list,
-+ {userstatus, {tuple, [
-+ {user, string},
-+ {host, string},
-+ {resource, string},
-+ {priority, integer},
-+ {status, string}
-+ ]}}
-+ }}},
-+ #ejabberd_commands{name = connected_users_info,
-+ tags = [session],
-+ desc = "List all established sessions and their information",
-+ module = ?MODULE, function = connected_users_info,
-+ args = [],
-+ result = {connected_users_info,
-+ {list,
-+ {sessions, {tuple,
-+ [{jid, string},
-+ {connection, string},
-+ {ip, string},
-+ {port, integer},
-+ {priority, integer},
-+ {node, string},
-+ {uptime, integer}
-+ ]}}
-+ }}},
-+ #ejabberd_commands{name = connected_users_vhost,
-+ tags = [session],
-+ desc = "Get the list of established sessions in a
vhost",
-+ module = ?MODULE, function = connected_users_vhost,
-+ args = [{host, string}],
-+ result = {connected_users_vhost, {list, {sessions, string}}}},
-+ #ejabberd_commands{name = user_sessions_info,
-+ tags = [session],
-+ desc = "Get information about all sessions of a user",
-+ module = ?MODULE, function = user_sessions_info,
-+ args = [{user, string}, {host, string}],
-+ result = {sessions_info,
-+ {list,
-+ {session, {tuple,
-+ [{connection, string},
-+ {ip, string},
-+ {port, integer},
-+ {priority, integer},
-+ {node, string},
-+ {uptime, integer},
-+ {status, string},
-+ {resource, string},
-+ {statustext, string}
-+ ]}}
-+ }}},
-+
-+ #ejabberd_commands{name = set_presence,
-+ tags = [session],
-+ desc = "Set presence of a session",
-+ module = ?MODULE, function = set_presence,
-+ args = [{user, string}, {host, string},
-+ {resource, string}, {type, string},
-+ {show, string}, {status, string},
-+ {priority, string}],
-+ result = {res, rescode}},
-+
-+ #ejabberd_commands{name = set_nickname, tags = [vcard],
-+ desc = "Set nickname in a user's vCard",
-+ module = ?MODULE, function = set_nickname,
-+ args = [{user, string}, {host, string}, {nickname, string}],
-+ result = {res, rescode}},
-+
-+ #ejabberd_commands{name = get_vcard, tags = [vcard],
-+ desc = "Get content from a vCard field",
-+ longdesc = Vcard1FieldsString ++ "\n" ++ Vcard2FieldsString ++
"\n\n" ++ VcardXEP,
-+ module = ?MODULE, function = get_vcard,
-+ args = [{user, string}, {host, string}, {name, string}],
-+ result = {content, string}},
-+ #ejabberd_commands{name = get_vcard2, tags = [vcard],
-+ desc = "Get content from a vCard field",
-+ longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++
"\n" ++ VcardXEP,
-+ module = ?MODULE, function = get_vcard,
-+ args = [{user, string}, {host, string}, {name, string}, {subname, string}],
-+ result = {content, string}},
-+ #ejabberd_commands{name = get_vcard2_multi, tags = [vcard],
-+ desc = "Get multiple contents from a vCard field (requires exmpp
installed)",
-+ longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++
"\n" ++ VcardXEP,
-+ module = ?MODULE, function = get_vcard_multi,
-+ args = [{user, string}, {host, string}, {name, string}, {subname, string}],
-+ result = {contents, {list, string}}},
-+
-+ #ejabberd_commands{name = set_vcard, tags = [vcard],
-+ desc = "Set content in a vCard field",
-+ longdesc = Vcard1FieldsString ++ "\n" ++ Vcard2FieldsString ++
"\n\n" ++ VcardXEP,
-+ module = ?MODULE, function = set_vcard,
-+ args = [{user, string}, {host, string}, {name, string}, {content, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = set_vcard2, tags = [vcard],
-+ desc = "Set content in a vCard subfield",
-+ longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++
"\n" ++ VcardXEP,
-+ module = ?MODULE, function = set_vcard,
-+ args = [{user, string}, {host, string}, {name, string}, {subname, string}, {content,
string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = set_vcard2_multi, tags = [vcard],
-+ desc = "Set multiple contents in a vCard subfield",
-+ longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++
"\n" ++ VcardXEP,
-+ module = ?MODULE, function = set_vcard,
-+ args = [{user, string}, {host, string}, {name, string}, {subname, string}, {contents,
{list, string}}],
-+ result = {res, rescode}},
-+
-+ #ejabberd_commands{name = add_rosteritem, tags = [roster],
-+ desc = "Add an item to a user's roster (supports ODBC)",
-+ module = ?MODULE, function = add_rosteritem,
-+ args = [{localuser, string}, {localserver, string},
-+ {user, string}, {server, string},
-+ {nick, string}, {group, string},
-+ {subs, string}],
-+ result = {res, rescode}},
-+ %%{"", "subs= none, from, to or both"},
-+ %%{"", "example: add-roster peter localhost mike
server.com MiKe
Employees both"},
-+ %%{"", "will add mike(a)server.com to peter@localhost roster"},
-+ #ejabberd_commands{name = delete_rosteritem, tags = [roster],
-+ desc = "Delete an item from a user's roster (supports ODBC)",
-+ module = ?MODULE, function = delete_rosteritem,
-+ args = [{localuser, string}, {localserver, string},
-+ {user, string}, {server, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = process_rosteritems, tags = [roster],
-+ desc = "List or delete rosteritems that match filtering options",
-+ longdesc = "Explanation of each argument:\n"
-+ " - action: what to do with each rosteritem that "
-+ "matches all the filtering options\n"
-+ " - subs: subscription type\n"
-+ " - asks: pending subscription\n"
-+ " - users: the JIDs of the local user\n"
-+ " - contacts: the JIDs of the contact in the roster\n"
-+ "\n"
-+ "Allowed values in the arguments:\n"
-+ " ACTION = list | delete\n"
-+ " SUBS = SUB[:SUB]* | any\n"
-+ " SUB = none | from | to | both\n"
-+ " ASKS = ASK[:ASK]* | any\n"
-+ " ASK = none | out | in\n"
-+ " USERS = JID[:JID]* | any\n"
-+ " CONTACTS = JID[:JID]* | any\n"
-+ " JID = characters valid in a JID, and can use the "
-+ "globs: *, ?, ! and [...]\n"
-+ "\n"
-+ "This example will list roster items with subscription "
-+ "'none', 'from' or 'to' that have any ask property, of
"
-+ "local users which JID is in the virtual host "
-+ "'example.org' and that the contact JID is either a "
-+ "bare server name (without user part) or that has a "
-+ "user part and the server part contains the word 'icq'"
-+ ":\n list none:from:to any *(a)example.org *:*@*icq*",
-+ module = ?MODULE, function = process_rosteritems,
-+ args = [{action, string}, {subs, string},
-+ {asks, string}, {users, string},
-+ {contacts, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = get_roster, tags = [roster],
-+ desc = "Get roster of a local user",
-+ module = ?MODULE, function = get_roster,
-+ args = [{user, string}, {host, string}],
-+ result = {contacts, {list, {contact, {tuple, [
-+ {jid, string},
-+ {nick, string},
-+ {subscription, string},
-+ {ask, string},
-+ {group, string}
-+ ]}}}}},
-+ #ejabberd_commands{name = push_roster, tags = [roster],
-+ desc = "Push template roster from file to a user",
-+ module = ?MODULE, function = push_roster,
-+ args = [{file, string}, {user, string}, {host, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = push_roster_all, tags = [roster],
-+ desc = "Push template roster from file to all those users",
-+ module = ?MODULE, function = push_roster_all,
-+ args = [{file, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = push_alltoall, tags = [roster],
-+ desc = "Add all the users to all the users of Host in Group",
-+ module = ?MODULE, function = push_alltoall,
-+ args = [{host, string}, {group, string}],
-+ result = {res, rescode}},
-+
-+ #ejabberd_commands{name = set_last, tags = [last],
-+ desc = "Set last activity information",
-+ longdesc = "Timestamp is the seconds since"
-+ "1970-01-01 00:00:00 UTC, for example: date +%s",
-+ module = ?MODULE, function = set_last,
-+ args = [{user, string}, {host, string}, {timestamp, integer}, {status, string}],
-+ result = {res, rescode}},
-+
-+ #ejabberd_commands{name = private_get, tags = [private],
-+ desc = "Get some information from a user private storage",
-+ module = ?MODULE, function = private_get,
-+ args = [{user, string}, {host, string}, {element, string}, {ns, string}],
-+ result = {res, string}},
-+ #ejabberd_commands{name = private_set, tags = [private],
-+ desc = "Set to the user private storage",
-+ module = ?MODULE, function = private_set,
-+ args = [{user, string}, {host, string}, {element, string}],
-+ result = {res, rescode}},
-+
-+ #ejabberd_commands{name = srg_create, tags = [shared_roster_group],
-+ desc = "Create a Shared Roster Group",
-+ longdesc = "If you want to specify several group "
-+ "identifiers in the Display argument,\n"
-+ "put \\ \" around the argument and\nseparate the "
-+ "identifiers with \\ \\ n\n"
-+ "For example:\n"
-+ " ejabberdctl srg_create group3 localhost "
-+ "name desc \\\"group1\\\\ngroup2\\\"",
-+ module = ?MODULE, function = srg_create,
-+ args = [{group, string}, {host, string},
-+ {name, string}, {description, string}, {display, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = srg_delete, tags = [shared_roster_group],
-+ desc = "Delete a Shared Roster Group",
-+ module = ?MODULE, function = srg_delete,
-+ args = [{group, string}, {host, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = srg_list, tags = [shared_roster_group],
-+ desc = "List the Shared Roster Groups in Host",
-+ module = ?MODULE, function = srg_list,
-+ args = [{host, string}],
-+ result = {groups, {list, {id, string}}}},
-+ #ejabberd_commands{name = srg_get_info, tags = [shared_roster_group],
-+ desc = "Get info of a Shared Roster Group",
-+ module = ?MODULE, function = srg_get_info,
-+ args = [{group, string}, {host, string}],
-+ result = {informations, {list, {information, {tuple, [{key, string}, {value,
string}]}}}}},
-+ #ejabberd_commands{name = srg_get_members, tags = [shared_roster_group],
-+ desc = "Get members of a Shared Roster Group",
-+ module = ?MODULE, function = srg_get_members,
-+ args = [{group, string}, {host, string}],
-+ result = {members, {list, {member, string}}}},
-+ #ejabberd_commands{name = srg_user_add, tags = [shared_roster_group],
-+ desc = "Add the JID user@host to the Shared Roster Group",
-+ module = ?MODULE, function = srg_user_add,
-+ args = [{user, string}, {host, string}, {group, string}, {grouphost, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = srg_user_del, tags = [shared_roster_group],
-+ desc = "Delete this JID user@host from the Shared Roster Group",
-+ module = ?MODULE, function = srg_user_del,
-+ args = [{user, string}, {host, string}, {group, string}, {grouphost, string}],
-+ result = {res, rescode}},
-+
-+ #ejabberd_commands{name = send_message_chat, tags = [stanza],
-+ desc = "Send a chat message to a local or remote bare of full JID",
-+ module = ?MODULE, function = send_message_chat,
-+ args = [{from, string}, {to, string}, {body, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = send_message_headline, tags = [stanza],
-+ desc = "Send a headline message to a local or remote bare of full JID",
-+ module = ?MODULE, function = send_message_headline,
-+ args = [{from, string}, {to, string},
-+ {subject, string}, {body, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = send_stanza_c2s, tags = [stanza],
-+ desc = "Send a stanza as if sent from a c2s session",
-+ module = ?MODULE, function = send_stanza_c2s,
-+ args = [{user, string}, {host, string}, {resource, string}, {stanza, string}],
-+ result = {res, rescode}},
-+ #ejabberd_commands{name = privacy_set, tags = [stanza],
-+ desc = "Send a IQ set privacy stanza for a local account",
-+ module = ?MODULE, function = privacy_set,
-+ args = [{user, string}, {host, string}, {xmlquery, string}],
-+ result = {res, rescode}},
-+
-+ #ejabberd_commands{name = stats, tags = [stats],
-+ desc = "Get statistical value: registeredusers onlineusers onlineusersnode
uptimeseconds",
-+ module = ?MODULE, function = stats,
-+ args = [{name, string}],
-+ result = {stat, integer}},
-+ #ejabberd_commands{name = stats_host, tags = [stats],
-+ desc = "Get statistical value for this host: registeredusers onlineusers",
-+ module = ?MODULE, function = stats,
-+ args = [{name, string}, {host, string}],
-+ result = {stat, integer}}
-+ ].
-+
-+
-+%%%
-+%%% Node
-+%%%
-+
-+compile(File) ->
-+ case compile:file(File) of
-+ ok -> ok;
-+ _ -> error
-+ end.
-+
-+load_config(Path) ->
-+ ok = ejabberd_config:load_file(Path).
-+
-+get_cookie() ->
-+ atom_to_list(erlang:get_cookie()).
-+
-+remove_node(Node) ->
-+ mnesia:del_table_copy(schema, list_to_atom(Node)),
-+ ok.
-+
-+export2odbc(Host, Directory) ->
-+ Tables = [
-+ {export_last, last},
-+ {export_offline, offline},
-+ {export_passwd, passwd},
-+ {export_private_storage, private_storage},
-+ {export_roster, roster},
-+ {export_vcard, vcard},
-+ {export_vcard_search, vcard_search}],
-+ Export = fun({TableFun, Table}) ->
-+ Filename = filename:join([Directory, atom_to_list(Table)++".txt"]),
-+ io:format("Trying to export Mnesia table '~p' on Host '~s'
to file '~s'~n", [Table, Host, Filename]),
-+ Res = (catch ejd2odbc:TableFun(Host, Filename)),
-+ io:format(" Result: ~p~n", [Res])
-+ end,
-+ lists:foreach(Export, Tables),
-+ ok.
-+
-+
-+%%%
-+%%% Accounts
-+%%%
-+
-+set_password(User, Host, Password) ->
-+ case ejabberd_auth:set_password(User, Host, Password) of
-+ ok ->
-+ ok;
-+ _ ->
-+ error
-+ end.
-+
-+%% Copied some code from ejabberd_commands.erl
-+check_password_hash(User, Host, PasswordHash, HashMethod) ->
-+ AccountPass = ejabberd_auth:get_password_s(User, Host),
-+ AccountPassHash = case HashMethod of
-+ "md5" -> get_md5(AccountPass);
-+ "sha" -> get_sha(AccountPass);
-+ _ -> undefined
-+ end,
-+ case AccountPassHash of
-+ undefined -> error;
-+ PasswordHash -> ok;
-+ _ -> error
-+ end.
-+get_md5(AccountPass) ->
-+ lists:flatten([io_lib:format("~.16B", [X])
-+ || X <- binary_to_list(crypto:md5(AccountPass))]).
-+get_sha(AccountPass) ->
-+ lists:flatten([io_lib:format("~.16B", [X])
-+ || X <- binary_to_list(crypto:sha(AccountPass))]).
-+
-+num_active_users(Host, Days) ->
-+ list_last_activity(Host, true, Days).
-+
-+%% Code based on ejabberd/src/web/ejabberd_web_admin.erl
-+list_last_activity(Host, Integral, Days) ->
-+ {MegaSecs, Secs, _MicroSecs} = now(),
-+ TimeStamp = MegaSecs * 1000000 + Secs,
-+ TS = TimeStamp - Days * 86400,
-+ case catch mnesia:dirty_select(
-+ last_activity, [{{last_activity, {'_', Host}, '$1', '_'},
-+ [{'>', '$1', TS}],
-+ [{'trunc', {'/',
-+ {'-', TimeStamp, '$1'},
-+ 86400}}]}]) of
-+ {'EXIT', _Reason} ->
-+ [];
-+ Vals ->
-+ Hist = histogram(Vals, Integral),
-+ if
-+ Hist == [] ->
-+ 0;
-+ true ->
-+ Left = Days - length(Hist),
-+ Tail = if
-+ Integral ->
-+ lists:duplicate(Left, lists:last(Hist));
-+ true ->
-+ lists:duplicate(Left, 0)
-+ end,
-+ lists:nth(Days, Hist ++ Tail)
-+ end
-+ end.
-+histogram(Values, Integral) ->
-+ histogram(lists:sort(Values), Integral, 0, 0, []).
-+histogram([H | T], Integral, Current, Count, Hist) when Current == H ->
-+ histogram(T, Integral, Current, Count + 1, Hist);
-+histogram([H | _] = Values, Integral, Current, Count, Hist) when Current < H ->
-+ if
-+ Integral ->
-+ histogram(Values, Integral, Current + 1, Count, [Count | Hist]);
-+ true ->
-+ histogram(Values, Integral, Current + 1, 0, [Count | Hist])
-+ end;
-+histogram([], _Integral, _Current, Count, Hist) ->
-+ if
-+ Count > 0 ->
-+ lists:reverse([Count | Hist]);
-+ true ->
-+ lists:reverse(Hist)
-+ end.
-+
-+
-+delete_old_users(Days) ->
-+ %% Get the list of registered users
-+ Users = ejabberd_auth:dirty_get_registered_users(),
-+
-+ {removed, N, UR} = delete_old_users(Days, Users),
-+ {ok, io_lib:format("Deleted ~p users: ~p", [N, UR])}.
-+
-+delete_old_users_vhost(Host, Days) ->
-+ %% Get the list of registered users
-+ Users = ejabberd_auth:get_vh_registered_users(Host),
-+
-+ {removed, N, UR} = delete_old_users(Days, Users),
-+ {ok, io_lib:format("Deleted ~p users: ~p", [N, UR])}.
-+
-+delete_old_users(Days, Users) ->
-+ %% Convert older time
-+ SecOlder = Days*24*60*60,
-+
-+ %% Get current time
-+ {MegaSecs, Secs, _MicroSecs} = now(),
-+ TimeStamp_now = MegaSecs * 1000000 + Secs,
-+
-+ %% For a user, remove if required and answer true
-+ F = fun({LUser, LServer}) ->
-+ %% Check if the user is logged
-+ case ejabberd_sm:get_user_resources(LUser, LServer) of
-+ %% If it isnt
-+ [] ->
-+ %% Look for his last_activity
-+ case (get_lastactivity_module(LServer)):get_last_info(LUser, LServer) of
-+ %% If it is
-+ %% existent:
-+ {ok, TimeStamp, _Status} ->
-+ %% get his age
-+ Sec = TimeStamp_now - TimeStamp,
-+ %% If he is
-+ if
-+ %% younger than SecOlder:
-+ Sec < SecOlder ->
-+ %% do nothing
-+ false;
-+ %% older:
-+ true ->
-+ %% remove the user
-+ ejabberd_auth:remove_user(LUser, LServer),
-+ true
-+ end;
-+ %% nonexistent:
-+ not_found ->
-+ %% remove the user
-+ ejabberd_auth:remove_user(LUser, LServer),
-+ true
-+ end;
-+ %% Else
-+ _ ->
-+ %% do nothing
-+ false
-+ end
-+ end,
-+ %% Apply the function to every user in the list
-+ Users_removed = lists:filter(F, Users),
-+ {removed, length(Users_removed), Users_removed}.
-+
-+get_lastactivity_module(Server) ->
-+ case lists:member(mod_last, gen_mod:loaded_modules(Server)) of
-+ true -> mod_last;
-+ _ -> mod_last_odbc
-+ end.
-+
-+
-+%%
-+%% Ban account
-+
-+ban_account(User, Host, ReasonText) ->
-+ Reason = prepare_reason(ReasonText),
-+ kick_sessions(User, Host, Reason),
-+ set_random_password(User, Host, Reason),
-+ ok.
-+
-+kick_sessions(User, Server, Reason) ->
-+ lists:map(
-+ fun(Resource) ->
-+ kick_this_session(User, Server, Resource, Reason)
-+ end,
-+ get_resources(User, Server)).
-+
-+get_resources(User, Server) ->
-+ lists:map(
-+ fun(Session) ->
-+ element(3, Session#session.usr)
-+ end,
-+ get_sessions(User, Server)).
-+
-+get_sessions(User, Server) ->
-+ LUser = jlib:nodeprep(User),
-+ LServer = jlib:nameprep(Server),
-+ Sessions = mnesia:dirty_index_read(session, {LUser, LServer}, #session.us),
-+ true = is_list(Sessions),
-+ Sessions.
-+
-+set_random_password(User, Server, Reason) ->
-+ NewPass = build_random_password(Reason),
-+ set_password_auth(User, Server, NewPass).
-+
-+build_random_password(Reason) ->
-+ Date = jlib:timestamp_to_iso(calendar:universal_time()),
-+ RandomString = randoms:get_string(),
-+ "BANNED_ACCOUNT--" ++ Date ++ "--" ++ RandomString ++
"--" ++ Reason.
-+
-+set_password_auth(User, Server, Password) ->
-+ ok = ejabberd_auth:set_password(User, Server, Password).
-+
-+prepare_reason([]) ->
-+ "Kicked by administrator";
-+prepare_reason([Reason]) ->
-+ Reason;
-+prepare_reason(Reason) when is_list(Reason) ->
-+ Reason;
-+prepare_reason(StringList) ->
-+ string:join(StringList, "_").
-+
-+
-+%%%
-+%%% Sessions
-+%%%
-+
-+num_resources(User, Host) ->
-+ length(ejabberd_sm:get_user_resources(User, Host)).
-+
-+resource_num(User, Host, Num) ->
-+ Resources = ejabberd_sm:get_user_resources(User, Host),
-+ case (0<Num) and (Num=<length(Resources)) of
-+ true ->
-+ lists:nth(Num, Resources);
-+ false ->
-+ lists:flatten(io_lib:format("Error: Wrong resource number: ~p", [Num]))
-+ end.
-+
-+kick_session(User, Server, Resource, ReasonText) ->
-+ kick_this_session(User, Server, Resource, prepare_reason(ReasonText)),
-+ ok.
-+
-+kick_this_session(User, Server, Resource, Reason) ->
-+ ejabberd_router:route(
-+ jlib:make_jid("", "", ""),
-+ jlib:make_jid(User, Server, Resource),
-+ {xmlelement, "broadcast", [], [{exit, Reason}]}).
-+
-+
-+status_num(Host, Status) ->
-+ length(get_status_list(Host, Status)).
-+status_num(Status) ->
-+ status_num("all", Status).
-+status_list(Host, Status) ->
-+ Res = get_status_list(Host, Status),
-+ [{U, S, R, P, St} || {U, S, R, P, St} <- Res].
-+status_list(Status) ->
-+ status_list("all", Status).
-+
-+
-+get_status_list(Host, Status_required) ->
-+ %% Get list of all logged users
-+ Sessions = ejabberd_sm:dirty_get_my_sessions_list(),
-+ %% Reformat the list
-+ Sessions2 = [ {Session#session.usr, Session#session.sid, Session#session.priority}
|| Session <- Sessions],
-+ Fhost = case Host of
-+ "all" ->
-+ %% All hosts are requested, so dont filter at all
-+ fun(_, _) -> true end;
-+ _ ->
-+ %% Filter the list, only Host is interesting
-+ fun(A, B) -> A == B end
-+ end,
-+ Sessions3 = [ {Pid, Server, Priority} || {{_User, Server, _Resource}, {_, Pid},
Priority} <- Sessions2, apply(Fhost, [Server, Host])],
-+ %% For each Pid, get its presence
-+ Sessions4 = [ {ejabberd_c2s:get_presence(Pid), Server, Priority} || {Pid, Server,
Priority} <- Sessions3],
-+ %% Filter by status
-+ Fstatus = case Status_required of
-+ "all" ->
-+ fun(_, _) -> true end;
-+ _ ->
-+ fun(A, B) -> A == B end
-+ end,
-+ [{User, Server, Resource, Priority, stringize(Status_text)}
-+ || {{User, Resource, Status, Status_text}, Server, Priority} <- Sessions4,
-+ apply(Fstatus, [Status, Status_required])].
-+
-+connected_users_info() ->
-+ USRIs = dirty_get_sessions_list2(),
-+ CurrentSec = calendar:datetime_to_gregorian_seconds({date(), time()}),
-+ lists:map(
-+ fun([{U, S, R}, {Now, Pid}, Priority, Info]) ->
-+ Conn = proplists:get_value(conn, Info),
-+ {Ip, Port} = proplists:get_value(ip, Info),
-+ IPS = inet_parse:ntoa(Ip),
-+ NodeS = atom_to_list(node(Pid)),
-+ Uptime = CurrentSec - calendar:datetime_to_gregorian_seconds(
-+ calendar:now_to_local_time(Now)),
-+ {[U, $@, S, $/, R], atom_to_list(Conn), IPS, Port, Priority, NodeS, Uptime}
-+ end,
-+ USRIs).
-+
-+connected_users_vhost(Host) ->
-+ USRs = ejabberd_sm:get_vh_session_list(Host),
-+ [ [U, $@, S, $/, R] || {U, S, R} <- USRs].
-+
-+%% Code copied from ejabberd_sm.erl and customized
-+dirty_get_sessions_list2() ->
-+ mnesia:dirty_select(
-+ session,
-+ [{#session{usr = '$1', sid = '$2', priority = '$3', info =
'$4', _ = '_'},
-+ [],
-+ [['$1', '$2', '$3', '$4']]}]).
-+
-+%% Make string more print-friendly
-+stringize(String) ->
-+ %% Replace newline characters with other code
-+ ejabberd_regexp:greplace(String, "\n", "\\n").
-+
-+set_presence(User, Host, Resource, Type, Show, Status, Priority) ->
-+ Pid = ejabberd_sm:get_session_pid(User, Host, Resource),
-+ USR = User ++ "@" ++ Host ++ "/" ++ Resource,
-+ US = User ++ "@" ++ Host,
-+ Message = {route_xmlstreamelement,
-+ {xmlelement, "presence",
-+ [{"from", USR}, {"to", US}, {"type", Type}],
-+ [{xmlelement, "show", [], [{xmlcdata, Show}]},
-+ {xmlelement, "status", [], [{xmlcdata, Status}]},
-+ {xmlelement, "priority", [], [{xmlcdata, Priority}]}]}},
-+ Pid ! Message.
-+
-+user_sessions_info(User, Host) ->
-+ CurrentSec = calendar:datetime_to_gregorian_seconds({date(), time()}),
-+ US = {User, Host},
-+ Sessions = case catch mnesia:dirty_index_read(session, US, #session.us) of
-+ {'EXIT', _Reason} ->
-+ [];
-+ Ss ->
-+ Ss
-+ end,
-+ lists:map(
-+ fun(Session) ->
-+ {_U, _S, Resource} = Session#session.usr,
-+ {Now, Pid} = Session#session.sid,
-+ {_U, _Resource, Status, StatusText} = ejabberd_c2s:get_presence(Pid),
-+ Info = Session#session.info,
-+ Priority = Session#session.priority,
-+ Conn = proplists:get_value(conn, Info),
-+ {Ip, Port} = proplists:get_value(ip, Info),
-+ IPS = inet_parse:ntoa(Ip),
-+ NodeS = atom_to_list(node(Pid)),
-+ Uptime = CurrentSec - calendar:datetime_to_gregorian_seconds(
-+ calendar:now_to_local_time(Now)),
-+ {atom_to_list(Conn), IPS, Port, Priority, NodeS, Uptime, Status, Resource,
StatusText}
-+ end,
-+ Sessions).
-+
-+
-+%%%
-+%%% Vcard
-+%%%
-+
-+set_nickname(User, Host, Nickname) ->
-+ R = mod_vcard:process_sm_iq(
-+ {jid, User, Host, "", User, Host, ""},
-+ {jid, User, Host, "", User, Host, ""},
-+ {iq, "", set, "", "en",
-+ {xmlelement, "vCard",
-+ [{"xmlns", "vcard-temp"}], [
-+ {xmlelement, "NICKNAME", [], [{xmlcdata, Nickname}]}
-+ ]
-+ }}),
-+ case R of
-+ {iq, [], result, [], _L, []} ->
-+ ok;
-+ _ ->
-+ error
-+ end.
-+
-+get_vcard(User, Host, Name) ->
-+ [Res | _] = get_vcard_content(User, Host, [Name]),
-+ Res.
-+
-+get_vcard(User, Host, Name, Subname) ->
-+ [Res | _] = get_vcard_content(User, Host, [Name, Subname]),
-+ Res.
-+
-+get_vcard_multi(User, Host, Name, Subname) ->
-+ get_vcard_content(User, Host, [Name, Subname]).
-+
-+set_vcard(User, Host, Name, SomeContent) ->
-+ set_vcard_content(User, Host, [Name], SomeContent).
-+
-+set_vcard(User, Host, Name, Subname, SomeContent) ->
-+ set_vcard_content(User, Host, [Name, Subname], SomeContent).
-+
-+
-+%%
-+%% Internal vcard
-+
-+get_module_resource(Server) ->
-+ case gen_mod:get_module_opt(Server, ?MODULE, module_resource, none) of
-+ none -> atom_to_list(?MODULE);
-+ R when is_list(R) -> R
-+ end.
-+
-+get_vcard_content(User, Server, Data) ->
-+ [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}),
-+ JID = jlib:make_jid(User, Server, get_module_resource(Server)),
-+ IQ = #iq{type = get, xmlns = ?NS_VCARD},
-+ IQr = Module:Function(JID, JID, IQ),
-+ case IQr#iq.sub_el of
-+ [A1] ->
-+ case get_vcard(Data, A1) of
-+ [] -> throw(error_no_value_found_in_vcard);
-+ ElemList -> [xml:get_tag_cdata(Elem) || Elem <- ElemList]
-+ end;
-+ [] ->
-+ throw(error_no_vcard_found)
-+ end.
-+
-+get_vcard([Data1, Data2], A1) ->
-+ case get_subtag(A1, Data1) of
-+ false -> false;
-+ A2List -> lists:flatten([get_vcard([Data2], A2) || A2 <- A2List])
-+ end;
-+
-+get_vcard([Data], A1) ->
-+ get_subtag(A1, Data).
-+
-+get_subtag(Xmlelement, Name) ->
-+ case code:ensure_loaded(exmpp_xml) of
-+ {error, _} ->
-+ [get_subtag_xml(Xmlelement, Name)];
-+ {module, exmpp_xml} ->
-+ get_subtag_exmpp(Xmlelement, Name)
-+ end.
-+
-+get_subtag_xml(Xmlelement, Name) ->
-+ xml:get_subtag(Xmlelement, Name).
-+
-+get_subtag_exmpp(Xmlelement, Name) ->
-+ Xmlel = exmpp_xml:xmlelement_to_xmlel(Xmlelement),
-+ XmlelList = exmpp_xml:get_elements(Xmlel, Name),
-+ [exmpp_xml:xmlel_to_xmlelement(Xmlel2) || Xmlel2 <- XmlelList].
-+
-+set_vcard_content(User, Server, Data, SomeContent) ->
-+ ContentList = case SomeContent of
-+ [Char | _] when not is_list(Char) -> [SomeContent];
-+ [Char | _] when is_list(Char) -> SomeContent
-+ end,
-+ [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}),
-+ JID = jlib:make_jid(User, Server, get_module_resource(Server)),
-+ IQ = #iq{type = get, xmlns = ?NS_VCARD},
-+ IQr = Module:Function(JID, JID, IQ),
-+
-+ %% Get old vcard
-+ A4 = case IQr#iq.sub_el of
-+ [A1] ->
-+ {_, _, _, A2} = A1,
-+ update_vcard_els(Data, ContentList, A2);
-+ [] ->
-+ update_vcard_els(Data, ContentList, [])
-+ end,
-+
-+ %% Build new vcard
-+ SubEl = {xmlelement, "vCard",
[{"xmlns","vcard-temp"}], A4},
-+ IQ2 = #iq{type=set, sub_el = SubEl},
-+
-+ Module:Function(JID, JID, IQ2),
-+ ok.
-+
-+update_vcard_els(Data, ContentList, Els1) ->
-+ Els2 = lists:keysort(2, Els1),
-+ [Data1 | Data2] = Data,
-+ NewEls = case Data2 of
-+ [] ->
-+ [{xmlelement, Data1, [], [{xmlcdata,Content}]} || Content <- ContentList];
-+ [D2] ->
-+ OldEl = case lists:keysearch(Data1, 2, Els2) of
-+ {value, A} -> A;
-+ false -> {xmlelement, Data1, [], []}
-+ end,
-+ {xmlelement, _, _, ContentOld1} = OldEl,
-+ Content2 = [{xmlelement, D2, [], [{xmlcdata,Content}]} || Content <-
ContentList],
-+ ContentOld2 = [A || {_, X, _, _} = A <- ContentOld1, X/=D2],
-+ ContentOld3 = lists:keysort(2, ContentOld2),
-+ ContentNew = lists:keymerge(2, Content2, ContentOld3),
-+ [{xmlelement, Data1, [], ContentNew}]
-+ end,
-+ Els3 = lists:keydelete(Data1, 2, Els2),
-+ lists:keymerge(2, NewEls, Els3).
-+
-+
-+%%%
-+%%% Roster
-+%%%
-+
-+add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group, Subs) ->
-+ case add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group,
list_to_atom(Subs), []) of
-+ {atomic, ok} ->
-+ push_roster_item(LocalUser, LocalServer, User, Server, {add, Nick, Subs, Group}),
-+ ok;
-+ _ ->
-+ error
-+ end.
-+
-+add_rosteritem(LU, LS, User, Server, Nick, Group, Subscription, Xattrs) ->
-+ subscribe(LU, LS, User, Server, Nick, Group, Subscription, Xattrs).
-+
-+subscribe(LU, LS, User, Server, Nick, Group, Subscription, _Xattrs) ->
-+ SubscriptionS = case is_atom(Subscription) of
-+ true -> atom_to_list(Subscription);
-+ false -> Subscription
-+ end,
-+ ItemEl = build_roster_item(User, Server, {add, Nick, SubscriptionS, Group}),
-+ {ok, M} = loaded_module(LS,[mod_roster_odbc,mod_roster]),
-+ M:set_items(
-+ LU, LS,
-+ {xmlelement,"query",
-+ [{"xmlns","jabber:iq:roster"}],
-+ [ItemEl]}).
-+
-+delete_rosteritem(LocalUser, LocalServer, User, Server) ->
-+ case unsubscribe(LocalUser, LocalServer, User, Server) of
-+ {atomic, ok} ->
-+ push_roster_item(LocalUser, LocalServer, User, Server, remove),
-+ ok;
-+ _ ->
-+ error
-+ end.
-+
-+unsubscribe(LU, LS, User, Server) ->
-+ ItemEl = build_roster_item(User, Server, remove),
-+ {ok, M} = loaded_module(LS,[mod_roster_odbc,mod_roster]),
-+ M:set_items(
-+ LU, LS,
-+ {xmlelement,"query",
-+ [{"xmlns","jabber:iq:roster"}],
-+ [ItemEl]}).
-+
-+loaded_module(Domain,Options) ->
-+ LoadedModules = gen_mod:loaded_modules(Domain),
-+ case lists:filter(fun(Module) ->
-+ lists:member(Module, LoadedModules)
-+ end, Options) of
-+ [M|_] -> {ok, M};
-+ [] -> {error,not_found}
-+ end.
-+
-+%% -----------------------------
-+%% Get Roster
-+%% -----------------------------
-+
-+get_roster(User, Server) ->
-+ Items = ejabberd_hooks:run_fold(roster_get, Server, [], [{User, Server}]),
-+ make_roster_xmlrpc(Items).
-+
-+%% Note: if a contact is in several groups, the contact is returned
-+%% several times, each one in a different group.
-+make_roster_xmlrpc(Roster) ->
-+ lists:foldl(
-+ fun(Item, Res) ->
-+ JIDS = jlib:jid_to_string(Item#roster.jid),
-+ Nick = Item#roster.name,
-+ Subs = atom_to_list(Item#roster.subscription),
-+ Ask = atom_to_list(Item#roster.ask),
-+ Groups = case Item#roster.groups of
-+ [] -> [""];
-+ Gs -> Gs
-+ end,
-+ ItemsX = [{JIDS, Nick, Subs, Ask, Group}
-+ || Group <- Groups],
-+ ItemsX ++ Res
-+ end,
-+ [],
-+ Roster).
-+
-+
-+%%-----------------------------
-+%% Push Roster from file
-+%%-----------------------------
-+
-+push_roster(File, User, Server) ->
-+ {ok, [Roster]} = file:consult(File),
-+ subscribe_roster({User, Server, "", User}, Roster).
-+
-+push_roster_all(File) ->
-+ {ok, [Roster]} = file:consult(File),
-+ subscribe_all(Roster).
-+
-+subscribe_all(Roster) ->
-+ subscribe_all(Roster, Roster).
-+subscribe_all([], _) ->
-+ ok;
-+subscribe_all([User1 | Users], Roster) ->
-+ subscribe_roster(User1, Roster),
-+ subscribe_all(Users, Roster).
-+
-+subscribe_roster(_, []) ->
-+ ok;
-+%% Do not subscribe a user to itself
-+subscribe_roster({Name, Server, Group, Nick}, [{Name, Server, _, _} | Roster]) ->
-+ subscribe_roster({Name, Server, Group, Nick}, Roster);
-+%% Subscribe Name2 to Name1
-+subscribe_roster({Name1, Server1, Group1, Nick1}, [{Name2, Server2, Group2, Nick2} |
Roster]) ->
-+ subscribe(Name1, Server1, Name2, Server2, Nick2, Group2, both, []),
-+ subscribe_roster({Name1, Server1, Group1, Nick1}, Roster).
-+
-+push_alltoall(S, G) ->
-+ Users = ejabberd_auth:get_vh_registered_users(S),
-+ Users2 = build_list_users(G, Users, []),
-+ subscribe_all(Users2),
-+ ok.
-+
-+build_list_users(_Group, [], Res) ->
-+ Res;
-+build_list_users(Group, [{User, Server}|Users], Res) ->
-+ build_list_users(Group, Users, [{User, Server, Group, User}|Res]).
-+
-+%% @spec(LU, LS, U, S, Action) -> ok
-+%% Action = {add, Nick, Subs, Group} | remove
-+%% @doc Push to the roster of account LU@LS the contact U@S.
-+%% The specific action to perform is defined in Action.
-+push_roster_item(LU, LS, U, S, Action) ->
-+ lists:foreach(fun(R) ->
-+ push_roster_item(LU, LS, R, U, S, Action)
-+ end, ejabberd_sm:get_user_resources(LU, LS)).
-+
-+push_roster_item(LU, LS, R, U, S, Action) ->
-+ LJID = jlib:make_jid(LU, LS, R),
-+ BroadcastEl = build_broadcast(U, S, Action),
-+ ejabberd_router:route(LJID, LJID, BroadcastEl),
-+ Item = build_roster_item(U, S, Action),
-+ ResIQ = build_iq_roster_push(Item),
-+ ejabberd_router:route(LJID, LJID, ResIQ).
-+
-+build_roster_item(U, S, {add, Nick, Subs, Group}) ->
-+ {xmlelement, "item",
-+ [{"jid", jlib:jid_to_string(jlib:make_jid(U, S, ""))},
-+ {"name", Nick},
-+ {"subscription", Subs}],
-+ [{xmlelement, "group", [], [{xmlcdata, Group}]}]
-+ };
-+build_roster_item(U, S, remove) ->
-+ {xmlelement, "item",
-+ [{"jid", jlib:jid_to_string(jlib:make_jid(U, S, ""))},
-+ {"subscription", "remove"}],
-+ []
-+ }.
-+
-+build_iq_roster_push(Item) ->
-+ {xmlelement, "iq",
-+ [{"type", "set"}, {"id", "push"}],
-+ [{xmlelement, "query",
-+ [{"xmlns", ?NS_ROSTER}],
-+ [Item]
-+ }
-+ ]
-+ }.
-+
-+build_broadcast(U, S, {add, _Nick, Subs, _Group}) ->
-+ build_broadcast(U, S, list_to_atom(Subs));
-+build_broadcast(U, S, remove) ->
-+ build_broadcast(U, S, none);
-+%% @spec (U::string(), S::string(), Subs::atom()) -> any()
-+%% Subs = both | from | to | none
-+build_broadcast(U, S, SubsAtom) when is_atom(SubsAtom) ->
-+ {xmlelement, "broadcast", [],
-+ [{item, {U, S, ""}, SubsAtom}]
-+ }.
-+
-+%%%
-+%%% Last Activity
-+%%%
-+
-+set_last(User, Server, Timestamp, Status) ->
-+ Mod = get_lastactivity_module(Server),
-+ Mod:store_last_info(User, Server, Timestamp, Status).
-+
-+%%%
-+%%% Private Storage
-+%%%
-+
-+%% Example usage:
-+%% $ ejabberdctl private_set badlop localhost "\<aa\
xmlns=\'bb\'\>Cluth\</aa\>"
-+%% $ ejabberdctl private_get badlop localhost aa bb
-+%% <aa xmlns='bb'>Cluth</aa>
-+
-+private_get(Username, Host, Element, Ns) ->
-+ From = jlib:make_jid(Username, Host, ""),
-+ To = jlib:make_jid(Username, Host, ""),
-+ IQ = {iq, "", get, ?NS_PRIVATE, "",
-+ {xmlelement,"query",
-+ [{"xmlns",?NS_PRIVATE}],
-+ [{xmlelement, Element, [{"xmlns", Ns}], []}]}},
-+ ResIq = mod_private:process_sm_iq(From, To, IQ),
-+ [{xmlelement,"query",
-+ [{"xmlns","jabber:iq:private"}],
-+ [SubEl]}] = ResIq#iq.sub_el,
-+ xml:element_to_string(SubEl).
-+
-+private_set(Username, Host, ElementString) ->
-+ case xml_stream:parse_element(ElementString) of
-+ {error, Error} ->
-+ io:format("Error found parsing the element:~n ~p~nError: ~p~n",
-+ [ElementString, Error]),
-+ error;
-+ Xml ->
-+ private_set2(Username, Host, Xml)
-+ end.
-+
-+private_set2(Username, Host, Xml) ->
-+ From = jlib:make_jid(Username, Host, ""),
-+ To = jlib:make_jid(Username, Host, ""),
-+ IQ = {iq, "", set, ?NS_PRIVATE, "",
-+ {xmlelement,"query",
-+ [{"xmlns",?NS_PRIVATE}],
-+ [Xml]}},
-+ mod_private:process_sm_iq(From, To, IQ),
-+ ok.
-+
-+%%%
-+%%% Shared Roster Groups
-+%%%
-+
-+srg_create(Group, Host, Name, Description, Display) ->
-+ DisplayList = case Display of
-+ [] -> [];
-+ _ -> ejabberd_regexp:split(Display, "\\\\n")
-+ end,
-+ Opts = [{name, Name},
-+ {displayed_groups, DisplayList},
-+ {description, Description}],
-+ {atomic, ok} = mod_shared_roster:create_group(Host, Group, Opts),
-+ ok.
-+
-+srg_delete(Group, Host) ->
-+ {atomic, ok} = mod_shared_roster:delete_group(Host, Group),
-+ ok.
-+
-+srg_list(Host) ->
-+ lists:sort(mod_shared_roster:list_groups(Host)).
-+
-+srg_get_info(Group, Host) ->
-+ Opts = mod_shared_roster:get_group_opts(Host,Group),
-+ [{io_lib:format("~p", [Title]),
-+ io_lib:format("~p", [Value])} || {Title, Value} <- Opts].
-+
-+srg_get_members(Group, Host) ->
-+ Members = mod_shared_roster:get_group_explicit_users(Host,Group),
-+ [jlib:jid_to_string(jlib:make_jid(MUser, MServer, ""))
-+ || {MUser, MServer} <- Members].
-+
-+srg_user_add(User, Host, Group, GroupHost) ->
-+ {atomic, ok} = mod_shared_roster:add_user_to_group(GroupHost, {User, Host}, Group),
-+ ok.
-+
-+srg_user_del(User, Host, Group, GroupHost) ->
-+ {atomic, ok} = mod_shared_roster:remove_user_from_group(GroupHost, {User, Host},
Group),
-+ ok.
-+
-+
-+%%%
-+%%% Stanza
-+%%%
-+
-+%% @doc Send a chat message to a Jabber account.
-+%% @spec (From::string(), To::string(), Body::string()) -> ok
-+send_message_chat(From, To, Body) ->
-+ Packet = build_packet(message_chat, [Body]),
-+ send_packet_all_resources(From, To, Packet).
-+
-+%% @doc Send a headline message to a Jabber account.
-+%% @spec (From::string(), To::string(), Subject::string(), Body::string()) -> ok
-+send_message_headline(From, To, Subject, Body) ->
-+ Packet = build_packet(message_headline, [Subject, Body]),
-+ send_packet_all_resources(From, To, Packet).
-+
-+%% @doc Send a packet to a Jabber account.
-+%% If a resource was specified in the JID,
-+%% the packet is sent only to that specific resource.
-+%% If no resource was specified in the JID,
-+%% and the user is remote or local but offline,
-+%% the packet is sent to the bare JID.
-+%% If the user is local and is online in several resources,
-+%% the packet is sent to all its resources.
-+send_packet_all_resources(FromJIDString, ToJIDString, Packet) ->
-+ FromJID = jlib:string_to_jid(FromJIDString),
-+ ToJID = jlib:string_to_jid(ToJIDString),
-+ ToUser = ToJID#jid.user,
-+ ToServer = ToJID#jid.server,
-+ case ToJID#jid.resource of
-+ "" ->
-+ send_packet_all_resources(FromJID, ToUser, ToServer, Packet);
-+ Res ->
-+ send_packet_all_resources(FromJID, ToUser, ToServer, Res, Packet)
-+ end.
-+
-+send_packet_all_resources(FromJID, ToUser, ToServer, Packet) ->
-+ case ejabberd_sm:get_user_resources(ToUser, ToServer) of
-+ [] ->
-+ send_packet_all_resources(FromJID, ToUser, ToServer, "", Packet);
-+ ToResources ->
-+ lists:foreach(
-+ fun(ToResource) ->
-+ send_packet_all_resources(FromJID, ToUser, ToServer,
-+ ToResource, Packet)
-+ end,
-+ ToResources)
-+ end.
-+
-+send_packet_all_resources(FromJID, ToU, ToS, ToR, Packet) ->
-+ ToJID = jlib:make_jid(ToU, ToS, ToR),
-+ ejabberd_router:route(FromJID, ToJID, Packet).
-+
-+
-+build_packet(message_chat, [Body]) ->
-+ {xmlelement, "message",
-+ [{"type", "chat"}, {"id", randoms:get_string()}],
-+ [{xmlelement, "body", [], [{xmlcdata, Body}]}]
-+ };
-+build_packet(message_headline, [Subject, Body]) ->
-+ {xmlelement, "message",
-+ [{"type", "headline"}, {"id",
randoms:get_string()}],
-+ [{xmlelement, "subject", [], [{xmlcdata, Subject}]},
-+ {xmlelement, "body", [], [{xmlcdata, Body}]}
-+ ]
-+ }.
-+
-+send_stanza_c2s(Username, Host, Resource, Stanza) ->
-+ C2sPid = ejabberd_sm:get_session_pid(Username, Host, Resource),
-+ XmlEl = xml_stream:parse_element(Stanza),
-+ p1_fsm:send_event(C2sPid, {xmlstreamelement, XmlEl}).
-+
-+privacy_set(Username, Host, QueryS) ->
-+ From = jlib:string_to_jid(Username ++ "@" ++ Host),
-+ To = jlib:string_to_jid(Host),
-+ QueryEl = xml_stream:parse_element(QueryS),
-+ StanzaEl = {xmlelement, "iq", [{"type", "set"}],
[QueryEl]},
-+ IQ = jlib:iq_query_info(StanzaEl),
-+ ejabberd_hooks:run_fold(
-+ privacy_iq_set,
-+ Host,
-+ {error, ?ERR_FEATURE_NOT_IMPLEMENTED},
-+ [From, To, IQ]
-+ ),
-+ ok.
-+
-+%%%
-+%%% Stats
-+%%%
-+
-+stats(Name) ->
-+ case Name of
-+ "uptimeseconds" -> trunc(element(1, erlang:statistics(wall_clock))/1000);
-+ "registeredusers" -> length(ejabberd_auth:dirty_get_registered_users());
-+ "onlineusersnode" -> length(ejabberd_sm:dirty_get_my_sessions_list());
-+ "onlineusers" -> length(ejabberd_sm:dirty_get_sessions_list())
-+ end.
-+
-+stats(Name, Host) ->
-+ case Name of
-+ "registeredusers" -> length(ejabberd_auth:get_vh_registered_users(Host));
-+ "onlineusers" -> length(ejabberd_sm:get_vh_session_list(Host))
-+ end.
-+
-+
-+
-+%%-----------------------------
-+%% Purge roster items
-+%%-----------------------------
-+
-+process_rosteritems(ActionS, SubsS, AsksS, UsersS, ContactsS) ->
-+ Action = case ActionS of
-+ "list" -> list;
-+ "delete" -> delete
-+ end,
-+
-+ Subs = lists:foldl(
-+ fun(any, _) -> [none, from, to, both];
-+ (Sub, Subs) -> [Sub | Subs]
-+ end,
-+ [],
-+ [list_to_atom(S) || S <- string:tokens(SubsS, ":")]
-+ ),
-+
-+ Asks = lists:foldl(
-+ fun(any, _) -> [none, out, in];
-+ (Ask, Asks) -> [Ask | Asks]
-+ end,
-+ [],
-+ [list_to_atom(S) || S <- string:tokens(AsksS, ":")]
-+ ),
-+
-+ Users = lists:foldl(
-+ fun("any", _) -> ["*", "*@*"];
-+ (U, Us) -> [U | Us]
-+ end,
-+ [],
-+ [S || S <- string:tokens(UsersS, ":")]
-+ ),
-+
-+ Contacts = lists:foldl(
-+ fun("any", _) -> ["*", "*@*"];
-+ (U, Us) -> [U | Us]
-+ end,
-+ [],
-+ [S || S <- string:tokens(ContactsS, ":")]
-+ ),
-+
-+ case rosteritem_purge({Action, Subs, Asks, Users, Contacts}) of
-+ {atomic, ok} ->
-+ ok;
-+ {error, Reason} ->
-+ io:format("Error purging rosteritems: ~p~n", [Reason]),
-+ error;
-+ {badrpc, Reason} ->
-+ io:format("BadRPC purging rosteritems: ~p~n", [Reason]),
-+ error
-+ end.
-+
-+%% @spec ({Action::atom(), Subs::[atom()], Asks::[atom()], User::string(),
Contact::string()}) -> {atomic, ok}
-+rosteritem_purge(Options) ->
-+ Num_rosteritems = mnesia:table_info(roster, size),
-+ io:format("There are ~p roster items in total.~n", [Num_rosteritems]),
-+ Key = mnesia:dirty_first(roster),
-+ ok = rip(Key, Options, {0, Num_rosteritems, 0, 0}),
-+ {atomic, ok}.
-+
-+rip('$end_of_table', _Options, Counters) ->
-+ print_progress_line(Counters),
-+ ok;
-+rip(Key, Options, {Pr, NT, NV, ND}) ->
-+ Key_next = mnesia:dirty_next(roster, Key),
-+ {Action, _, _, _, _} = Options,
-+ ND2 = case decide_rip(Key, Options) of
-+ true ->
-+ apply_action(Action, Key),
-+ ND+1;
-+ false ->
-+ ND
-+ end,
-+ NV2 = NV+1,
-+ Pr2 = print_progress_line({Pr, NT, NV2, ND2}),
-+ rip(Key_next, Options, {Pr2, NT, NV2, ND2}).
-+
-+apply_action(list, Key) ->
-+ {User, Server, JID} = Key,
-+ {RUser, RServer, _} = JID,
-+ io:format("Matches: ~s@~s ~s@~s~n", [User, Server, RUser, RServer]);
-+apply_action(delete, Key) ->
-+ apply_action(list, Key),
-+ mnesia:dirty_delete(roster, Key).
-+
-+print_progress_line({Pr, NT, NV, ND}) ->
-+ Pr2 = trunc((NV/NT)*100),
-+ case Pr == Pr2 of
-+ true ->
-+ ok;
-+ false ->
-+ io:format("Progress ~p% - visited ~p - deleted ~p~n", [Pr2, NV, ND])
-+ end,
-+ Pr2.
-+
-+decide_rip(Key, {_Action, Subs, Asks, User, Contact}) ->
-+ case catch mnesia:dirty_read(roster, Key) of
-+ [RI] ->
-+ lists:member(RI#roster.subscription, Subs)
-+ andalso lists:member(RI#roster.ask, Asks)
-+ andalso decide_rip_jid(RI#roster.us, User)
-+ andalso decide_rip_jid(RI#roster.jid, Contact);
-+ _ ->
-+ false
-+ end.
-+
-+%% Returns true if the server of the JID is included in the servers
-+decide_rip_jid({UName, UServer, _UResource}, Match_list) ->
-+ decide_rip_jid({UName, UServer}, Match_list);
-+decide_rip_jid({UName, UServer}, Match_list) ->
-+ lists:any(
-+ fun(Match_string) ->
-+ MJID = jlib:string_to_jid(Match_string),
-+ MName = MJID#jid.luser,
-+ MServer = MJID#jid.lserver,
-+ Is_server = is_glob_match(UServer, MServer),
-+ case MName of
-+ [] when UName == [] ->
-+ Is_server;
-+ [] ->
-+ false;
-+ _ ->
-+ Is_server
-+ andalso is_glob_match(UName, MName)
-+ end
-+ end,
-+ Match_list).
-+
-+%% Copied from ejabberd-2.0.0/src/acl.erl
-+is_regexp_match(String, RegExp) ->
-+ case ejabberd_regexp:run(String, RegExp) of
-+ nomatch ->
-+ false;
-+ match ->
-+ true;
-+ {error, ErrDesc} ->
-+ io:format(
-+ "Wrong regexp ~p in ACL: ~p",
-+ [RegExp, ErrDesc]),
-+ false
-+ end.
-+is_glob_match(String, [$! | Glob]) ->
-+ not is_regexp_match(String, ejabberd_regexp:sh_to_awk(Glob));
-+is_glob_match(String, Glob) ->
-+ is_regexp_match(String, ejabberd_regexp:sh_to_awk(Glob)).
---
-1.8.3.1
-
diff --git a/ejabberd-0004-Fedora-specific-changes-to-ejabberdctl.patch
b/ejabberd-0004-Fedora-specific-changes-to-ejabberdctl.patch
deleted file mode 100644
index 20cf399..0000000
--- a/ejabberd-0004-Fedora-specific-changes-to-ejabberdctl.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From 2e72b2ac86fcbc5902555621422db36684d42385 Mon Sep 17 00:00:00 2001
-From: Peter Lemenkov <lemenkov(a)gmail.com>
-Date: Tue, 16 Feb 2010 16:30:05 +0300
-Subject: [PATCH 04/10] Fedora-specific changes to ejabberdctl
-
-Signed-off-by: Peter Lemenkov <lemenkov(a)gmail.com>
----
- src/ejabberdctl.template | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template
-index 461ec1a..b298e01 100644
---- a/src/ejabberdctl.template
-+++ b/src/ejabberdctl.template
-@@ -9,10 +9,10 @@ ERL_MAX_ETS_TABLES=1400
-
- # define default environment variables
- NODE=ejabberd
--HOST=localhost
-+HOST=`hostname -s 2>/dev/null || echo "localhost"`
- ERLANG_NODE=$NODE@$HOST
- ERL=@erl@
--INSTALLUSER=@installuser@
-+INSTALLUSER=ejabberd
-
- # parse command line parameters
- ARGS=
-@@ -46,7 +46,7 @@ if [ "$LOGS_DIR" = "" ] ; then
- LOGS_DIR=@LOCALSTATEDIR@/log/ejabberd
- fi
- if [ "$SPOOLDIR" = "" ] ; then
-- SPOOLDIR=@LOCALSTATEDIR@/lib/ejabberd
-+ SPOOLDIR=@LOCALSTATEDIR@/lib/ejabberd/spool
- fi
- if [ "$EJABBERD_DOC_PATH" = "" ] ; then
- EJABBERD_DOC_PATH=@DOCDIR@
-@@ -62,7 +62,7 @@ EJID=`id -g $INSTALLUSER`
- EXEC_CMD="false"
- for GID in $GIDS; do
- if [ $GID -eq 0 ] ; then
-- EXEC_CMD="su ${INSTALLUSER} -p -c"
-+ EXEC_CMD="/sbin/runuser -s /bin/bash -p ejabberd -c"
- fi
- done
- if [ "$ID" -eq "$EJID" ] ; then
---
-1.8.3.1
-
diff --git a/ejabberd-0004-Install-.so-objects-with-0755-permissions.patch
b/ejabberd-0004-Install-.so-objects-with-0755-permissions.patch
new file mode 100644
index 0000000..dbf4fbf
--- /dev/null
+++ b/ejabberd-0004-Install-.so-objects-with-0755-permissions.patch
@@ -0,0 +1,19 @@
+From: Peter Lemenkov <lemenkov(a)gmail.com>
+Date: Sat, 12 Jun 2010 14:14:52 +0400
+Subject: [PATCH] Install *.so objects with 0755 permissions
+
+Signed-off-by: Peter Lemenkov <lemenkov(a)gmail.com>
+
+diff --git a/Makefile.in b/Makefile.in
+index 018ccd7..58d3486 100644
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -156,7 +156,7 @@ install: all
+ #
+ # Binary system libraries
+ $(INSTALL) -d $(SODIR)
+- $(INSTALL) -m 644 $(DLLs) $(SODIR)
++ $(INSTALL) -m 755 $(DLLs) $(SODIR)
+ #
+ # Translated strings
+ $(INSTALL) -d $(MSGSDIR)
diff --git a/ejabberd-0005-Clean-up-false-security-measure.patch
b/ejabberd-0005-Clean-up-false-security-measure.patch
new file mode 100644
index 0000000..a6a99fd
--- /dev/null
+++ b/ejabberd-0005-Clean-up-false-security-measure.patch
@@ -0,0 +1,19 @@
+From: Peter Lemenkov <lemenkov(a)gmail.com>
+Date: Wed, 17 Jul 2013 14:56:09 +0400
+Subject: [PATCH] Clean up false security measure
+
+Signed-off-by: Peter Lemenkov <lemenkov(a)gmail.com>
+
+diff --git a/Makefile.in b/Makefile.in
+index 58d3486..de47be2 100644
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -127,7 +127,7 @@ install: all
+ #
+ # Administration script
+ [ -d $(SBINDIR) ] || $(INSTALL) -d -m 755 $(SBINDIR)
+- $(INSTALL) -m 550 $(G_USER) ejabberdctl.example $(SBINDIR)/ejabberdctl
++ $(INSTALL) -m 755 $(G_USER) ejabberdctl.example $(SBINDIR)/ejabberdctl
+ #
+ # Init script
+ $(SED) -e "s*@ctlscriptpath@*$(SBINDIR)*" \
diff --git a/ejabberd-0005-Install-.so-objects-with-0755-permissions.patch
b/ejabberd-0005-Install-.so-objects-with-0755-permissions.patch
deleted file mode 100644
index af85b3c..0000000
--- a/ejabberd-0005-Install-.so-objects-with-0755-permissions.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From 75f9fdbe72c77c1521edc7402c0d27883dadf46c Mon Sep 17 00:00:00 2001
-From: Peter Lemenkov <lemenkov(a)gmail.com>
-Date: Sat, 12 Jun 2010 14:14:52 +0400
-Subject: [PATCH 05/10] Install *.so objects with 0755 permissions
-
-Signed-off-by: Peter Lemenkov <lemenkov(a)gmail.com>
----
- src/Makefile.in | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/Makefile.in b/src/Makefile.in
-index 42af5b2..64ed856 100644
---- a/src/Makefile.in
-+++ b/src/Makefile.in
-@@ -237,7 +237,7 @@ install: all
- #
- # Binary system libraries
- install -d $(SODIR)
-- install -m 644 *.so $(SODIR)
-+ install -m 755 *.so $(SODIR)
- #
- # Translated strings
- install -d $(MSGSDIR)
---
-1.8.3.1
-
diff --git a/ejabberd-0006-Enable-polkit-support.patch
b/ejabberd-0006-Enable-polkit-support.patch
new file mode 100644
index 0000000..715c5a4
--- /dev/null
+++ b/ejabberd-0006-Enable-polkit-support.patch
@@ -0,0 +1,16 @@
+From: Peter Lemenkov <lemenkov(a)gmail.com>
+Date: Wed, 17 Jul 2013 14:51:04 +0400
+Subject: [PATCH] Enable polkit support
+
+Signed-off-by: Peter Lemenkov <lemenkov(a)gmail.com>
+
+diff --git a/ejabberdctl.template b/ejabberdctl.template
+index 09b9947..0fd33fe 100755
+--- a/ejabberdctl.template
++++ b/ejabberdctl.template
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!/usr/bin/pkexec /bin/sh
+
+ # define default configuration
+ POLL=true
diff --git a/ejabberd-0006-Support-SASL-GSSAPI-authentication-thanks-to-Mikael-.patch
b/ejabberd-0006-Support-SASL-GSSAPI-authentication-thanks-to-Mikael-.patch
deleted file mode 100644
index a9b4dda..0000000
--- a/ejabberd-0006-Support-SASL-GSSAPI-authentication-thanks-to-Mikael-.patch
+++ /dev/null
@@ -1,505 +0,0 @@
-From e49dbaca001a3d311a2f8a8e878c5b8b6fc385c0 Mon Sep 17 00:00:00 2001
-From: Badlop <badlop(a)process-one.net>
-Date: Thu, 15 Apr 2010 17:20:16 +0200
-Subject: [PATCH 06/10] Support SASL GSSAPI authentication (thanks to Mikael
- Magnusson)(EJAB-831)
-
----
- src/cyrsasl.erl | 71 +++++++++++++++-----
- src/cyrsasl.hrl | 15 +++++
- src/cyrsasl_anonymous.erl | 6 +-
- src/cyrsasl_digest.erl | 6 +-
- src/cyrsasl_gssapi.erl | 166 ++++++++++++++++++++++++++++++++++++++++++++++
- src/cyrsasl_plain.erl | 6 +-
- src/cyrsasl_scram.erl | 5 +-
- src/ejabberd_c2s.erl | 12 +++-
- src/ejabberd_socket.erl | 19 ++++++
- 9 files changed, 281 insertions(+), 25 deletions(-)
- create mode 100644 src/cyrsasl.hrl
- create mode 100644 src/cyrsasl_gssapi.erl
-
-diff --git a/src/cyrsasl.erl b/src/cyrsasl.erl
-index 9d1377f..802c679 100644
---- a/src/cyrsasl.erl
-+++ b/src/cyrsasl.erl
-@@ -30,21 +30,36 @@
- -export([start/0,
- register_mechanism/3,
- listmech/1,
-- server_new/7,
-+ server_new/8,
- server_start/3,
- server_step/2]).
-
-+-include("cyrsasl.hrl").
- -include("ejabberd.hrl").
-
-+%% @type saslmechanism() = {sasl_mechanism, Mechanism, Module, Require_Plain}
-+%% Mechanism = string()
-+%% Module = atom()
-+%% Require_Plain = bool().
-+%% Registry entry of a supported SASL mechanism.
-+
- -record(sasl_mechanism, {mechanism, module, password_type}).
---record(sasl_state, {service, myname, realm,
-- get_password, check_password, check_password_digest,
-- mech_mod, mech_state}).
-+
-+%% @type saslstate() = {sasl_state, Service, Myname, Mech_Mod, Mech_State, Params}
-+%% Service = string()
-+%% Myname = string()
-+%% Mech_Mod = atom()
-+%% Mech_State = term().
-+%% Params = term().
-+%% State of this process.
-+
-+-record(sasl_state, {service, myname,
-+ mech_mod, mech_state, params}).
-
- -export([behaviour_info/1]).
-
- behaviour_info(callbacks) ->
-- [{mech_new, 4}, {mech_step, 2}];
-+ [{mech_new, 1}, {mech_step, 2}];
- behaviour_info(_Other) ->
- undefined.
-
-@@ -56,8 +71,30 @@ start() ->
- cyrsasl_digest:start([]),
- cyrsasl_scram:start([]),
- cyrsasl_anonymous:start([]),
-+ maybe_try_start_gssapi(),
- ok.
-
-+maybe_try_start_gssapi() ->
-+ case os:getenv("KRB5_KTNAME") of
-+ false ->
-+ ok;
-+ _String ->
-+ try_start_gssapi()
-+ end.
-+
-+try_start_gssapi() ->
-+ case code:load_file(esasl) of
-+ {module, _Module} ->
-+ cyrsasl_gssapi:start([]);
-+ {error, What} ->
-+ ?ERROR_MSG("Support for GSSAPI not started because esasl.beam was not found:
~p", [What])
-+ end.
-+
-+%% @spec (Mechanism, Module, Require_Plain) -> true
-+%% Mechanism = string()
-+%% Module = atom()
-+%% Require_Plain = bool()
-+
- register_mechanism(Mechanism, Module, PasswordType) ->
- ets:insert(sasl_mechanism,
- #sasl_mechanism{mechanism = Mechanism,
-@@ -119,24 +156,28 @@ listmech(Host) ->
- filter_anonymous(Host, Mechs).
-
- server_new(Service, ServerFQDN, UserRealm, _SecFlags,
-- GetPassword, CheckPassword, CheckPasswordDigest) ->
-+ GetPassword, CheckPassword, CheckPasswordDigest, Socket) ->
-+ Params = #sasl_params{
-+ host = ServerFQDN,
-+ realm = UserRealm,
-+ get_password = GetPassword,
-+ check_password = CheckPassword,
-+ check_password_digest= CheckPasswordDigest,
-+ socket = Socket
-+ },
-+
- #sasl_state{service = Service,
- myname = ServerFQDN,
-- realm = UserRealm,
-- get_password = GetPassword,
-- check_password = CheckPassword,
-- check_password_digest= CheckPasswordDigest}.
-+ params = Params}.
-+
-
- server_start(State, Mech, ClientIn) ->
- case lists:member(Mech, listmech(State#sasl_state.myname)) of
- true ->
- case ets:lookup(sasl_mechanism, Mech) of
- [#sasl_mechanism{module = Module}] ->
-- {ok, MechState} = Module:mech_new(
-- State#sasl_state.myname,
-- State#sasl_state.get_password,
-- State#sasl_state.check_password,
-- State#sasl_state.check_password_digest),
-+ {ok, MechState} =
-+ Module:mech_new(State#sasl_state.params),
- server_step(State#sasl_state{mech_mod = Module,
- mech_state = MechState},
- ClientIn);
-diff --git a/src/cyrsasl.hrl b/src/cyrsasl.hrl
-new file mode 100644
-index 0000000..b4cc3e3
---- /dev/null
-+++ b/src/cyrsasl.hrl
-@@ -0,0 +1,15 @@
-+%% @type saslparams() = {sasl_params, Host, Realm, GetPassword, CheckPassword,
CheckPasswordDigest}
-+%% Host = string()
-+%% Realm = string()
-+%% GetPassword = function()
-+%% CheckPassword = function()
-+%% CheckPasswordDigest = any().
-+%% Parameters for SASL.
-+
-+-record(sasl_params, {
-+ host,
-+ realm,
-+ get_password,
-+ check_password,
-+ check_password_digest,
-+ socket}).
-diff --git a/src/cyrsasl_anonymous.erl b/src/cyrsasl_anonymous.erl
-index cb0b1e3..085e98c 100644
---- a/src/cyrsasl_anonymous.erl
-+++ b/src/cyrsasl_anonymous.erl
-@@ -27,7 +27,9 @@
-
- -module(cyrsasl_anonymous).
-
---export([start/1, stop/0, mech_new/4, mech_step/2]).
-+-export([start/1, stop/0, mech_new/1, mech_step/2]).
-+
-+-include("cyrsasl.hrl").
-
- -behaviour(cyrsasl).
-
-@@ -40,7 +42,7 @@ start(_Opts) ->
- stop() ->
- ok.
-
--mech_new(Host, _GetPassword, _CheckPassword, _CheckPasswordDigest) ->
-+mech_new(#sasl_params{host=Host}) ->
- {ok, #state{server = Host}}.
-
- mech_step(State, _ClientIn) ->
-diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl
-index 557e498..e4199f8 100644
---- a/src/cyrsasl_digest.erl
-+++ b/src/cyrsasl_digest.erl
-@@ -29,10 +29,11 @@
-
- -export([start/1,
- stop/0,
-- mech_new/4,
-+ mech_new/1,
- mech_step/2]).
-
- -include("ejabberd.hrl").
-+-include("cyrsasl.hrl").
-
- -behaviour(cyrsasl).
-
-@@ -47,7 +48,8 @@ start(_Opts) ->
- stop() ->
- ok.
-
--mech_new(Host, GetPassword, _CheckPassword, CheckPasswordDigest) ->
-+mech_new(#sasl_params{host=Host, get_password=GetPassword,
-+ check_password_digest=CheckPasswordDigest}) ->
- {ok, #state{step = 1,
- nonce = randoms:get_string(),
- host = Host,
-diff --git a/src/cyrsasl_gssapi.erl b/src/cyrsasl_gssapi.erl
-new file mode 100644
-index 0000000..11d9955
---- /dev/null
-+++ b/src/cyrsasl_gssapi.erl
-@@ -0,0 +1,166 @@
-+%%%----------------------------------------------------------------------
-+%%% File : cyrsasl_gssapi.erl
-+%%% Author : Mikael Magnusson <mikma(a)users.sourceforge.net>
-+%%% Purpose : GSSAPI SASL mechanism
-+%%% Created : 1 June 2007 by Mikael Magnusson <mikma(a)users.sourceforge.net>
-+%%% Id : $Id: $
-+%%%----------------------------------------------------------------------
-+%%%
-+%%% Copyright (C) 2007-2009 Mikael Magnusson <mikma(a)users.sourceforge.net>
-+%%%
-+%%% Permission is hereby granted, free of charge, to any person
-+%%% obtaining a copy of this software and associated documentation
-+%%% files (the "Software"), to deal in the Software without
-+%%% restriction, including without limitation the rights to use, copy,
-+%%% modify, merge, publish, distribute, sublicense, and/or sell copies
-+%%% of the Software, and to permit persons to whom the Software is
-+%%% furnished to do so, subject to the following conditions:
-+%%%
-+%%% The above copyright notice and this permission notice shall be
-+%%% included in all copies or substantial portions of the Software.
-+%%%
-+%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-+%%% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-+%%% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-+%%% NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-+%%% BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-+%%% ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-+%%% CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+%%% SOFTWARE.
-+%%%
-+
-+%%%
-+%%% configuration options:
-+%%% {sasl_realm, "<Kerberos realm>"}.
-+%%%
-+%%% environment variables:
-+%%% KRB5_KTNAME
-+%%%
-+
-+-module(cyrsasl_gssapi).
-+-author('mikma(a)users.sourceforge.net').
-+-vsn('$Revision: $ ').
-+
-+-export([start/1,
-+ stop/0,
-+ mech_new/1,
-+ mech_step/2]).
-+
-+-include("ejabberd.hrl").
-+-include("cyrsasl.hrl").
-+
-+-behaviour(cyrsasl).
-+
-+-define(SERVER, ?MODULE).
-+-define(SERVICE, "xmpp").
-+
-+-record(state, {sasl,
-+ needsmore=true,
-+ step=0,
-+ host,
-+ realm,
-+ authid,
-+ authzid,
-+ authrealm,
-+ error}).
-+
-+start(_Opts) ->
-+ ChildSpec =
-+ {?SERVER,
-+ {esasl, start_link, [{local, ?SERVER}]},
-+ transient,
-+ 1000,
-+ worker,
-+ [esasl]},
-+
-+ case supervisor:start_child(ejabberd_sup, ChildSpec) of
-+ {ok, _Pid} ->
-+ cyrsasl:register_mechanism("GSSAPI", ?MODULE, false);
-+ {error, Error} = E ->
-+ ?ERROR_MSG("esasl failed: ~p", [Error]),
-+ E
-+ end.
-+
-+
-+stop() ->
-+ catch esasl:stop(?SERVER),
-+ supervisor:terminate_child(ejabberd_sup, ?SERVER),
-+ supervisor:delete_child(ejabberd_sup, ?SERVER).
-+
-+mech_new(#sasl_params{host=Host, realm=Realm, socket=Socket}) ->
-+ case ejabberd_socket:gethostname(Socket) of
-+ {ok, FQDN} ->
-+ ?DEBUG("mech_new ~p ~p ~p~n", [Host, Realm, FQDN]),
-+ case esasl:server_start(?SERVER, "GSSAPI", ?SERVICE, FQDN) of
-+ {ok, Sasl} ->
-+ {ok, #state{sasl=Sasl,host=Host,realm=Realm}};
-+ {error, {gsasl_error, Error}} ->
-+ {ok, Str} = esasl:str_error(?SERVER, Error),
-+ ?DEBUG("esasl error: ~p", [Str]),
-+ {ok, #state{needsmore=error,error="internal-server-error"}};
-+ {error, Error} ->
-+ ?DEBUG("esasl error: ~p", [Error]),
-+ {ok, #state{needsmore=error,error="internal-server-error"}}
-+ end;
-+ {error, Error} ->
-+ ?DEBUG("gethostname error: ~p", [Error]),
-+ {ok, #state{needsmore=error,error="internal-server-error"}}
-+ end.
-+
-+mech_step(State, ClientIn) when is_list(ClientIn) ->
-+ catch do_step(State, ClientIn).
-+
-+do_step(#state{needsmore=error,error=Error}=_State, _) ->
-+ {error, Error};
-+do_step(#state{needsmore=false}=State, _) ->
-+ check_user(State);
-+do_step(#state{needsmore=true,sasl=Sasl,step=Step}=State, ClientIn) ->
-+ ?DEBUG("mech_step~n", []),
-+ case esasl:step(Sasl, list_to_binary(ClientIn)) of
-+ {ok, RspAuth} ->
-+ ?DEBUG("ok~n", []),
-+ {ok, Display_name} = esasl:property_get(Sasl, gssapi_display_name),
-+ {ok, Authzid} = esasl:property_get(Sasl, authzid),
-+ {Authid, [$@ | Auth_realm]} =
-+ lists:splitwith(fun(E)->E =/= $@ end, Display_name),
-+ State1 = State#state{authid=Authid,
-+ authzid=Authzid,
-+ authrealm=Auth_realm},
-+ handle_step_ok(State1, binary_to_list(RspAuth));
-+ {needsmore, RspAuth} ->
-+ ?DEBUG("needsmore~n", []),
-+ if (Step > 0) and (ClientIn =:= []) and (RspAuth =:= <<>>) ->
-+ {error, "not-authorized"};
-+ true ->
-+ {continue, binary_to_list(RspAuth),
-+ State#state{step=Step+1}}
-+ end;
-+ {error, _} ->
-+ {error, "not-authorized"}
-+ end.
-+
-+handle_step_ok(State, []) ->
-+ check_user(State);
-+handle_step_ok(#state{step=Step}=State, RspAuth) ->
-+ ?DEBUG("continue~n", []),
-+ {continue, RspAuth, State#state{needsmore=false,step=Step+1}}.
-+
-+check_user(#state{authid=Authid,authzid=Authzid,
-+ authrealm=Auth_realm,host=Host,realm=Realm}) ->
-+ if Realm =/= Auth_realm ->
-+ ?DEBUG("bad realm ~p (expected ~p)~n",[Auth_realm, Realm]),
-+ throw({error, "not-authorized"});
-+ true ->
-+ ok
-+ end,
-+
-+ case ejabberd_auth:is_user_exists(Authid, Host) of
-+ false ->
-+ ?DEBUG("bad user ~p~n",[Authid]),
-+ throw({error, "not-authorized"});
-+ true ->
-+ ok
-+ end,
-+
-+ ?DEBUG("GSSAPI authenticated ~p ~p~n", [Authid, Authzid]),
-+ {ok, [{username, Authid}, {authzid, Authzid}]}.
-diff --git a/src/cyrsasl_plain.erl b/src/cyrsasl_plain.erl
-index 7192cd1..7bf41b3 100644
---- a/src/cyrsasl_plain.erl
-+++ b/src/cyrsasl_plain.erl
-@@ -27,7 +27,9 @@
- -module(cyrsasl_plain).
- -author('alexey(a)process-one.net').
-
---export([start/1, stop/0, mech_new/4, mech_step/2, parse/1]).
-+-export([start/1, stop/0, mech_new/1, mech_step/2, parse/1]).
-+
-+-include("cyrsasl.hrl").
-
- -behaviour(cyrsasl).
-
-@@ -40,7 +42,7 @@ start(_Opts) ->
- stop() ->
- ok.
-
--mech_new(_Host, _GetPassword, CheckPassword, _CheckPasswordDigest) ->
-+mech_new(#sasl_params{check_password = CheckPassword}) ->
- {ok, #state{check_password = CheckPassword}}.
-
- mech_step(State, ClientIn) ->
-diff --git a/src/cyrsasl_scram.erl b/src/cyrsasl_scram.erl
-index dc671b2..d65cc6f 100644
---- a/src/cyrsasl_scram.erl
-+++ b/src/cyrsasl_scram.erl
-@@ -29,10 +29,11 @@
-
- -export([start/1,
- stop/0,
-- mech_new/4,
-+ mech_new/1,
- mech_step/2]).
-
- -include("ejabberd.hrl").
-+-include("cyrsasl.hrl").
-
- -behaviour(cyrsasl).
-
-@@ -48,7 +49,7 @@ start(_Opts) ->
- stop() ->
- ok.
-
--mech_new(_Host, GetPassword, _CheckPassword, _CheckPasswordDigest) ->
-+mech_new(#sasl_params{get_password=GetPassword}) ->
- {ok, #state{step = 2, get_password = GetPassword}}.
-
- mech_step(#state{step = 2} = State, ClientIn) ->
-diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
-index ed26400..11ae5dd 100644
---- a/src/ejabberd_c2s.erl
-+++ b/src/ejabberd_c2s.erl
-@@ -305,9 +305,16 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
- send_header(StateData, Server, "1.0", DefaultLang),
- case StateData#state.authenticated of
- false ->
-+ Realm =
-+ case ejabberd_config:get_local_option({sasl_realm, Server}) of
-+ undefined ->
-+ "";
-+ Realm0 ->
-+ Realm0
-+ end,
- SASLState =
- cyrsasl:server_new(
-- "jabber", Server, "", [],
-+ "jabber", Server, Realm, [],
- fun(U) ->
- ejabberd_auth:get_password_with_authmodule(
- U, Server)
-@@ -319,7 +326,8 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
- fun(U, P, D, DG) ->
- ejabberd_auth:check_password_with_authmodule(
- U, Server, P, D, DG)
-- end),
-+ end,
-+ StateData#state.socket),
- Mechs = lists:map(
- fun(S) ->
- {xmlelement, "mechanism", [],
-diff --git a/src/ejabberd_socket.erl b/src/ejabberd_socket.erl
-index 836e7d9..59e4034 100644
---- a/src/ejabberd_socket.erl
-+++ b/src/ejabberd_socket.erl
-@@ -44,9 +44,11 @@
- get_peer_certificate/1,
- get_verify_result/1,
- close/1,
-+ gethostname/1,
- sockname/1, peername/1]).
-
- -include("ejabberd.hrl").
-+-include_lib("kernel/include/inet.hrl").
-
- -record(socket_state, {sockmod, socket, receiver}).
-
-@@ -228,6 +230,23 @@ peername(#socket_state{sockmod = SockMod, socket = Socket}) ->
- SockMod:peername(Socket)
- end.
-
-+gethostname(#socket_state{socket = Socket} = State) ->
-+ ?DEBUG("gethostname ~p~n", [Socket]),
-+
-+ case sockname(State) of
-+ {ok, {Addr, _Port}} ->
-+ case inet:gethostbyaddr(Addr) of
-+ {ok, HostEnt} when is_record(HostEnt, hostent) ->
-+ ?DEBUG("gethostname result ~p~n",
-+ [HostEnt#hostent.h_name]),
-+ {ok, HostEnt#hostent.h_name};
-+ {error, _Reason} = E ->
-+ E
-+ end;
-+ {error, _Reason} = E ->
-+ E
-+ end.
-+
- %%====================================================================
- %% Internal functions
- %%====================================================================
---
-1.8.3.1
-
diff --git a/ejabberd-0007-Disable-INET_DIST_INTERFACE-by-default.patch
b/ejabberd-0007-Disable-INET_DIST_INTERFACE-by-default.patch
deleted file mode 100644
index d0d1d40..0000000
--- a/ejabberd-0007-Disable-INET_DIST_INTERFACE-by-default.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From a8910615b82e7af8cb32916792970de0b53e5872 Mon Sep 17 00:00:00 2001
-From: Peter Lemenkov <lemenkov(a)gmail.com>
-Date: Sat, 18 Jun 2011 23:24:28 +0400
-Subject: [PATCH 07/10] Disable INET_DIST_INTERFACE by default
-
-Signed-off-by: Peter Lemenkov <lemenkov(a)gmail.com>
----
- src/ejabberdctl.cfg.example | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/ejabberdctl.cfg.example b/src/ejabberdctl.cfg.example
-index b72058a..5ee43cf 100644
---- a/src/ejabberdctl.cfg.example
-+++ b/src/ejabberdctl.cfg.example
-@@ -59,7 +59,7 @@
- #
- # Default: {127,0,0,1}
- #
--INET_DIST_INTERFACE={127,0,0,1}
-+#INET_DIST_INTERFACE={127,0,0,1}
-
- #.
- #' ERL_EPMD_ADDRESS: IP addresses where epmd listens for connections
---
-1.8.3.1
-
diff --git a/ejabberd-0007-Install-into-BINDIR-instead-of-SBINDIR.patch
b/ejabberd-0007-Install-into-BINDIR-instead-of-SBINDIR.patch
new file mode 100644
index 0000000..7a0e178
--- /dev/null
+++ b/ejabberd-0007-Install-into-BINDIR-instead-of-SBINDIR.patch
@@ -0,0 +1,45 @@
+From: Peter Lemenkov <lemenkov(a)gmail.com>
+Date: Wed, 17 Jul 2013 14:53:49 +0400
+Subject: [PATCH] Install into BINDIR instead of SBINDIR
+
+Signed-off-by: Peter Lemenkov <lemenkov(a)gmail.com>
+
+diff --git a/Makefile.in b/Makefile.in
+index de47be2..037d2ff 100644
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -11,8 +11,8 @@ DESTDIR =
+ # /etc/ejabberd/
+ ETCDIR = $(DESTDIR)@sysconfdir@/ejabberd
+
+-# /sbin/
+-SBINDIR = $(DESTDIR)@sbindir@
++# /bin/
++BINDIR = $(DESTDIR)@bindir@
+
+ # /lib/ejabberd/
+ EJABBERDDIR = $(DESTDIR)@libdir@/ejabberd
+@@ -126,11 +126,11 @@ install: all
+ $(INSTALL) -b -m 644 $(G_USER) inetrc $(ETCDIR)/inetrc
+ #
+ # Administration script
+- [ -d $(SBINDIR) ] || $(INSTALL) -d -m 755 $(SBINDIR)
+- $(INSTALL) -m 755 $(G_USER) ejabberdctl.example $(SBINDIR)/ejabberdctl
++ [ -d $(BINDIR) ] || $(INSTALL) -d -m 755 $(BINDIR)
++ $(INSTALL) -m 755 $(G_USER) ejabberdctl.example $(BINDIR)/ejabberdctl
+ #
+ # Init script
+- $(SED) -e "s*@ctlscriptpath@*$(SBINDIR)*" \
++ $(SED) -e "s*@ctlscriptpath@*$(BINDIR)*" \
+ -e "s*@installuser@*$(INIT_USER)*" ejabberd.init.template \
+ > ejabberd.init
+ chmod 755 ejabberd.init
+@@ -191,7 +191,7 @@ install: all
+ uninstall: uninstall-binary
+
+ uninstall-binary:
+- rm -f $(SBINDIR)/ejabberdctl
++ rm -f $(BINDIR)/ejabberdctl
+ rm -fr $(DOCDIR)
+ rm -f $(BEAMDIR)/*.beam
+ rm -f $(BEAMDIR)/*.app
diff --git a/ejabberd-0008-Clean-up-false-security-measure.patch
b/ejabberd-0008-Clean-up-false-security-measure.patch
deleted file mode 100644
index a44f130..0000000
--- a/ejabberd-0008-Clean-up-false-security-measure.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From c827055ee650243c2af546753743f692ae0fe758 Mon Sep 17 00:00:00 2001
-From: Peter Lemenkov <lemenkov(a)gmail.com>
-Date: Wed, 17 Jul 2013 14:56:09 +0400
-Subject: [PATCH 08/10] Clean up false security measure
-
-Signed-off-by: Peter Lemenkov <lemenkov(a)gmail.com>
----
- src/Makefile.in | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/Makefile.in b/src/Makefile.in
-index 64ed856..1a1fa41 100644
---- a/src/Makefile.in
-+++ b/src/Makefile.in
-@@ -202,7 +202,7 @@ install: all
- #
- # Administration script
- [ -d $(SBINDIR) ] || install -d -m 755 $(SBINDIR)
-- install -m 550 $(G_USER) ejabberdctl.example $(SBINDIR)/ejabberdctl
-+ install -m 755 $(G_USER) ejabberdctl.example $(SBINDIR)/ejabberdctl
- #
- # Init script
- sed -e "s*@ctlscriptpath@*$(SBINDIR)*" \
---
-1.8.3.1
-
diff --git a/ejabberd-0008-Disable-Erlang-version-check.patch
b/ejabberd-0008-Disable-Erlang-version-check.patch
new file mode 100644
index 0000000..3c6d723
--- /dev/null
+++ b/ejabberd-0008-Disable-Erlang-version-check.patch
@@ -0,0 +1,38 @@
+From: Peter Lemenkov <lemenkov(a)gmail.com>
+Date: Sat, 30 Aug 2014 12:21:45 +0400
+Subject: [PATCH] Disable Erlang version check
+
+Signed-off-by: Peter Lemenkov <lemenkov(a)gmail.com>
+
+diff --git a/configure.ac b/configure.ac
+index e7bb43b..d24c543 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -3,8 +3,6 @@
+
+ AC_PREREQ(2.53)
+ AC_INIT(ejabberd, m4_esyscmd([echo `git describe --tags 2>/dev/null || echo
community` | sed 's/-g.*//' | tr -d '\012']), [ejabberd(a)process-one.net],
[ejabberd])
+-REQUIRE_ERLANG_MIN="5.9.1 (Erlang/OTP R15B01)"
+-REQUIRE_ERLANG_MAX="9.0.0 (No Max)"
+
+ # Checks for programs.
+ AC_PROG_MAKE_SET
+@@ -32,18 +30,6 @@ AC_PATH_TOOL(ERLC, erlc, , [${extra_erl_path}$PATH])
+ AC_ERLANG_NEED_ERL
+ AC_ERLANG_NEED_ERLC
+
+-AC_ARG_ENABLE(erlang-version-check,
+-[AC_HELP_STRING([--enable-erlang-version-check],
+- [Check Erlang/OTP version @<:@default=yes@:>@])])
+-case "$enable_erlang_version_check" in
+- yes|'')
+- ERLANG_VERSION_CHECK([$REQUIRE_ERLANG_MIN],[$REQUIRE_ERLANG_MAX])
+- ;;
+- no)
+- ERLANG_VERSION_CHECK([$REQUIRE_ERLANG_MIN],[$REQUIRE_ERLANG_MAX],[warn])
+- ;;
+-esac
+-
+ # Checks and sets ERLANG_ROOT_DIR and ERLANG_LIB_DIR variable
+ AC_ERLANG_SUBST_ROOT_DIR
+ # AC_ERLANG_SUBST_LIB_DIR
diff --git a/ejabberd-0009-Enable-polkit-support.patch
b/ejabberd-0009-Enable-polkit-support.patch
deleted file mode 100644
index fd31fd1..0000000
--- a/ejabberd-0009-Enable-polkit-support.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-From f2420ac96bb52eeb5a01111cabb4f5580db42142 Mon Sep 17 00:00:00 2001
-From: Peter Lemenkov <lemenkov(a)gmail.com>
-Date: Wed, 17 Jul 2013 14:51:04 +0400
-Subject: [PATCH 09/10] Enable polkit support
-
-Signed-off-by: Peter Lemenkov <lemenkov(a)gmail.com>
----
- src/ejabberdctl.template | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template
-index b298e01..fa6c5c2 100644
---- a/src/ejabberdctl.template
-+++ b/src/ejabberdctl.template
-@@ -1,4 +1,4 @@
--#!/bin/sh
-+#!/usr/bin/pkexec /bin/sh
-
- # define default configuration
- POLL=true
---
-1.8.3.1
-
diff --git a/ejabberd-0009-Fix-permissions-for-captcha-script.patch
b/ejabberd-0009-Fix-permissions-for-captcha-script.patch
new file mode 100644
index 0000000..d694c57
--- /dev/null
+++ b/ejabberd-0009-Fix-permissions-for-captcha-script.patch
@@ -0,0 +1,19 @@
+From: Peter Lemenkov <lemenkov(a)gmail.com>
+Date: Sun, 31 Aug 2014 13:21:48 +0400
+Subject: [PATCH] Fix permissions for captcha script
+
+Signed-off-by: Peter Lemenkov <lemenkov(a)gmail.com>
+
+diff --git a/Makefile.in b/Makefile.in
+index 037d2ff..d972c98 100644
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -150,7 +150,7 @@ install: all
+ #
+ # Binary C programs
+ $(INSTALL) -d $(PBINDIR)
+- $(INSTALL) -m 750 $(O_USER) tools/captcha.sh $(PBINDIR)
++ $(INSTALL) -m 755 $(O_USER) tools/captcha.sh $(PBINDIR)
+ -[ -f deps/p1_pam/priv/bin/epam ] \
+ && $(INSTALL) -m 750 $(O_USER) deps/p1_pam/priv/bin/epam $(PBINDIR)
+ #
diff --git a/ejabberd-0010-Enable-systemd-notification-if-available.patch
b/ejabberd-0010-Enable-systemd-notification-if-available.patch
new file mode 100644
index 0000000..8a04f37
--- /dev/null
+++ b/ejabberd-0010-Enable-systemd-notification-if-available.patch
@@ -0,0 +1,18 @@
+From: Peter Lemenkov <lemenkov(a)gmail.com>
+Date: Sun, 31 Aug 2014 16:08:17 +0400
+Subject: [PATCH] Enable systemd notification if available
+
+Signed-off-by: Peter Lemenkov <lemenkov(a)gmail.com>
+
+diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl
+index 379f728..9aa6801 100644
+--- a/src/ejabberd_app.erl
++++ b/src/ejabberd_app.erl
+@@ -66,6 +66,7 @@ start(normal, _Args) ->
+ maybe_add_nameservers(),
+ start_modules(),
+ ejabberd_listener:start_listeners(),
++ {module, sd_notify} == code:load_file(sd_notify) andalso sd_notify:sd_notify(0,
"READY=1"),
+ ?INFO_MSG("ejabberd ~s is started in the node ~p", [?VERSION, node()]),
+ Sup;
+ start(_, _) ->
diff --git a/ejabberd-0010-Install-into-BINDIR-instead-of-SBINDIR.patch
b/ejabberd-0010-Install-into-BINDIR-instead-of-SBINDIR.patch
deleted file mode 100644
index 3868b01..0000000
--- a/ejabberd-0010-Install-into-BINDIR-instead-of-SBINDIR.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From 729db839b762a472444bacff22a1cb8870635272 Mon Sep 17 00:00:00 2001
-From: Peter Lemenkov <lemenkov(a)gmail.com>
-Date: Wed, 17 Jul 2013 14:53:49 +0400
-Subject: [PATCH 10/10] Install into BINDIR instead of SBINDIR
-
-Signed-off-by: Peter Lemenkov <lemenkov(a)gmail.com>
----
- src/Makefile.in | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/src/Makefile.in b/src/Makefile.in
-index 1a1fa41..1578183 100644
---- a/src/Makefile.in
-+++ b/src/Makefile.in
-@@ -92,7 +92,7 @@ DESTDIR =
- ETCDIR = $(DESTDIR)@sysconfdir@/ejabberd
-
- # /sbin/
--SBINDIR = $(DESTDIR)@sbindir@
-+BINDIR = $(DESTDIR)@bindir@
-
- # /lib/ejabberd/
- EJABBERDDIR = $(DESTDIR)@libdir@/ejabberd
-@@ -201,11 +201,11 @@ install: all
- install -b -m 644 $(G_USER) inetrc $(ETCDIR)/inetrc
- #
- # Administration script
-- [ -d $(SBINDIR) ] || install -d -m 755 $(SBINDIR)
-- install -m 755 $(G_USER) ejabberdctl.example $(SBINDIR)/ejabberdctl
-+ [ -d $(BINDIR) ] || install -d -m 755 $(BINDIR)
-+ install -m 755 $(G_USER) ejabberdctl.example $(BINDIR)/ejabberdctl
- #
- # Init script
-- sed -e "s*@ctlscriptpath@*$(SBINDIR)*" \
-+ sed -e "s*@ctlscriptpath@*$(BINDIR)*" \
- -e "s*@installuser@*$(INIT_USER)*" ejabberd.init.template \
- > ejabberd.init
- chmod 755 ejabberd.init
-@@ -273,7 +273,7 @@ install: all
- uninstall: uninstall-binary
-
- uninstall-binary:
-- rm -f $(SBINDIR)/ejabberdctl
-+ rm -f $(BINDIR)/ejabberdctl
- rm -fr $(DOCDIR)
- rm -f $(BEAMDIR)/*.beam
- rm -f $(BEAMDIR)/*.app
---
-1.8.3.1
-
diff --git a/ejabberd.init b/ejabberd.init
deleted file mode 100644
index 71cadea..0000000
--- a/ejabberd.init
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/bin/bash
-#
-# ejabberd Start and stop ejabberd.
-
-# chkconfig: - 40 60
-# description: ejabberd
-# processname: ejabberd
-# pidfile: /var/run/ejabberd.pid
-
-### BEGIN INIT INFO
-# Provides: ejabberd
-# Required-Start: network
-# Required-Stop: network
-# Default-Start:
-# Default-Stop: 0 1 6
-# Short-Description: Start and stop ejabberd
-# Description: A distributed, fault-tolerant Jabber/XMPP server
-### END INIT INFO
-
-. /etc/rc.d/init.d/functions
-
-if [ -r /etc/sysconfig/ejabberd ]; then
- . /etc/sysconfig/ejabberd
-fi
-
-if [ ! "$CONFIG_FILE" ]; then
- CONFIG_FILE=/etc/ejabberd/ejabberd.cfg
-fi
-
-# we're using symlinked consolehelper to check user's rights
-progctl=/usr/bin/ejabberdctl
-
-start() {
- echo -n $"Starting ejabberd: "
- if [ "$ULIMIT_MAX_FILES" ]; then
- ulimit -n $ULIMIT_MAX_FILES
- fi
-
- # check whether ejabberd was already started
- if $progctl status > /dev/null 2>&1 ; then
- echo -n "already running" && warning && echo
- return 0
- fi
-
- daemon $progctl start --config $CONFIG_FILE \
- --ctl-config /etc/ejabberd/ejabberdctl.cfg \
- --logs "/var/log/ejabberd" \
- --spool "/var/lib/ejabberd/spool" \
- 2>/dev/null
- RETVAL=$?
- [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ejabberd
- echo
-
- # it takes some time to actually start necessary nodes
- sleep 5
-
- return $RETVAL
-}
-
-stop() {
- # Stop daemons.
- echo -n "Shutting down ejabberd: "
-
- # check whether ejabberd was already stopped
- if ! $progctl status > /dev/null 2>&1 ; then
- echo -n "already stopped" && warning && echo
- return 0
- fi
-
- daemon $progctl stop 2>/dev/null
- RETVAL=$?
- [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ejabberd
- echo
-
- # it takes some time to actually stop necessary nodes
- sleep 5
-
- return $RETVAL
-}
-
-restart() {
- stop
- sleep 5
- start
-}
-
-# See how we were called.
-case "$1" in
- start)
- start
- ;;
- stop)
- stop
- ;;
- restart|force-reload)
- restart
- ;;
- condrestart|try-restart)
- [ -f /var/lock/subsys/ejabberd ] && restart || :
- ;;
- status)
- $progctl status
- ;;
- *)
- echo "Usage: ejabberd
{start|stop|restart|force-reload|condrestart|try-restart|status}"
- exit 2
-esac
-
-exit $?
-
-
diff --git a/ejabberd.logrotate b/ejabberd.logrotate
index cf5274a..9921889 100644
--- a/ejabberd.logrotate
+++ b/ejabberd.logrotate
@@ -4,6 +4,6 @@
create 0640 ejabberd ejabberd
sharedscripts
postrotate
- runuser -s /bin/bash - ejabberd -c "/usr/sbin/ejabberdctl reopen-log"
>/dev/null 2>/dev/null || true
+ runuser -s /bin/bash - ejabberd -c "/usr/bin/ejabberdctl reopen-log"
>/dev/null 2>/dev/null || true
endscript
}
diff --git a/ejabberd.service b/ejabberd.service
index ea16733..2fe9048 100644
--- a/ejabberd.service
+++ b/ejabberd.service
@@ -1,6 +1,7 @@
[Unit]
Description=A distributed, fault-tolerant Jabber/XMPP server
-After=network.target
+Requires=network-online.target
+After=network-online.target
[Service]
Type=oneshot
@@ -9,11 +10,11 @@ Group=ejabberd
LimitNOFILE=16000
RestartSec=5
ExecStart=/usr/bin/bash /usr/bin/ejabberdctl \
- --config /etc/ejabberd/ejabberd.cfg \
+ --config /etc/ejabberd/ejabberd.yml \
--ctl-config /etc/ejabberd/ejabberdctl.cfg \
--logs "/var/log/ejabberd" \
- --spool "/var/lib/ejabberd/spool" start
-ExecStop=/usr/sbin/ejabberdctl stop
+ --spool "/var/lib/ejabberd" start
+ExecStop=/usr/bin/ejabberdctl stop
RemainAfterExit=yes
[Install]
diff --git a/ejabberd.spec b/ejabberd.spec
index 52c8d73..485d856 100644
--- a/ejabberd.spec
+++ b/ejabberd.spec
@@ -1,4 +1,5 @@
%global _hardened_build 1
+
# FIXME non-standard directory for storing *.so objects
%{?filter_setup:
%filter_provides_in %{_libdir}/ejabberd/priv/lib/.*\.so$
@@ -15,15 +16,14 @@
# see
https://bugzilla.redhat.com/bugzilla/250253
%global _with_hevea 0
%else
-# FIXME Hevea is deadly broken currently
-%global _with_hevea 0
+%global _with_hevea 1
%endif
%endif
Name: ejabberd
-Version: 2.1.13
-Release: 10%{?dist}
+Version: 14.07
+Release: 1%{?dist}
Summary: A distributed, fault-tolerant Jabber/XMPP server
Group: Applications/Internet
@@ -32,10 +32,8 @@ URL:
http://www.ejabberd.im/
%if 0%{?el7}%{?fedora}
VCS:
scm:git:https://github.com/processone/ejabberd.git
%endif
-Source0:
https://github.com/processone/%{name}/archive/v%{version}/%{name}-v%{vers...
-Source1: ejabberd.init
+Source0:
https://github.com/processone/%{name}/archive/%{version}/%{name}-%{versio...
Source2: ejabberd.logrotate
-Source3: ejabberd.sysconfig
# Support for systemd
Source4: ejabberd.service
@@ -45,42 +43,46 @@ Source5: ejabberd.tmpfiles.conf
Source9: ejabberdctl.pam
Source11: ejabberd.pam
-# usermode support for old systems
-Source10: ejabberdctl.apps
# polkit support
Source12: ejabberdctl.polkit.actions
Source13: ejabberdctl.polkit.rules
+Source14: ejabberd-src-deps.tar
+
# Use ejabberd as an example for PAM service name (fedora/epel-specific)
Patch1: ejabberd-0001-Fix-PAM-service-example-name-to-match-actual-one.patch
-# fixed delays in s2s connections
-Patch2: ejabberd-0002-Fixed-delays-in-s2s-connections.patch
# Introducing mod_admin_extra
-Patch3: ejabberd-0003-Introducing-mod_admin_extra.patch
+Patch2: ejabberd-0002-Introducing-mod_admin_extra.patch
# BZ# 439583, 452326, 451554, 465196, 502361 (fedora/epel-specific)
-Patch4: ejabberd-0004-Fedora-specific-changes-to-ejabberdctl.patch
-# Fix so-lib permissions while installing (fedora/epel-specific)
-Patch5: ejabberd-0005-Install-.so-objects-with-0755-permissions.patch
-# Backported from upstream
-Patch6: ejabberd-0006-Support-SASL-GSSAPI-authentication-thanks-to-Mikael-.patch
-# Disable IP restriction for ejabberdctl (seems that it doesn't work well)
-Patch7: ejabberd-0007-Disable-INET_DIST_INTERFACE-by-default.patch
-# Don't try to make system-wide scripts unreadable for users (fedora/epel-specific)
-Patch8: ejabberd-0008-Clean-up-false-security-measure.patch
+Patch3: ejabberd-0003-Fedora-specific-changes-to-ejabberdctl.patch
+# Fedora-specific
+Patch4: ejabberd-0004-Install-.so-objects-with-0755-permissions.patch
+# Fedora-specific
+Patch5: ejabberd-0005-Clean-up-false-security-measure.patch
# polkit support
-Patch9: ejabberd-0009-Enable-polkit-support.patch
-# polkit support
-Patch10:ejabberd-0010-Install-into-BINDIR-instead-of-SBINDIR.patch
-
-BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+Patch6: ejabberd-0006-Enable-polkit-support.patch
+# Fedora-specific
+Patch7: ejabberd-0007-Install-into-BINDIR-instead-of-SBINDIR.patch
+# Fedora-specific
+Patch8: ejabberd-0008-Disable-Erlang-version-check.patch
+# Fedora-specific
+Patch9: ejabberd-0009-Fix-permissions-for-captcha-script.patch
+# Fedora-specific
+Patch10:ejabberd-0010-Enable-systemd-notification-if-available.patch
BuildRequires: expat-devel
BuildRequires: openssl-devel >= 0.9.8
BuildRequires: pam-devel
+BuildRequires: libyaml-devel
BuildRequires: erlang
+BuildRequires: erlang-rebar
+# FIXME
+#BuildRequires: erlang-jiffy
+#BuildRequires: erlang-lager
+#BuildRequires: erlang-ibrowse
+#BuildRequires: erlang-xmlrpc
%if 0%{?_with_hevea}
BuildRequires: hevea
-BuildRequires: texlive
BuildRequires: texlive-comment
%endif
BuildRequires: autoconf
@@ -90,61 +92,22 @@ BuildRequires: automake
Requires(pre): shadow-utils
Requires(post): /usr/bin/openssl
-%if 0%{?el5}%{?el6}
-Requires(post): /sbin/chkconfig
-Requires(preun): /sbin/chkconfig
-Requires(preun): /sbin/service
-Requires(postun): /sbin/service
-%else
Requires(post): systemd
Requires(preun): systemd
Requires(postun): systemd
-%endif
Provides: user(%{name})
Provides: group(%{name})
-#Error:erlang(exmpp_jid:domain_as_list/1)
-#Error:erlang(exmpp_jid:make/2)
-#Error:erlang(exmpp_jid:node_as_list/1)
-#Error:erlang(exmpp_jid:parse/1)
-#Error:erlang(exmpp_jid:prep_domain_as_list/1)
-#Error:erlang(exmpp_jid:prep_node_as_list/1)
-#Error:erlang(exmpp_jid:prep_resource_as_list/1)
-#Error:erlang(exmpp_jid:resource_as_list/1)
-#Error:erlang(exmpp:start/0)
-#Error:erlang(exmpp_xml:document_to_list/1)
-#Error:erlang(exmpp_xml:foreach/2)
-#Error:erlang(exmpp_xml:get_attribute/3)
-#Error:erlang(exmpp_xml:get_attribute_as_list/3)
-#Error:erlang(exmpp_xml:get_element/2)
-#Error:erlang(exmpp_xml:get_elements/2)
-#Error:erlang(exmpp_xml:parse/2)
-#Error:erlang(exmpp_xml:start_parser/1)
-#Error:erlang(exmpp_xml:stop_parser/1)
-#Error:erlang(exmpp_xml:xmlelement_to_xmlel/1)
-#Error:erlang(exmpp_xml:xmlel_to_xmlelement/1)
-#Error:erlang(mysql_conn:fetch/3)
-#Error:erlang(mysql_conn:start/6)
-#Error:erlang(mysql_conn:stop/1)
-#Error:erlang(mysql:get_result_affected_rows/1)
-#Error:erlang(mysql:get_result_field_info/1)
-#Error:erlang(mysql:get_result_reason/1)
-#Error:erlang(mysql:get_result_rows/1)
-#Error:erlang(release_handler_1:eval_script/3)
-#Error:erlang(ssl:seed/1)
Requires: erlang
-#Error:erlang(esasl:str_error/2)
-Requires: erlang-esasl
-%if 0%{?el5}%{?el6}
-Requires: usermode
-%else
+# FIXME see also patch #10
+#Requires: erlang-sd_notify
# for /usr/bin/pkexec
Requires: polkit
-%endif
# for flock in ejabberdctl
Requires: util-linux
%{?__erlang_drv_version:Requires: %{__erlang_drv_version}}
+%{?__erlang_nif_version:Requires: %{__erlang_nif_version}}
%description
@@ -155,10 +118,8 @@ Windows NT/2000/XP).
%package doc
Summary: Documentation for ejabberd
-%if 0%{?el6}%{?el7}%{?fedora}
BuildArch: noarch
Obsoletes: %{name}-doc < 2.1.4
-%endif
# docdir owner
Requires: %{name} = %{version}-%{release}
Group: Documentation
@@ -170,100 +131,67 @@ Documentation for ejabberd.
%setup -q
%patch1 -p1 -b .pam_name
-%patch2 -p1 -b .s2s_delays
-%patch3 -p1 -b .mod_admin_extra
-%patch4 -p1 -b .fedora_specific
-%patch5 -p1 -b .fix_perms
-%patch6 -p1 -b .gssapi
-%patch7 -p1 -b .disable_ip_restriction_for_ejabberdctl
-%patch8 -p1 -b .dont_hide
-%if 0%{?el7}%{?fedora}
-%patch9 -p1 -b .use_polkit
-%patch10 -p1 -b .usr_bin
-%endif
+%patch2 -p1 -b .mod_admin_extra
+%patch3 -p1 -b .fedora_specific
+%patch4 -p1 -b .so_lib_755
+%patch5 -p1 -b .false_security
+%patch6 -p1 -b .use_polkit
+%patch7 -p1 -b .use_bindir
+%patch8 -p1 -b .no_ver_check
+%patch9 -p1 -b .captcha_perms
+#%patch10 -p1 -b .systemd_notify
+
+tar xvf %{S:14}
%build
-pushd src
autoreconf -ivf
-%configure --enable-odbc --enable-pam
-# doesn't build on SMP currently
+
+# Disabled: --enable-hipe --enable-roster-gateway-workaround
--enable-transient_supervisors --enable-full-xml --enable-mssql --enable-tools
--enable-riak
+%configure --enable-nif --enable-odbc --enable-mysql --enable-pgsql --enable-pam
--enable-zlib --enable-json --enable-iconv --enable-debug --enable-http --enable-lager
make
-popd
%if 0%{?_with_hevea}
pushd doc
# remove pre-built docs
-rm -f dev.html features.html features.pdf guide.html guide.pdf
+rm -f dev.html features.html
+# See this link -
http://thread.gmane.org/gmane.linux.redhat.fedora.devel/198954/focus=198957
+make release
make html pdf
popd
%endif
%install
-rm -rf %{buildroot}
-
-pushd src
make install DESTDIR=%{buildroot}
-popd
# fix example SSL certificate path to real one, which we created recently (see above)
-%{__perl} -pi -e 's!/path/to/ssl.pem!/etc/ejabberd/ejabberd.pem!g'
%{buildroot}/etc/ejabberd/ejabberd.cfg
+%{__perl} -pi -e 's!/path/to/ssl.pem!/etc/ejabberd/ejabberd.pem!g'
%{buildroot}/etc/ejabberd/ejabberd.yml
# fix captcha path
-%{__perl} -pi -e
's!/lib/ejabberd/priv/bin/captcha.sh!%{_libdir}/%{name}/priv/bin/captcha.sh!g'
%{buildroot}/etc/ejabberd/ejabberd.cfg
-
-mkdir -p %{buildroot}/var/log/ejabberd
-mkdir -p %{buildroot}/var/lib/ejabberd/spool
+%{__perl} -pi -e
's!/lib/ejabberd/priv/bin/captcha.sh!%{_libdir}/%{name}/priv/bin/captcha.sh!g'
%{buildroot}/etc/ejabberd/ejabberd.yml
install -D -p -m 0644 %{S:9} %{buildroot}%{_sysconfdir}/pam.d/ejabberdctl
install -D -p -m 0644 %{S:11} %{buildroot}%{_sysconfdir}/pam.d/ejabberd
-%if 0%{?el5}
-# No password-auth PAM scheme in EL5 - see rhbz #758601
-sed -i -e "s,password-auth,system-auth,g"
%{buildroot}%{_sysconfdir}/pam.d/ejabberd
-%endif
-
-%if 0%{?el5}%{?el6}
-# install init-script
-install -D -p -m 0755 %{S:1} %{buildroot}%{_initrddir}/ejabberd
-# install sysconfig file
-install -D -p -m 0644 %{S:3} %{buildroot}%{_sysconfdir}/sysconfig/ejabberd
-%else
# install systemd entry
install -D -m 0644 -p %{S:4} %{buildroot}%{_unitdir}/%{name}.service
install -D -m 0644 -p %{S:5} %{buildroot}%{_tmpfilesdir}/%{name}.conf
-%endif
# install config for logrotate
install -D -p -m 0644 %{S:2} %{buildroot}%{_sysconfdir}/logrotate.d/ejabberd
-# create room for necessary data
+# create room for additional files (such as SQL schemas)
install -d %{buildroot}%{_datadir}/%{name}
# install sql-scripts for creating db schemes for various RDBMS
-install -p -m 0644 src/odbc/mssql2000.sql %{buildroot}%{_datadir}/%{name}
-install -p -m 0644 src/odbc/mssql2005.sql %{buildroot}%{_datadir}/%{name}
-install -p -m 0644 src/odbc/mysql.sql %{buildroot}%{_datadir}/%{name}
-install -p -m 0644 src/odbc/pg.sql %{buildroot}%{_datadir}/%{name}
-
-# Fix permissions for captcha script
-# In fact, we can also chown root:ejabberd here, but I'm not sure
-# that we should care about the possibility of reading by someone
-# for this *default* sript, which is not intended to be changed
-chmod 755 %{buildroot}%{_libdir}/%{name}/priv/bin/captcha.sh
-
-%if 0%{?el5}%{?el6}
-# Use usermode on old systems
-mkdir -p %{buildroot}%{_bindir}
-ln -s consolehelper %{buildroot}%{_bindir}/ejabberdctl
-install -D -p -m 0644 %{S:10}
%{buildroot}%{_sysconfdir}/security/console.apps/ejabberdctl
-%else
-# Use polkit
+install -p -m 0644 sql/mssql2000.sql %{buildroot}%{_datadir}/%{name}
+install -p -m 0644 sql/mssql2005.sql %{buildroot}%{_datadir}/%{name}
+install -p -m 0644 sql/mssql2012.sql %{buildroot}%{_datadir}/%{name}
+install -p -m 0644 sql/mysql.sql %{buildroot}%{_datadir}/%{name}
+install -p -m 0644 sql/pg.sql %{buildroot}%{_datadir}/%{name}
+
+# Install polkit-related files
install -D -p -m 0644 %{S:12}
%{buildroot}%{_datadir}/polkit-1/actions/ejabberdctl.policy
install -D -p -m 0644 %{S:13}
%{buildroot}%{_datadir}/polkit-1/rules.d/51-ejabberdctl.rules
-%endif
-
-# Remove installed doc-files
-rm -rf %{buildroot}%{_defaultdocdir}
%pre
@@ -293,25 +221,18 @@ if [ $1 -gt 1 ]; then
# fix cookie path (since ver. 2.1.0 cookie stored in /var/lib/ejabberd/spool
# rather than in /var/lib/ejabberd
- if [ -f /var/lib/ejabberd/.erlang.cookie ]; then
- cp -pu /var/lib/ejabberd/{,spool/}.erlang.cookie
+ if [ -f /var/lib/ejabberd/spool/.erlang.cookie ]; then
+ cp -pu /var/lib/ejabberd/{spool/,}.erlang.cookie
echo
- echo The ejabberd cookie file was moved.
- echo Please delete old one from /var/lib/ejabberd/.erlang.cookie
+ echo The ejabberd cookie file was moved again.
+ echo Please delete old one from /var/lib/ejabberd/spool/.erlang.cookie
echo
fi
fi
%post
-%if 0%{?el5}%{?el6}
-if [ $1 -eq 1 ]; then
- # Initial installation
- /sbin/chkconfig --add %{name} || :
-fi
-%else
%systemd_post %{name}.service
-%endif
# Create SSL certificate with default values if it doesn't exist
(cd /etc/ejabberd
@@ -336,111 +257,56 @@ fi)
%preun
-%if 0%{?el5}%{?el6}
-if [ $1 -eq 0 ]; then
- # Package removal, not upgrade
- /sbin/service %{name} stop >/dev/null 2>&1 || :
- /sbin/chkconfig --del %{name} || :
-fi
-%else
%systemd_preun %{name}.service
-%endif
%postun
-%if 0%{?el5}%{?el6}
-if [ $1 -ge 1 ]; then
- # Package upgrade, not uninstall
- /sbin/service %{name} condrestart >/dev/null 2>&1
-fi
-%else
%systemd_postun_with_restart %{name}.service
-%endif
-
-
-%clean
-rm -rf %{buildroot}
%files
%doc COPYING
%attr(750,ejabberd,ejabberd) %dir %{_sysconfdir}/ejabberd
-%attr(640,ejabberd,ejabberd) %config(noreplace) %{_sysconfdir}/ejabberd/ejabberd.cfg
+%attr(640,ejabberd,ejabberd) %config(noreplace) %{_sysconfdir}/ejabberd/ejabberd.yml
%attr(640,ejabberd,ejabberd) %config(noreplace) %{_sysconfdir}/ejabberd/ejabberdctl.cfg
%attr(640,ejabberd,ejabberd) %config(noreplace) %{_sysconfdir}/ejabberd/inetrc
-%if 0%{?el5}%{?el6}
-%config(noreplace) %{_sysconfdir}/sysconfig/%{name}
-%{_initrddir}/%{name}
-%else
%{_unitdir}/%{name}.service
%{_tmpfilesdir}/%{name}.conf
-%endif
%config(noreplace) %{_sysconfdir}/logrotate.d/%{name}
%config(noreplace) %{_sysconfdir}/pam.d/%{name}
%config(noreplace) %{_sysconfdir}/pam.d/ejabberdctl
-%if 0%{?el5}%{?el6}
-%{_sbindir}/ejabberdctl
-%config(noreplace) %{_sysconfdir}/security/console.apps/ejabberdctl
-%else
%{_datadir}/polkit-1/actions/ejabberdctl.policy
%{_datadir}/polkit-1/rules.d/51-ejabberdctl.rules
-%endif
%{_bindir}/ejabberdctl
%dir %{_libdir}/%{name}
%dir %{_libdir}/%{name}/ebin
%dir %{_libdir}/%{name}/include
-%dir %{_libdir}/%{name}/include/eldap
-%dir %{_libdir}/%{name}/include/mod_muc
-%dir %{_libdir}/%{name}/include/mod_proxy65
-%dir %{_libdir}/%{name}/include/mod_pubsub
-%dir %{_libdir}/%{name}/include/web
%dir %{_libdir}/%{name}/priv
%dir %{_libdir}/%{name}/priv/bin
%dir %{_libdir}/%{name}/priv/lib
%dir %{_libdir}/%{name}/priv/msgs
-%{_libdir}/%{name}/ebin/%{name}.app
+%{_libdir}/%{name}/ebin/*.app
%{_libdir}/%{name}/ebin/*.beam
-%{_libdir}/%{name}/include/XmppAddr.hrl
-%{_libdir}/%{name}/include/adhoc.hrl
-%{_libdir}/%{name}/include/cyrsasl.hrl
-%{_libdir}/%{name}/include/ejabberd.hrl
-%{_libdir}/%{name}/include/ejabberd_commands.hrl
-%{_libdir}/%{name}/include/ejabberd_config.hrl
-%{_libdir}/%{name}/include/ejabberd_ctl.hrl
-%{_libdir}/%{name}/include/eldap/ELDAPv3.hrl
-%{_libdir}/%{name}/include/eldap/eldap.hrl
-%{_libdir}/%{name}/include/jlib.hrl
-%{_libdir}/%{name}/include/mod_muc/mod_muc_room.hrl
-%{_libdir}/%{name}/include/mod_privacy.hrl
-%{_libdir}/%{name}/include/mod_proxy65/mod_proxy65.hrl
-%{_libdir}/%{name}/include/mod_pubsub/pubsub.hrl
-%{_libdir}/%{name}/include/mod_roster.hrl
-%{_libdir}/%{name}/include/web/ejabberd_http.hrl
-%{_libdir}/%{name}/include/web/ejabberd_web_admin.hrl
-%{_libdir}/%{name}/include/web/http_bind.hrl
+%{_libdir}/%{name}/include/*.hrl
%{_libdir}/%{name}/priv/bin/captcha.sh
%attr(4750,root,ejabberd) %{_libdir}/%{name}/priv/bin/epam
-%{_libdir}/%{name}/priv/lib/ejabberd_zlib_drv.so
-%{_libdir}/%{name}/priv/lib/expat_erl.so
-%{_libdir}/%{name}/priv/lib/iconv_erl.so
-%{_libdir}/%{name}/priv/lib/sha_drv.so
-%{_libdir}/%{name}/priv/lib/stringprep_drv.so
-%{_libdir}/%{name}/priv/lib/tls_drv.so
+%{_libdir}/%{name}/priv/lib/*.so
+
%{_libdir}/%{name}/priv/msgs/*.msg
%dir %{_datadir}/%{name}
%{_datadir}/%{name}/mssql2000.sql
%{_datadir}/%{name}/mssql2005.sql
+%{_datadir}/%{name}/mssql2012.sql
%{_datadir}/%{name}/mysql.sql
%{_datadir}/%{name}/pg.sql
%attr(750,ejabberd,ejabberd) %dir /var/lib/ejabberd
-%attr(750,ejabberd,ejabberd) %dir /var/lib/ejabberd/spool
%attr(750,ejabberd,ejabberd) %dir /var/lock/ejabberdctl
%attr(750,ejabberd,ejabberd) %dir /var/log/ejabberd
@@ -454,6 +320,14 @@ rm -rf %{buildroot}
%changelog
+* Sat Aug 30 2014 Peter Lemenkov <lemenkov(a)gmail.com> - 14.07-1
+- Ver. 14.07
+- Dropped support for EPEL5, EPEL6
+- Dropped initial untested support for GSSAPI - nobody is interested in testing
+ and further developing this
+- Fixed
https://bugzilla.redhat.com/1089475
+- Fixed
https://bugzilla.redhat.com/1117450
+
* Thu Aug 28 2014 Peter Lemenkov <lemenkov(a)gmail.com> - 2.1.13-10
- Rebuild with Erlang 17.2.1
diff --git a/ejabberd.sysconfig b/ejabberd.sysconfig
deleted file mode 100644
index 20a8a7a..0000000
--- a/ejabberd.sysconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-## Settings for ejabberd
-
-## Where should ejabberd find its configuration file?
-#
-CONFIG_FILE=/etc/ejabberd/ejabberd.cfg
-
-## ULIMIT_MAX_FILES alters the number of files that ejabberd is
-## allowed to have open at once. If it is unset the system default
-## (usually 1024) will be used. ejabberd will want over twice as many
-## open files as it has active connections, so if you have a few
-## hundred or more users you will want to set this.
-#
-ULIMIT_MAX_FILES=1024
diff --git a/ejabberdctl.apps b/ejabberdctl.apps
deleted file mode 100644
index 30eab2c..0000000
--- a/ejabberdctl.apps
+++ /dev/null
@@ -1,5 +0,0 @@
-USER=root
-PROGRAM=/usr/sbin/ejabberdctl
-SESSION=yes
-FALLBACK=no
-GUI=no
diff --git a/sources b/sources
index 4c10b8d..b1728e6 100644
--- a/sources
+++ b/sources
@@ -1 +1,2 @@
-2a7c3b711b4f7091f811c51b52beb735 ejabberd-v2.1.13.tar.gz
+a26b8acfc8fd15d94874befa06da15be ejabberd-14.07.tar.gz
+0362024d73b2c8ee38246be5a168869b ejabberd-src-deps.tar
--
cgit v1.1
https://src.fedoraproject.org/cgit/ejabberd.git/commit/?h=epel7&id=14...