mirror of
https://github.com/processone/ejabberd.git
synced 2024-10-05 14:51:05 +02:00
Merge branch '2.2.x' of gitorious.process-one.net:+ejabberd-developers/ejabberd/maincustomers into 2.2.x
This commit is contained in:
commit
c77e7fbb7d
@ -1192,6 +1192,12 @@ handle_event({del_rosteritem, IJID}, StateName, StateData) ->
|
||||
NewStateData = roster_change(IJID, none, StateData),
|
||||
fsm_next_state(StateName, NewStateData);
|
||||
|
||||
handle_event({xmlstreamcdata, _}, StateName, StateData) ->
|
||||
?DEBUG("cdata ping", []),
|
||||
NSD1 = change_reception(StateData, true),
|
||||
NSD2 = start_keepalive_timer(NSD1),
|
||||
fsm_next_state(StateName, NSD2);
|
||||
|
||||
handle_event(_Event, StateName, StateData) ->
|
||||
fsm_next_state(StateName, StateData).
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
-define(MODS, []).
|
@ -17,7 +17,10 @@
|
||||
push_notification/8,
|
||||
enable_offline_notification/5,
|
||||
disable_notification/3,
|
||||
receive_offline_packet/3]).
|
||||
receive_offline_packet/3,
|
||||
resend_badge/1,
|
||||
multi_resend_badge/1,
|
||||
offline_resend_badge/0]).
|
||||
|
||||
%% Debug commands
|
||||
-export([get_token_by_jid/1]).
|
||||
@ -232,6 +235,50 @@ receive_offline_packet(From, To, Packet) ->
|
||||
ok
|
||||
end.
|
||||
|
||||
resend_badge(To) ->
|
||||
Host = To#jid.lserver,
|
||||
case gen_mod:is_loaded(Host, mod_applepush) of
|
||||
true ->
|
||||
case lookup_cache(To) of
|
||||
false ->
|
||||
{error, "no cached data for the user"};
|
||||
{ID, AppID, SendBody, SendFrom} ->
|
||||
?DEBUG("lookup: ~p~n", [{ID, AppID, SendBody, SendFrom}]),
|
||||
PushService = get_push_service(Host, To, AppID),
|
||||
ServiceJID = jlib:make_jid("", PushService, ""),
|
||||
Offline = ejabberd_hooks:run_fold(
|
||||
count_offline_messages,
|
||||
Host,
|
||||
0,
|
||||
[To#jid.luser, Host]),
|
||||
if
|
||||
Offline == 0 ->
|
||||
ok;
|
||||
true ->
|
||||
Badge = integer_to_list(Offline),
|
||||
DeviceID = erlang:integer_to_list(ID, 16),
|
||||
Packet1 =
|
||||
{xmlelement, "message", [],
|
||||
[{xmlelement, "push", [{"xmlns", ?NS_P1_PUSH}],
|
||||
[{xmlelement, "id", [],
|
||||
[{xmlcdata, DeviceID}]},
|
||||
{xmlelement, "badge", [],
|
||||
[{xmlcdata, Badge}]}]}]},
|
||||
ejabberd_router:route(To, ServiceJID, Packet1)
|
||||
end
|
||||
end;
|
||||
false ->
|
||||
{error, "mod_applepush is not loaded"}
|
||||
end.
|
||||
|
||||
multi_resend_badge(JIDs) ->
|
||||
lists:foreach(fun resend_badge/1, JIDs).
|
||||
|
||||
offline_resend_badge() ->
|
||||
USs = mnesia:dirty_all_keys(applepush_cache),
|
||||
JIDs = lists:map(fun({U, S}) -> jlib:make_jid(U, S, "") end, USs),
|
||||
multi_resend_badge(JIDs).
|
||||
|
||||
lookup_cache(JID) ->
|
||||
#jid{luser = LUser, lserver = LServer} = JID,
|
||||
LUS = {LUser, LServer},
|
||||
|
@ -198,14 +198,16 @@ handle_info({ssl, Socket, Packet}, State)
|
||||
<<8, Status, CmdID:32>> when Status /= 0 ->
|
||||
case dict:find(CmdID, State#state.cmd_cache) of
|
||||
{ok, {JID, _DeviceID}} ->
|
||||
From = jlib:make_jid("", State#state.host, ""),
|
||||
ejabberd_router:route(
|
||||
From, JID,
|
||||
{xmlelement, "message", [],
|
||||
[{xmlelement, "disable",
|
||||
[{"xmlns", ?NS_P1_PUSH},
|
||||
{"status", integer_to_list(Status)}],
|
||||
[]}]});
|
||||
?ERROR_MSG("PUSH ERROR for ~p: ~p", [JID, Status]),
|
||||
%From = jlib:make_jid("", State#state.host, ""),
|
||||
%ejabberd_router:route(
|
||||
% From, JID,
|
||||
% {xmlelement, "message", [],
|
||||
% [{xmlelement, "disable",
|
||||
% [{"xmlns", ?NS_P1_PUSH},
|
||||
% {"status", integer_to_list(Status)}],
|
||||
% []}]});
|
||||
ok;
|
||||
error ->
|
||||
?ERROR_MSG("Unknown cmd ID ~p~n", [CmdID]),
|
||||
ok
|
||||
@ -408,8 +410,13 @@ make_payload(State, Msg, Badge, Sound, Sender) ->
|
||||
Payloads = lists:filter(fun(S) -> S /= "" end,
|
||||
[AlertPayload, BadgePayload, SoundPayload]),
|
||||
Payload =
|
||||
"{\"aps\":{" ++ join(Payloads, ",") ++ "},"
|
||||
"\"from\":\"" ++ json_escape(Sender) ++ "\"}",
|
||||
case Sender of
|
||||
"" ->
|
||||
"{\"aps\":{" ++ join(Payloads, ",") ++ "}}";
|
||||
_ ->
|
||||
"{\"aps\":{" ++ join(Payloads, ",") ++ "},"
|
||||
"\"from\":\"" ++ json_escape(Sender) ++ "\"}"
|
||||
end,
|
||||
PayloadLen = length(Payload),
|
||||
if
|
||||
PayloadLen > ?MAX_PAYLOAD_SIZE ->
|
||||
|
@ -1,71 +0,0 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : mod_keepalive.erl
|
||||
%%% Author : Christophe romain <cromain@process-one.net>
|
||||
%%% Purpose : Hidden code autoload
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-module(mod_keepalive).
|
||||
-author('cromain@process-one.net').
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-export([start/2, stop/1, init/1]).
|
||||
|
||||
-include("keepalive.hrl").
|
||||
|
||||
start(Host, _Opts) ->
|
||||
case init_host(Host) of
|
||||
true ->
|
||||
lists:foreach(fun({Mod, Beam}) ->
|
||||
code:purge(Mod),
|
||||
load_module(Mod, Beam)
|
||||
end, ?MODS);
|
||||
false ->
|
||||
ok
|
||||
end.
|
||||
|
||||
stop(_Host) ->
|
||||
ok.
|
||||
|
||||
init(["pack"|Mods]) ->
|
||||
Code = lists:foldl(fun(Mod, Acc) ->
|
||||
case file:read_file(Mod++".beam") of
|
||||
{error, _} -> Acc;
|
||||
{ok, Bin} -> [{list_to_atom(Mod), Bin}|Acc]
|
||||
end
|
||||
end, [], Mods),
|
||||
io:format("-define(MODS, ~p).", [Code]);
|
||||
init(_) ->
|
||||
error.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% Internal module protection
|
||||
|
||||
-define(VALID_HOSTS, []). % default is unlimited use
|
||||
-define(MAX_USERS, 0). % default is unlimited use
|
||||
|
||||
init_host(VHost) ->
|
||||
case ?VALID_HOSTS of
|
||||
[] -> % unlimited use
|
||||
true;
|
||||
ValidList -> % limited use
|
||||
init_host(VHost, ValidList)
|
||||
end.
|
||||
init_host([], _) ->
|
||||
false;
|
||||
init_host(VHost, ValidEncryptedList) ->
|
||||
EncryptedHost = erlang:md5(lists:reverse(VHost)),
|
||||
case lists:member(EncryptedHost, ValidEncryptedList) of
|
||||
true ->
|
||||
case ?MAX_USERS of
|
||||
0 -> true;
|
||||
N -> ejabberd_auth:get_vh_registered_users_number(VHost) =< N
|
||||
end;
|
||||
false ->
|
||||
case string:chr(VHost, $.) of
|
||||
0 -> false;
|
||||
Pos -> init_host(string:substr(VHost, Pos+1), ValidEncryptedList)
|
||||
end
|
||||
end.
|
41
src/mod_pubsub/pubsub_clean.erl
Normal file
41
src/mod_pubsub/pubsub_clean.erl
Normal file
@ -0,0 +1,41 @@
|
||||
-module(pubsub_clean).
|
||||
|
||||
-define(TIMEOUT, 1000*600). % 1 minute
|
||||
|
||||
-export([start/0, loop/0, subscribed/1, offline/1]).
|
||||
|
||||
start() ->
|
||||
Pid = spawn(?MODULE, loop, []),
|
||||
register(pubsub_clean, Pid),
|
||||
Pid.
|
||||
|
||||
loop() ->
|
||||
receive
|
||||
purge -> purge()
|
||||
after ?TIMEOUT -> purge()
|
||||
end,
|
||||
loop().
|
||||
|
||||
purge() ->
|
||||
{Sessions, Subscriptions} = {mnesia:table_info(session,size),mnesia:table_info(pubsub_state,size)},
|
||||
if Subscriptions > Sessions + 500 ->
|
||||
lists:foreach(fun(K) ->
|
||||
[N]=mnesia:dirty_read({pubsub_node, K}),
|
||||
I=element(3,N),
|
||||
lists:foreach(fun(JID) ->
|
||||
mnesia:dirty_delete({pubsub_state, {JID, I}})
|
||||
end, offline(subscribed(I)))
|
||||
end, mnesia:dirty_all_keys(pubsub_node));
|
||||
true ->
|
||||
ok
|
||||
end.
|
||||
|
||||
subscribed(NodeId) ->
|
||||
lists:map(fun(S) ->
|
||||
element(1,element(2,S))
|
||||
end, mnesia:dirty_match_object({pubsub_state, {'_',NodeId},'_',none,subscribed})).
|
||||
|
||||
offline(Jids) ->
|
||||
lists:filter(fun({U,S,""}) -> ejabberd_sm:get_user_resources(U,S) == [];
|
||||
({U,S,R}) -> not lists:member(R,ejabberd_sm:get_user_resources(U,S))
|
||||
end, Jids).
|
112
src/mod_pubsub/pubsub_debug.erl
Normal file
112
src/mod_pubsub/pubsub_debug.erl
Normal file
@ -0,0 +1,112 @@
|
||||
-module(pubsub_debug).
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
nodeid(Host, Node) ->
|
||||
case mnesia:dirty_read({pubsub_node, {Host, Node}}) of
|
||||
[N] -> nodeid(N);
|
||||
_ -> 0
|
||||
end.
|
||||
nodeid(N) -> N#pubsub_node.id.
|
||||
nodeids() -> [nodeid(Host, Node) || {Host, Node} <- mnesia:dirty_all_keys(pubsub_node)].
|
||||
nodeids_by_type(Type) -> [nodeid(N) || N <- mnesia:dirty_match_object(#pubsub_node{type=Type, _='_'})].
|
||||
nodeids_by_option(Key, Value) -> [nodeid(N) || N <- mnesia:dirty_match_object(#pubsub_node{_='_'}), lists:member({Key, Value}, N#pubsub_node.options)].
|
||||
nodeids_by_owner(JID) -> [nodeid(N) || N <- mnesia:dirty_match_object(#pubsub_node{_='_'}), lists:member(JID, N#pubsub_node.owners)].
|
||||
nodes_by_id(I) -> mnesia:dirty_match_object(#pubsub_node{id=I, _='_'}).
|
||||
|
||||
state(JID, NodeId) ->
|
||||
case mnesia:dirty_read({pubsub_state, {JID, NodeId}}) of
|
||||
[S] -> S;
|
||||
_ -> undefined
|
||||
end.
|
||||
states(NodeId) -> mnesia:dirty_match_object(#pubsub_state{stateid={'_', NodeId}, _='_'}).
|
||||
stateid(S) -> element(1, S#pubsub_state.stateid).
|
||||
stateids(NodeId) -> [stateid(S) || S <- states(NodeId)].
|
||||
states_by_jid(JID) -> mnesia:dirty_match_object(#pubsub_state{stateid={JID, '_'}, _='_'}).
|
||||
|
||||
item(ItemId, NodeId) ->
|
||||
case mnesia:dirty_read({pubsub_item, {ItemId, NodeId}}) of
|
||||
[I] -> I;
|
||||
_ -> undefined
|
||||
end.
|
||||
items(NodeId) -> mnesia:dirty_match_object(#pubsub_item{itemid={'_', NodeId}, _='_'}).
|
||||
itemid(I) -> element(1, I#pubsub_item.itemid).
|
||||
itemids(NodeId) -> [itemid(I) || I <- items(NodeId)].
|
||||
items_by_id(ItemId) -> mnesia:dirty_match_object(#pubsub_item{itemid={ItemId, '_'}, _='_'}).
|
||||
|
||||
affiliated(NodeId) -> [stateid(S) || S <- states(NodeId), S#pubsub_state.affiliation=/=none].
|
||||
subscribed(NodeId) -> [stateid(S) || S <- states(NodeId), S#pubsub_state.subscriptions=/=[]].
|
||||
%subscribed(NodeId) -> [stateid(S) || S <- states(NodeId), S#pubsub_state.subscription=/=none]. %% old record
|
||||
owners(NodeId) -> [stateid(S) || S <- mnesia:dirty_match_object(#pubsub_state{stateid={'_', NodeId}, affiliation=owner, _='_'})].
|
||||
|
||||
orphan_items(NodeId) ->
|
||||
itemids(NodeId) -- lists:foldl(fun(S, A) -> A++S#pubsub_state.items end, [], mnesia:dirty_match_object(#pubsub_state{stateid={'_', NodeId}, _='_'})).
|
||||
newer_items(NodeId, Seconds) ->
|
||||
Now = calendar:universal_time(),
|
||||
Oldest = calendar:seconds_to_daystime(Seconds),
|
||||
[itemid(I) || I <- items(NodeId), calendar:time_difference(calendar:now_to_universal_time(element(1, I#pubsub_item.modification)), Now) < Oldest].
|
||||
older_items(NodeId, Seconds) ->
|
||||
Now = calendar:universal_time(),
|
||||
Oldest = calendar:seconds_to_daystime(Seconds),
|
||||
[itemid(I) || I <- items(NodeId), calendar:time_difference(calendar:now_to_universal_time(element(1, I#pubsub_item.modification)), Now) > Oldest].
|
||||
|
||||
orphan_nodes() -> [I || I <- nodeids(), owners(I)==[]].
|
||||
duplicated_nodes() -> L = nodeids(), lists:usort(L -- lists:seq(1, lists:max(L))).
|
||||
node_options(NodeId) ->
|
||||
[N] = mnesia:dirty_match_object(#pubsub_node{id=NodeId, _='_'}),
|
||||
N#pubsub_node.options.
|
||||
update_node_options(Key, Value, NodeId) ->
|
||||
[N] = mnesia:dirty_match_object(#pubsub_node{id=NodeId, _='_'}),
|
||||
NewOptions = lists:keyreplace(Key, 1, N#pubsub_node.options, {Key, Value}),
|
||||
mnesia:dirty_write(N#pubsub_node{options = NewOptions}).
|
||||
|
||||
check() ->
|
||||
mnesia:transaction(fun() ->
|
||||
case mnesia:read({pubsub_index, node}) of
|
||||
[Idx] ->
|
||||
Free = Idx#pubsub_index.free,
|
||||
Last = Idx#pubsub_index.last,
|
||||
Allocated = lists:seq(1, Last) -- Free,
|
||||
NodeIds = mnesia:foldl(fun(N,A) -> [nodeid(N)|A] end, [], pubsub_node),
|
||||
StateIds = lists:usort(mnesia:foldl(fun(S,A) -> [element(2, S#pubsub_state.stateid)|A] end, [], pubsub_state)),
|
||||
ItemIds = lists:usort(mnesia:foldl(fun(I,A) -> [element(2, I#pubsub_item.itemid)|A] end, [], pubsub_item)),
|
||||
BadNodeIds = NodeIds -- Allocated,
|
||||
BadStateIds = StateIds -- NodeIds,
|
||||
BadItemIds = ItemIds -- NodeIds,
|
||||
Lost = Allocated -- NodeIds,
|
||||
[{bad_nodes, [N#pubsub_node.nodeid || N <- lists:flatten([mnesia:match_object(#pubsub_node{id=I, _='_'}) || I <- BadNodeIds])]},
|
||||
{bad_states, lists:foldl(fun(N,A) -> A++[{I,N} || I <- stateids(N)] end, [], BadStateIds)},
|
||||
{bad_items, lists:foldl(fun(N,A) -> A++[{I,N} || I <- itemids(N)] end, [], BadItemIds)},
|
||||
{lost_idx, Lost},
|
||||
{orphaned, [I || I <- NodeIds, owners(I)==[]]},
|
||||
{duplicated, lists:usort(NodeIds -- lists:seq(1, lists:max(NodeIds)))}];
|
||||
_ ->
|
||||
no_index
|
||||
end
|
||||
end).
|
||||
|
||||
rebuild_index() ->
|
||||
mnesia:transaction(fun() ->
|
||||
NodeIds = mnesia:foldl(fun(N,A) -> [nodeid(N)|A] end, [], pubsub_node),
|
||||
Last = lists:max(NodeIds),
|
||||
Free = lists:seq(1, Last) -- NodeIds,
|
||||
mnesia:write(#pubsub_index{index = node, last = Last, free = Free})
|
||||
end).
|
||||
|
||||
pep_subscriptions(LUser, LServer, LResource) ->
|
||||
case ejabberd_sm:get_session_pid({LUser, LServer, LResource}) of
|
||||
C2SPid when is_pid(C2SPid) ->
|
||||
case catch ejabberd_c2s:get_subscribed(C2SPid) of
|
||||
Contacts when is_list(Contacts) ->
|
||||
lists:map(fun({U, S, _}) ->
|
||||
io_lib:format("~s@~s", [U, S])
|
||||
end, Contacts);
|
||||
_ ->
|
||||
[]
|
||||
end;
|
||||
_ ->
|
||||
[]
|
||||
end.
|
@ -76,7 +76,13 @@ process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) ->
|
||||
{UTC, UTC_diff} = jlib:timestamp_to_iso(Now_universal, utc),
|
||||
Seconds_diff = calendar:datetime_to_gregorian_seconds(Now_local)
|
||||
- calendar:datetime_to_gregorian_seconds(Now_universal),
|
||||
{Hd, Md, _} = calendar:seconds_to_time(Seconds_diff),
|
||||
{Hd, Md, _} = case Seconds_diff >= 0 of
|
||||
true ->
|
||||
calendar:seconds_to_time(Seconds_diff);
|
||||
false ->
|
||||
{Hd0, Md0, Sd0} = calendar:seconds_to_time(-Seconds_diff),
|
||||
{-Hd0, Md0, Sd0}
|
||||
end,
|
||||
{_, TZO_diff} = jlib:timestamp_to_iso({{0, 0, 0}, {0, 0, 0}}, {Hd, Md}),
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "time",
|
||||
|
Loading…
Reference in New Issue
Block a user