rpms/ejabberd/F-11 ejabberd-captcha-bashism.patch, NONE, 1.1 ejabberd-http-poll-web-page.patch, NONE, 1.1 ejabberd-mod_admin_extra.patch, NONE, 1.1 ejabberd-piefxis-vhost-export.patch, NONE, 1.1 ejabberd-vcard-reqs-forwarding.patch, NONE, 1.1 ejabberd-ejabberdctl_fix.diff, 1.7, 1.8 ejabberd.spec, 1.41, 1.42 import.log, 1.14, 1.15
Peter Lemenkov
peter at fedoraproject.org
Thu Dec 10 19:11:12 UTC 2009
- Previous message: rpms/ejabberd/F-12 ejabberd-captcha-bashism.patch, NONE, 1.1 ejabberd-http-poll-web-page.patch, NONE, 1.1 ejabberd-mod_admin_extra.patch, NONE, 1.1 ejabberd-piefxis-vhost-export.patch, NONE, 1.1 ejabberd-vcard-reqs-forwarding.patch, NONE, 1.1 ejabberd-ejabberdctl_fix.diff, 1.7, 1.8 ejabberd.spec, 1.47, 1.48 import.log, 1.15, 1.16
- Next message: rpms/automake/devel automake.spec,1.47,1.48
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Author: peter
Update of /cvs/pkgs/rpms/ejabberd/F-11
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv11011/F-11
Modified Files:
ejabberd-ejabberdctl_fix.diff ejabberd.spec import.log
Added Files:
ejabberd-captcha-bashism.patch
ejabberd-http-poll-web-page.patch
ejabberd-mod_admin_extra.patch
ejabberd-piefxis-vhost-export.patch
ejabberd-vcard-reqs-forwarding.patch
Log Message:
Fixed all issues, related with upgrading from the previous 2.0.5
ejabberd-captcha-bashism.patch:
captcha.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- NEW FILE ejabberd-captcha-bashism.patch ---
Makes the captcha script explicitly request bash as it uses
its special variable "RANDOM" which is not defined by POSIX.
The issue is tracked upstream at
https://support.process-one.net/browse/EJAB-1105
While it will be sensible to incorporate the upstream fix
(which will make the script work in POSIX-compliant shells also),
until bash is required in Debian, this patch is OK.
diff --git a/tools/captcha.sh b/tools/captcha.sh
index 4d40567..d68edfa 100755
--- a/tools/captcha.sh
+++ b/tools/captcha.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
INPUT=$1
ejabberd-http-poll-web-page.patch:
ejabberd_http_poll.erl | 22 +++++++++++++++++++++-
mod_http_bind.erl | 25 ++++++++++++++++---------
2 files changed, 37 insertions(+), 10 deletions(-)
--- NEW FILE ejabberd-http-poll-web-page.patch ---
Generates a human-readable XHTML page which is returned
when a user tries to browse the HTTP-poll URL configured
for the server (a common mistake).
This issue is tracked in EJAB-1106.
This changeset was introduced in revision 2751,
branch http://svn.process-one.net/ejabberd/branches/ejabberd-2.1.x
The first stable version containing the fix is 2.1.1.
--- a/src/web/ejabberd_http_poll.erl (revision 2750)
+++ b/src/web/ejabberd_http_poll.erl (revision 2751)
@@ -154,12 +154,32 @@
end
end;
_ ->
- {200, [?CT, {"Set-Cookie", "ID=-2:0; expires=-1"}], ""}
+ HumanHTMLxmlel = get_human_html_xmlel(),
+ {200, [?CT, {"Set-Cookie", "ID=-2:0; expires=-1"}], HumanHTMLxmlel}
end;
process(_, _Request) ->
{400, [], {xmlelement, "h1", [],
[{xmlcdata, "400 Bad Request"}]}}.
+%% Code copied from mod_http_bind.erl and customized
+get_human_html_xmlel() ->
+ Heading = "ejabberd " ++ atom_to_list(?MODULE),
+ {xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}],
+ [{xmlelement, "head", [],
+ [{xmlelement, "title", [], [{xmlcdata, Heading}]}]},
+ {xmlelement, "body", [],
+ [{xmlelement, "h1", [], [{xmlcdata, Heading}]},
+ {xmlelement, "p", [],
+ [{xmlcdata, "An implementation of "},
+ {xmlelement, "a",
+ [{"href", "http://xmpp.org/extensions/xep-0025.html"}],
+ [{xmlcdata, "Jabber HTTP Polling (XEP-0025)"}]}]},
+ {xmlelement, "p", [],
+ [{xmlcdata, "This web page is only informative. "
+ "To use HTTP-Poll you need a Jabber/XMPP client that supports it."}
+ ]}
+ ]}]}.
+
%%%----------------------------------------------------------------------
%%% Callback functions from gen_fsm
%%%----------------------------------------------------------------------
--- a/src/web/mod_http_bind.erl (revision 2750)
+++ b/src/web/mod_http_bind.erl (revision 2751)
@@ -69,7 +69,14 @@
ejabberd_http_bind:process_request(Data, IP);
process([], #request{method = 'GET',
data = []}) ->
- Heading = "Ejabberd " ++ atom_to_list(?MODULE) ++ " v" ++ ?MOD_HTTP_BIND_VERSION,
+ get_human_html_xmlel();
+process(_Path, _Request) ->
+ ?DEBUG("Bad Request: ~p", [_Request]),
+ {400, [], {xmlelement, "h1", [],
+ [{xmlcdata, "400 Bad Request"}]}}.
+
+get_human_html_xmlel() ->
+ Heading = "ejabberd " ++ atom_to_list(?MODULE) ++ " v" ++ ?MOD_HTTP_BIND_VERSION,
{xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}],
[{xmlelement, "head", [],
[{xmlelement, "title", [], [{xmlcdata, Heading}]}]},
@@ -77,15 +84,15 @@
[{xmlelement, "h1", [], [{xmlcdata, Heading}]},
{xmlelement, "p", [],
[{xmlcdata, "An implementation of "},
- {xmlelement, "a", [{"href", "http://www.xmpp.org/extensions/xep-0206.html"}],
- [{xmlcdata, "XMPP over BOSH (XEP-0206)"}]}]}
- ]}]};
-process(_Path, _Request) ->
- ?DEBUG("Bad Request: ~p", [_Request]),
- {400, [], {xmlelement, "h1", [],
- [{xmlcdata, "400 Bad Request"}]}}.
+ {xmlelement, "a",
+ [{"href", "http://xmpp.org/extensions/xep-0206.html"}],
+ [{xmlcdata, "XMPP over BOSH (XEP-0206)"}]}]},
+ {xmlelement, "p", [],
+ [{xmlcdata, "This web page is only informative. "
+ "To use HTTP-Bind you need a Jabber/XMPP client that supports it."}
+ ]}
+ ]}]}.
-
%%%----------------------------------------------------------------------
%%% BEHAVIOUR CALLBACKS
%%%----------------------------------------------------------------------
ejabberd-mod_admin_extra.patch:
ejabberd.app | 1
mod_admin_extra.erl | 1279 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 1280 insertions(+)
--- NEW FILE ejabberd-mod_admin_extra.patch ---
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:
https://forge.process-one.net/browse/ejabberd-modules/mod_admin_extra
(trunk, revision 976).
diff --git a/src/ejabberd.app b/src/ejabberd.app
index e0e943e..f017015 100644
--- a/src/ejabberd.app
+++ b/src/ejabberd.app
@@ -104,6 +104,7 @@
mod_vcard_ldap,
mod_vcard_odbc,
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..9f3ca14
--- /dev/null
+++ b/src/mod_admin_extra.erl
@@ -0,0 +1,1279 @@
+%%%-------------------------------------------------------------------
+%%% File : mod_admin_extra.erl
+%%% Author : Badlop <badlop at process-one.net>
+%%% Purpose : Contributed administrative functions and commands
+%%% Created : 10 Aug 2008 by Badlop <badlop at 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 at 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,
+ %% Vcard
+ set_nickname/3,
+ get_vcard/3,
+ get_vcard/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_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,
+ %% 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",
+ 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",
+ 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 acount 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 = 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 = 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_vcard2,
+ args = [{user, string}, {host, string}, {name, string}, {subname, string}, {content, string}],
+ result = {res, rescode}},
+
+ #ejabberd_commands{name = add_rosteritem, tags = [roster],
+ desc = "Add an item to a user's roster",
+ 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 at server.com to peter at localhost roster"},
+ #ejabberd_commands{name = delete_rosteritem, tags = [roster],
+ desc = "Delete an item from a user's roster",
+ 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 *@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},
+ {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 = 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 at 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 at 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 = 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.
+
+
+-record(last_activity, {us, timestamp, status}).
+
+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 mnesia:dirty_read(last_activity, {LUser, LServer}) of
+ %% If it is
+ %% existent:
+ [#last_activity{timestamp = TimeStamp}] ->
+ %% 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:
+ [] ->
+ %% 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}.
+
+
+%%
+%% 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])].
+
+%% Make string more print-friendly
+stringize(String) ->
+ %% Replace newline characters with other code
+ element(2, regexp:gsub(String, "\n", "\\n")).
+
+
+%%%
+%%% 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) ->
+ get_vcard_content(User, Host, [Name]).
+
+get_vcard(User, Host, Name, Subname) ->
+ get_vcard_content(User, Host, [Name, Subname]).
+
+set_vcard(User, Host, Name, Content) ->
+ set_vcard_content(User, Host, [Name], Content).
+
+set_vcard(User, Host, Name, Subname, Content) ->
+ set_vcard_content(User, Host, [Name, Subname], Content).
+
+
+%%
+%% Internal vcard
+
+get_vcard_content(User, Server, Data) ->
+ [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}),
+ JID = jlib:make_jid(User, 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
+ false -> "Error: no_value";
+ Elem -> xml:get_tag_cdata(Elem)
+ end;
+ [] ->
+ "Error: no_vcard"
+ end.
+
+get_vcard([Data1, Data2], A1) ->
+ case xml:get_subtag(A1, Data1) of
+ false -> false;
+ A2 -> get_vcard([Data2], A2)
+ end;
+
+get_vcard([Data], A1) ->
+ xml:get_subtag(A1, Data).
+
+set_vcard_content(User, Server, Data, Content) ->
+ [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}),
+ JID = jlib:make_jid(User, 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, Content, A2);
+ [] ->
+ update_vcard_els(Data, Content, [])
+ 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, Content, Els1) ->
+ Els2 = lists:keysort(2, Els1),
+ [Data1 | Data2] = Data,
+ NewEl = case Data2 of
+ [] ->
+ {xmlelement, Data1, [], [{xmlcdata,Content}]};
+ [D2] ->
+ OldEl = case lists:keysearch(Data1, 2, Els2) of
+ {value, A} -> A;
+ false -> {xmlelement, Data1, [], []}
+ end,
+ {xmlelement, _, _, ContentOld1} = OldEl,
+ Content2 = [{xmlelement, D2, [], [{xmlcdata,Content}]}],
+ ContentOld2 = lists:keysort(2, ContentOld1),
+ ContentOld3 = lists:keydelete(D2, 2, ContentOld2),
+ ContentNew = lists:keymerge(2, Content2, ContentOld3),
+ {xmlelement, Data1, [], ContentNew}
+ end,
+ Els3 = lists:keydelete(Data1, 2, Els2),
+ lists:keymerge(2, [NewEl], 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) ->
+ mnesia:transaction(
+ fun() ->
+ mnesia:write({roster,
+ {LU,LS,{User,Server,[]}}, % uj
+ {LU,LS}, % user
+ {User,Server,[]}, % jid
+ Nick, % name: "Mom", []
+ Subscription, % subscription: none, to=you see him, from=he sees you, both
+ none, % ask: out=send request, in=somebody requests you, none
+ [Group], % groups: ["Family"]
+ Xattrs, % xattrs: [{"category","conference"}]
+ [] % xs: []
+ })
+ end).
+
+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) ->
+ mnesia:transaction(
+ fun() ->
+ mnesia:delete({roster, {LU, LS, {User, Server, []}}})
+ end).
+
+
+%% -----------------------------
+%% Get Roster
+%% -----------------------------
+
+get_roster(User, Server) ->
+ {ok, Roster} = get_roster2(User, Server),
+ make_roster_xmlrpc(Roster).
+
+get_roster2(User, Server) ->
+ Modules = gen_mod:loaded_modules(Server),
+ Roster = case lists:member(mod_roster, Modules) of
+ true ->
+ mod_roster:get_user_roster([], {User, Server});
+ false ->
+ case lists:member(mod_roster_odbc, Modules) of
+ true ->
+ mod_roster_odbc:get_user_roster([], {User, Server});
+ false ->
+ {error, "Neither mod_roster or mod_roster_odbc are enabled"}
+ end
+ end,
+ {ok, Roster}.
+
+%% 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,
+ Groups = case Item#roster.groups of
+ [] -> [""];
+ Gs -> Gs
+ end,
+ ItemsX = [{JIDS, Nick, 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 at LS the contact U at 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) ->
+ Item = build_roster_item(U, S, Action),
+ ResIQ = build_iq_roster_push(Item),
+ LJID = jlib:make_jid(LU, LS, R),
+ 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]
+ }
+ ]
+ }.
+
+
+%%%
+%%% Shared Roster Groups
+%%%
+
+srg_create(Group, Host, Name, Description, Display) ->
+ {ok, DisplayList} = regexp:split(Display, "\\\\n"),
+ 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"}],
+ [{xmlelement, "body", [], [{xmlcdata, Body}]}]
+ };
+build_packet(message_headline, [Subject, Body]) ->
+ {xmlelement, "message",
+ [{"type", "headline"}],
+ [{xmlelement, "subject", [], [{xmlcdata, Subject}]},
+ {xmlelement, "body", [], [{xmlcdata, Body}]}
+ ]
+ }.
+
+%%%
+%%% 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 regexp:first_match(String, RegExp) of
+ nomatch ->
+ false;
+ {match, _, _} ->
+ true;
+ {error, ErrDesc} ->
+ io:format(
+ "Wrong regexp ~p in ACL: ~p",
+ [RegExp, lists:flatten(regexp:format_error(ErrDesc))]),
+ false
+ end.
+is_glob_match(String, Glob) ->
+ is_regexp_match(String, regexp:sh_to_awk(Glob)).
ejabberd-piefxis-vhost-export.patch:
ejabberd_piefxis.erl | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
--- NEW FILE ejabberd-piefxis-vhost-export.patch ---
This patch enables generation of the main XML file
when exporting data of a virtual host into PIEFXIS format.
This issue is tracked upstream as EJAB-1098.
This changeset was introduced in revisions 2753,
branch http://svn.process-one.net/ejabberd/branches/ejabberd-2.1.x
The first stable version containing the fix is 2.1.1.
--- a/src/ejabberd_piefxis.erl (revision 2752)
+++ b/src/ejabberd_piefxis.erl (revision 2753)
@@ -212,7 +212,7 @@
El),
ok;
{atomic, exists} ->
- ?INFO_MSG("User ~p@~p already exists, using stored profile...~n",
+ io:format("Account ~s@~s already exists, updating it...~n",
[User, Domain]),
io:format(""),
ok = exmpp_xml:foreach(
@@ -417,10 +417,10 @@
%%%==================================
-%%%% Export server
+%%%% Export hosts
-%% @spec (Dir::string()) -> ok
-export_server(Dir) ->
+%% @spec (Dir::string(), Hosts::[string()]) -> ok
+export_hosts(Dir, Hosts) ->
try_start_exmpp(),
FnT = make_filename_template(),
@@ -430,7 +430,6 @@
print(Fd, make_piefxis_xml_head()),
print(Fd, make_piefxis_server_head()),
- Hosts = ?MYHOSTS,
FilesAndHosts = [{make_host_filename(FnT, Host), Host} || Host <- Hosts],
[print(Fd, make_xinclude(FnH)) || {FnH, _Host} <- FilesAndHosts],
@@ -443,14 +442,20 @@
ok.
%%%==================================
+%%%% Export server
+
+%% @spec (Dir::string()) -> ok
+export_server(Dir) ->
+ Hosts = ?MYHOSTS,
+ export_hosts(Dir, Hosts).
+
+%%%==================================
%%%% Export host
%% @spec (Dir::string(), Host::string()) -> ok
export_host(Dir, Host) ->
- try_start_exmpp(),
- FnT = make_filename_template(),
- FnH = make_host_filename(FnT, Host),
- export_host(Dir, FnH, Host).
+ Hosts = [Host],
+ export_hosts(Dir, Hosts).
%% @spec (Dir::string(), Fn::string(), Host::string()) -> ok
export_host(Dir, FnH, Host) ->
ejabberd-vcard-reqs-forwarding.patch:
ejabberd_c2s.erl | 2 -
ejabberd_sm.erl | 2 -
mod_muc/mod_muc_room.erl | 58 ++++++++++++++++++++++++++++++++++++++++++-----
3 files changed, 54 insertions(+), 8 deletions(-)
--- NEW FILE ejabberd-vcard-reqs-forwarding.patch ---
This bug fixes a long-standing bug with ejabberd violating
RFC 3920 by intercepting vCard request coming to a user's
full JID, which should be forwarded to the user's client instead.
This behaviour is especially noticeable in MUC rooms.
This issue is tracked upstream as EJAB-1045.
This changeset was introduced in revisions 2766-2768
branch http://svn.process-one.net/ejabberd/branches/ejabberd-2.1.x
The first stable version containing the fix is 2.1.1.
--- a/src/ejabberd_sm.erl (revision 2762)
+++ b/src/ejabberd_sm.erl (revision 2768)
@@ -481,7 +481,7 @@
_ ->
Err =
jlib:make_error_reply(
- Packet, ?ERR_RECIPIENT_UNAVAILABLE),
+ Packet, ?ERR_SERVICE_UNAVAILABLE),
ejabberd_router:route(To, From, Err)
end;
_ ->
--- a/src/mod_muc/mod_muc_room.erl (revision 2762)
+++ b/src/mod_muc/mod_muc_room.erl (revision 2768)
@@ -470,9 +470,10 @@
{xmlelement, "iq", Attrs, _Els} = Packet},
StateData) ->
Lang = xml:get_attr_s("xml:lang", Attrs),
+ StanzaId = xml:get_attr_s("id", Attrs),
case {(StateData#state.config)#config.allow_query_users,
- is_user_online(From, StateData)} of
- {true, true} ->
+ is_user_online_iq(StanzaId, From, StateData)} of
+ {true, {true, NewId, FromFull}} ->
case find_jid_by_nick(ToNick, StateData) of
false ->
case jlib:iq_query_info(Packet) of
@@ -489,13 +490,15 @@
end;
ToJID ->
{ok, #user{nick = FromNick}} =
- ?DICT:find(jlib:jid_tolower(From),
+ ?DICT:find(jlib:jid_tolower(FromFull),
StateData#state.users),
+ {ToJID2, Packet2} = handle_iq_vcard(FromFull, ToJID,
+ StanzaId, NewId,Packet),
ejabberd_router:route(
jlib:jid_replace_resource(StateData#state.jid, FromNick),
- ToJID, Packet)
+ ToJID2, Packet2)
end;
- {_, false} ->
+ {_, {false, _, _}} ->
case jlib:iq_query_info(Packet) of
reply ->
ok;
@@ -829,7 +832,6 @@
{next_state, normal_state, StateData}
end.
-
%% @doc Check if this non participant can send message to room.
%%
%% XEP-0045 v1.23:
@@ -969,6 +971,50 @@
LJID = jlib:jid_tolower(JID),
?DICT:is_key(LJID, StateData#state.users).
+
+%%%
+%%% Handle IQ queries of vCard
+%%%
+is_user_online_iq(StanzaId, JID, StateData) when JID#jid.lresource /= "" ->
+ {is_user_online(JID, StateData), StanzaId, JID};
+is_user_online_iq(StanzaId, JID, StateData) when JID#jid.lresource == "" ->
+ try stanzaid_unpack(StanzaId) of
+ {OriginalId, Resource} ->
+ JIDWithResource = jlib:jid_replace_resource(JID, Resource),
+ {is_user_online(JIDWithResource, StateData),
+ OriginalId, JIDWithResource}
+ catch
+ _:_ ->
+ {is_user_online(JID, StateData), StanzaId, JID}
+ end.
+
+handle_iq_vcard(FromFull, ToJID, StanzaId, NewId, Packet) ->
+ ToBareJID = jlib:jid_remove_resource(ToJID),
+ IQ = jlib:iq_query_info(Packet),
+ handle_iq_vcard2(FromFull, ToJID, ToBareJID, StanzaId, NewId, IQ, Packet).
+handle_iq_vcard2(_FromFull, ToJID, ToBareJID, StanzaId, _NewId,
+ #iq{type = get, xmlns = ?NS_VCARD}, Packet)
+ when ToBareJID /= ToJID ->
+ {ToBareJID, change_stanzaid(StanzaId, ToJID, Packet)};
+handle_iq_vcard2(_FromFull, ToJID, _ToBareJID, _StanzaId, NewId, _IQ, Packet) ->
+ {ToJID, change_stanzaid(NewId, Packet)}.
+
+stanzaid_pack(OriginalId, Resource) ->
+ "berd"++base64:encode_to_string("ejab\0" ++ OriginalId ++ "\0" ++ Resource).
+stanzaid_unpack("berd"++StanzaIdBase64) ->
+ StanzaId = base64:decode_to_string(StanzaIdBase64),
+ ["ejab", OriginalId, Resource] = string:tokens(StanzaId, "\0"),
+ {OriginalId, Resource}.
+
+change_stanzaid(NewId, Packet) ->
+ {xmlelement, Name, Attrs, Els} = jlib:remove_attr("id", Packet),
+ {xmlelement, Name, [{"id", NewId} | Attrs], Els}.
+change_stanzaid(PreviousId, ToJID, Packet) ->
+ NewId = stanzaid_pack(PreviousId, ToJID#jid.lresource),
+ change_stanzaid(NewId, Packet).
+%%%
+%%%
+
role_to_list(Role) ->
case Role of
moderator -> "moderator";
--- a/src/ejabberd_c2s.erl (revision 2762)
+++ b/src/ejabberd_c2s.erl (revision 2768)
@@ -1220,7 +1220,7 @@
"iq" ->
IQ = jlib:iq_query_info(Packet),
case IQ of
- #iq{xmlns = ?NS_VCARD} ->
+ #iq{xmlns = ?NS_VCARD} when (To#jid.luser == "") or (To#jid.lresource == "") ->
Host = StateData#state.server,
case ets:lookup(sm_iqtable, {?NS_VCARD, Host}) of
[{_, Module, Function, Opts}] ->
ejabberd-ejabberdctl_fix.diff:
ejabberdctl.template | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
Index: ejabberd-ejabberdctl_fix.diff
===================================================================
RCS file: /cvs/pkgs/rpms/ejabberd/F-11/ejabberd-ejabberdctl_fix.diff,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -p -r1.7 -r1.8
--- ejabberd-ejabberdctl_fix.diff 21 Nov 2009 08:04:47 -0000 1.7
+++ ejabberd-ejabberdctl_fix.diff 10 Dec 2009 19:11:11 -0000 1.8
@@ -1,5 +1,5 @@
---- src/ejabberdctl.template.fix_ctl 2009-11-06 22:53:19.000000000 +0300
-+++ src/ejabberdctl.template 2009-11-21 10:43:17.654686409 +0300
+--- src/ejabberdctl.template 2009-11-06 22:53:19.000000000 +0300
++++ src/ejabberdctl.template 2009-12-10 21:07:28.648659178 +0300
@@ -9,10 +9,10 @@
# define default environment variables
@@ -13,6 +13,15 @@
# parse command line parameters
ARGS=
+@@ -46,7 +46,7 @@
+ 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@
@@ -60,14 +60,14 @@
EJID=`id -g $INSTALLUSER`
EXEC_CMD="false"
Index: ejabberd.spec
===================================================================
RCS file: /cvs/pkgs/rpms/ejabberd/F-11/ejabberd.spec,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -p -r1.41 -r1.42
--- ejabberd.spec 21 Nov 2009 08:04:47 -0000 1.41
+++ ejabberd.spec 10 Dec 2009 19:11:12 -0000 1.42
@@ -12,7 +12,7 @@
Name: ejabberd
Version: 2.1.0
-Release: 1%{?dist}
+Release: 2%{?dist}
Summary: A distributed, fault-tolerant Jabber/XMPP server
Group: Applications/Internet
@@ -24,7 +24,7 @@ Source2: ejabberd.logrotate
Source3: ejabberd.sysconfig
# http://www.ejabberd.im/mod_ctlextra
-# this module will be removed in the near future in favor of mod_admin_extra
+# this module will be removed in the nearest future in favor of mod_admin_extra
# svn export -r 1020 https://svn.process-one.net/ejabberd-modules/mod_ctlextra/trunk/src/mod_ctlextra.erl
Source4: mod_ctlextra.erl
@@ -47,7 +47,23 @@ Patch3: ejabberd-ejabberd_cfg_pam_name.d
Patch5: ejabberd-mod_ctlextra_mentioning_in_ejabberd_app.diff
# fixed delays in s2s connections
Patch8: ejabberd-fixed_delays_in_s2s.patch
-
+# captcha.sh uses some BASH-specific variables
+# see https://support.process-one.net/browse/EJAB-1105
+Patch9: ejabberd-captcha-bashism.patch
+# Introducing mod_admin_extra
+Patch10: ejabberd-mod_admin_extra.patch
+# Fixed long-standing bug with RFC 3920 violation
+# see https://support.process-one.net/browse/EJAB-1045
+Patch11: ejabberd-vcard-reqs-forwarding.patch
+# Generates a human-readable XHTML page which is returned
+# when a user tries to browse the HTTP-poll URL configured
+# for the server (a common mistake).
+# see https://support.process-one.net/browse/EJAB-1106
+Patch12: ejabberd-http-poll-web-page.patch
+# This patch enables generation of the main XML file
+# when exporting data of a virtual host into PIEFXIS format.
+# see https://support.process-one.net/browse/EJAB-1098
+Patch13: ejabberd-piefxis-vhost-export.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
@@ -93,6 +109,33 @@ Documentation for ejabberd.
%{__fe_groupadd} %{uid} -r %{name} &>/dev/null || :
%{__fe_useradd} %{uid} -r -s /sbin/nologin -d /var/lib/ejabberd -M \
-c 'ejabberd' -g %{name} %{name} &>/dev/null || :
+# we should backup DB in every upgrade
+if ejabberdctl status >/dev/null ; then
+ # Use timestamp to make database restoring easier
+ TIME=$(date +%Y-%m-%dT%H:%M:%S)
+ BACKUPDIR=$(mktemp -d -p /var/tmp/ ejabberd-$TIME.XXXXXX)
+ chown ejabberd:ejabberd $BACKUPDIR
+ BACKUP=$BACKUPDIR/ejabberd-database
+ ejabberdctl backup $BACKUP
+ # Change ownership to root:root because ejabberd user might be
+ # removed on package removal.
+ chown -R root:root $BACKUPDIR
+ chmod 700 $BACKUPDIR
+ echo
+ echo The ejabberd database has been backed up to $BACKUP.
+ echo
+fi
+
+# 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 -pf /var/lib/ejabberd/{,spool/}.erlang.cookie
+ echo
+ echo The ejabberd cookie file was moved.
+ echo Please remove old one from /var/lib/ejabberd/.erlang.cookie
+ echo
+fi
+
%post
/sbin/chkconfig --add %{name}
@@ -134,6 +177,11 @@ fi
%patch3 -p0 -b .pam_name
%patch5 -p0 -b .mod_ctlextra
%patch8 -p0 -b .s2s
+%patch9 -p1 -b .bashism
+%patch10 -p1 -b .mod_admin_extra
+%patch11 -p1 -b .vcard_rfc_violation
+%patch12 -p1 -b .xhtml
+%patch13 -p1 -b .piefxis
dos2unix src/odbc/mssql2000.sql
@@ -169,6 +217,9 @@ chmod a+x %{buildroot}%{_libdir}/%{name}
# 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
+# 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
@@ -194,12 +245,9 @@ install -p -m 0644 src/odbc/mssql2000.sq
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}
-# install example script for CAPTCHA-protection
-install -p -m 0644 tools/captcha.sh %{buildroot}%{_datadir}/%{name}
# removed files, which would be packaged later (see 'files' section)
rm -rf %{buildroot}%{_docdir}/%{name}
-rm -f %{buildroot}%{_libdir}/%{name}/priv/bin/captcha.sh
%clean
rm -rf %{buildroot}
@@ -253,6 +301,7 @@ rm -rf %{buildroot}
%{_libdir}/%{name}/include/mod_roster.hrl
%{_libdir}/%{name}/include/web/ejabberd_http.hrl
%{_libdir}/%{name}/include/web/ejabberd_web_admin.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
@@ -262,7 +311,6 @@ rm -rf %{buildroot}
%{_libdir}/%{name}/priv/msgs/*.msg
%dir %{_datadir}/%{name}
-%{_datadir}/%{name}/captcha.sh
%{_datadir}/%{name}/mssql2000.sql
%{_datadir}/%{name}/mssql2005.sql
%{_datadir}/%{name}/mysql.sql
@@ -303,6 +351,11 @@ rm -rf %{buildroot}
%doc doc/yozhikheader.png
%changelog
+* Thu Dec 10 2009 Peter Lemenkov <lemenkov at gmail.com> 2.1.0-2
+- DB backups are made on every upgrade/uninstall
+- Fixed installation of captcha.sh example helper
+- Added patches 9,10,11,12,13 from Debian's package
+
* Fri Nov 20 2009 Peter Lemenkov <lemenkov at gmail.com> 2.1.0-1
- Ver. 2.1.0
- Upstream no longer providing ChangeLog
Index: import.log
===================================================================
RCS file: /cvs/pkgs/rpms/ejabberd/F-11/import.log,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -p -r1.14 -r1.15
--- import.log 21 Nov 2009 08:04:47 -0000 1.14
+++ import.log 10 Dec 2009 19:11:12 -0000 1.15
@@ -12,3 +12,4 @@ ejabberd-2_0_5-3_fc10:F-11:ejabberd-2.0.
ejabberd-2_0_5-6_fc11:F-11:ejabberd-2.0.5-6.fc11.src.rpm:1251229070
ejabberd-2_0_5-8_fc11:F-11:ejabberd-2.0.5-8.fc11.src.rpm:1252493180
ejabberd-2_1_0-1_fc12:F-11:ejabberd-2.1.0-1.fc12.src.rpm:1258790645
+ejabberd-2_1_0-2_fc12:F-11:ejabberd-2.1.0-2.fc12.src.rpm:1260472235
- Previous message: rpms/ejabberd/F-12 ejabberd-captcha-bashism.patch, NONE, 1.1 ejabberd-http-poll-web-page.patch, NONE, 1.1 ejabberd-mod_admin_extra.patch, NONE, 1.1 ejabberd-piefxis-vhost-export.patch, NONE, 1.1 ejabberd-vcard-reqs-forwarding.patch, NONE, 1.1 ejabberd-ejabberdctl_fix.diff, 1.7, 1.8 ejabberd.spec, 1.47, 1.48 import.log, 1.15, 1.16
- Next message: rpms/automake/devel automake.spec,1.47,1.48
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the scm-commits
mailing list