Merge from trunk (r1709 to r1730).

Ejabberd should be usable again.

PR:		EJABP-1

SVN Revision: 1731
This commit is contained in:
Jean-Sébastien Pédron 2008-12-16 13:16:56 +00:00
parent 62f9f6e6c5
commit 6a3436b1c4
4 changed files with 106 additions and 85 deletions

View File

@ -1,3 +1,9 @@
2008-12-16 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
Merge from trunk (r1709 to r1730).
Ejabberd should be usable again.
2008-12-16 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
* src/mod_pubsub/mod_pubsub.erl: Convert to exmpp the parts recently
@ -9,6 +15,10 @@
* src/mod_pubsub/mod_pubsub.erl: Fix get_item_name deadlock on
transaction
2008-12-12 Alexey Shchepin <alexey@process-one.net>
* src/ejabberd_c2s.erl: Bugfix in "from" attribute checking
2008-12-10 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
* src/eldap/eldap_utils.erl (case_insensitive_match/2): Replace
@ -18,9 +28,46 @@
* src/mod_pubsub: Merge from latest trunk (r1716).
2008-12-09 Christophe Romain <christophe.romain@process-one.net>
* src/mod_pubsub/mod_pubsub.erl: prevent publish items with invalid
XML schema bugfix (EJAB-699) (previous commit was uncomplete)
and fix bug injected in previous commit
2008-12-08 Christophe Romain <christophe.romain@process-one.net>
* src/ejabberd_c2s.erl: Reduce memory consumption due to caps handling
* src/mod_pubsub/mod_pubsub.erl: Likewise
* src/mod_caps.erl: Likewise
* src/mod_pubsub/mod_pubsub.erl: ignore unknown configuration fields
(EJAB-762) (thanks to Jack Moffitt)
* src/mod_pubsub/mod_pubsub.erl: fix node authorization bug (EJAB-798)
send authorization update event (EJAB-799) (thanks to Brian Cully)
* src/mod_pubsub/mod_pubsub.erl: add nodetree filtering and
authorization (EJAB-813) (thanks to Brian Cully)
* src/mod_pubsub/nodetree_default.erl: Likewise
* src/mod_pubsub/nodetree_virtual.erl: Likewise
* src/mod_pubsub/gen_pubsub_nodetree.erl: Likewise
* src/mod_pubsub/mod_pubsub.erl: prevent publish items with invalid
XML schema (EJAB-699)
* src/mod_pubsub/pubsub.hrl: remove unused pubsub_presence record
* src/mod_pubsub/node_flat.erl: renamed from node_zoo
* src/mod_pubsub/mod_pubsub.erl: reply to suscriptions options queries
with unsupported feature error (EJAB-713)
* src/mod_pubsub/node_default.erl: remove pubsub_state record when
unsubscribing node without affiliation (EJAB-776)
2008-12-08 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
* src/mod_pubsub: Merge from trunk (r1692 to r1709).
Merge from trunk (r1692 to r1709).
2008-12-08 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>

View File

@ -37,8 +37,7 @@
send_element/2,
socket_type/0,
get_presence/1,
get_subscribed/1,
get_subscribed_and_online/1]).
get_subscribed/1]).
%% gen_fsm callbacks
-export([init/1,
@ -85,7 +84,6 @@
pres_f = ?SETS:new(),
pres_a = ?SETS:new(),
pres_i = ?SETS:new(),
pres_available = ?DICT:new(),
pres_last, pres_pri,
pres_timestamp,
pres_invis = false,
@ -205,14 +203,8 @@ init([{SockMod, Socket}, Opts]) ->
end.
%% Return list of all available resources of contacts,
%% in form [{JID, Caps}].
get_subscribed(FsmRef) ->
gen_fsm:sync_send_all_state_event(
FsmRef, get_subscribed, 1000).
get_subscribed_and_online(FsmRef) ->
gen_fsm:sync_send_all_state_event(
FsmRef, get_subscribed_and_online, 1000).
gen_fsm:sync_send_all_state_event(FsmRef, get_subscribed, 1000).
%%----------------------------------------------------------------------
%% Func: StateName/2
@ -951,29 +943,8 @@ handle_sync_event({get_presence}, _From, StateName, StateData) ->
fsm_reply(Reply, StateName, StateData);
handle_sync_event(get_subscribed, _From, StateName, StateData) ->
Subscribed = StateData#state.pres_f,
Online = StateData#state.pres_available,
Pred = fun({U, S, _} = User, _Caps) ->
?SETS:is_element({U, S, undefined},
Subscribed) orelse
?SETS:is_element(User, Subscribed)
end,
SubscribedAndOnline = ?DICT:filter(Pred, Online),
SubscribedWithCaps = ?SETS:fold(fun(User, Acc) ->
[{User, undefined}|Acc]
end, ?DICT:to_list(SubscribedAndOnline), Subscribed),
{reply, SubscribedWithCaps, StateName, StateData};
handle_sync_event(get_subscribed_and_online, _From, StateName, StateData) ->
Subscribed = StateData#state.pres_f,
Online = StateData#state.pres_available,
Pred = fun({U, S, _R} = User, _Caps) ->
?SETS:is_element({U, S, undefined},
Subscribed) orelse
?SETS:is_element(User, Subscribed)
end,
SubscribedAndOnline = ?DICT:filter(Pred, Online),
{reply, ?DICT:to_list(SubscribedAndOnline), StateName, StateData};
Subscribed = ?SETS:to_list(StateData#state.pres_f),
{reply, Subscribed, StateName, StateData};
handle_sync_event(_Event, _From, StateName, StateData) ->
Reply = ok,
@ -1065,42 +1036,39 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
LFrom = jlib:short_prepd_jid(From),
LBFrom = jlib:short_prepd_bare_jid(From),
%% Note contact availability
Els = Packet#xmlel.children,
Caps = mod_caps:read_caps(Els),
mod_caps:note_caps(StateData#state.server, From, Caps),
NewAvailable = case exmpp_presence:get_type(Packet) of
'unavailable' ->
?DICT:erase(LFrom, StateData#state.pres_available);
_ ->
?DICT:store(LFrom, Caps, StateData#state.pres_available)
end,
NewStateData = StateData#state{pres_available = NewAvailable},
case exmpp_presence:get_type(Packet) of
'unavailable' ->
mod_caps:clear_caps(From);
_ ->
Caps = mod_caps:read_caps(Packet#xmlel.children),
mod_caps:note_caps(StateData#state.server, From, Caps)
end,
case ?SETS:is_element(
LFrom, NewStateData#state.pres_a) orelse
LFrom, StateData#state.pres_a) orelse
?SETS:is_element(
LBFrom, NewStateData#state.pres_a) of
LBFrom, StateData#state.pres_a) of
true ->
{true, Attrs, NewStateData};
{true, Attrs, StateData};
false ->
case ?SETS:is_element(
LFrom, NewStateData#state.pres_f) of
LFrom, StateData#state.pres_f) of
true ->
A = ?SETS:add_element(
LFrom,
NewStateData#state.pres_a),
StateData#state.pres_a),
{true, Attrs,
NewStateData#state{pres_a = A}};
StateData#state{pres_a = A}};
false ->
case ?SETS:is_element(
LBFrom, NewStateData#state.pres_f) of
LBFrom, StateData#state.pres_f) of
true ->
A = ?SETS:add_element(
LBFrom,
NewStateData#state.pres_a),
StateData#state.pres_a),
{true, Attrs,
NewStateData#state{pres_a = A}};
StateData#state{pres_a = A}};
false ->
{true, Attrs, NewStateData}
{true, Attrs, StateData}
end
end
end;
@ -1907,28 +1875,15 @@ is_ip_blacklisted({IP,_Port}) ->
check_from(El, FromJID) ->
case exmpp_stanza:get_sender(El) of
undefined ->
exmpp_stanza:set_sender(El, FromJID);
JIDElString ->
El;
SJID ->
try
JIDEl = exmpp_jid:list_to_jid(JIDElString),
case JIDEl#jid.lresource of
undefined ->
%% Matching JID: The stanza is ok
if JIDEl#jid.lnode == FromJID#jid.lnode andalso
JIDEl#jid.ldomain == FromJID#jid.ldomain ->
El;
true ->
'invalid-from'
end;
_ ->
%% Matching JID: The stanza is ok
if JIDEl#jid.lnode == FromJID#jid.lnode andalso
JIDEl#jid.ldomain == FromJID#jid.ldomain andalso
JIDEl#jid.lresource == FromJID#jid.lresource ->
El;
true ->
'invalid-from'
end
JID = exmpp_jid:list_to_jid(SJID),
case exmpp_jid:compare_jids(JID, FromJID) of
true ->
El;
false ->
'invalid-from'
end
catch
_:_ ->

View File

@ -31,7 +31,9 @@
-behaviour(gen_mod).
-export([read_caps/1,
get_caps/1,
note_caps/3,
clear_caps/1,
get_features/2,
handle_disco_response/3]).
@ -58,6 +60,7 @@
-record(caps, {node, version, exts}).
-record(caps_features, {node_pair, features}).
-record(user_caps, {jid, caps}).
-record(state, {host,
disco_requests = ?DICT:new(),
feature_queries = []}).
@ -80,12 +83,26 @@ read_caps([_ | Tail], Result) ->
read_caps([], Result) ->
Result.
%% get_caps reads user caps from database
get_caps(JID) ->
case catch mnesia:dirty_read({user_caps, list_to_binary(exmpp_jid:jid_to_list(JID))}) of
[#user_caps{caps=Caps}] ->
Caps;
_ ->
nothing
end.
%% clear_caps removes user caps from database
clear_caps(JID) ->
catch mnesia:dirty_delete({user_caps, list_to_binary(exmpp_jid:jid_to_list(JID))}).
%% note_caps should be called to make the module request disco
%% information. Host is the host that asks, From is the full JID that
%% sent the caps packet, and Caps is what read_caps returned.
note_caps(Host, From, Caps) ->
case Caps of
nothing -> ok;
nothing ->
ok;
_ ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
gen_server:cast(Proc, {note_caps, From, Caps})
@ -129,7 +146,9 @@ init([Host, _Opts]) ->
mnesia:create_table(caps_features,
[{ram_copies, [node()]},
{attributes, record_info(fields, caps_features)}]),
mnesia:add_table_copy(caps_features, node(), ram_copies),
mnesia:create_table(user_caps,
[{disc_copies, [node()]},
{attributes, record_info(fields, user_caps)}]),
{ok, #state{host = Host}}.
maybe_get_features(#caps{node = Node, version = Version, exts = Exts}) ->
@ -177,10 +196,12 @@ handle_call(stop, _From, State) ->
{stop, normal, ok, State}.
handle_cast({note_caps, From,
#caps{node = Node, version = Version, exts = Exts}},
#caps{node = Node, version = Version, exts = Exts} = Caps},
#state{host = Host, disco_requests = Requests} = State) ->
%% XXX: this leads to race conditions where ejabberd will send
%% lots of caps disco requests.
mnesia:dirty_write(#user_caps{jid = list_to_binary(exmpp_jid:jid_to_list(From)),
caps = Caps}),
SubNodes = [Version | Exts],
%% Now, find which of these are not already in the database.
Fun = fun() ->
@ -195,11 +216,9 @@ handle_cast({note_caps, From,
end,
case mnesia:transaction(Fun) of
{atomic, Missing} ->
%% For each unknown caps "subnode", we send a disco
%% request.
NewRequests =
lists:foldl(
fun(SubNode, Dict) ->
%% For each unknown caps "subnode", we send a disco request.
NewRequests = lists:foldl(
fun(SubNode, Dict) ->
ID = randoms:get_string(),
Query = exmpp_xml:set_attribute(
#xmlel{ns = ?NS_DISCO_INFO, name = 'query'},

View File

@ -480,9 +480,9 @@ handle_cast({presence, JID, Pid}, State) ->
case catch ejabberd_c2s:get_subscribed(Pid) of
Contacts when is_list(Contacts) ->
lists:foreach(
fun({{User, Server, _}, _}) ->
fun({User, Server, _}) ->
Owner = {User, Server, undefined},
lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options} = PN) ->
lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) ->
case get_option(Options, send_last_published_item) of
on_sub_and_presence ->
case is_caps_notify(ServerHost, Node, LJID) of