mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
* tools/ejabberdctl: Added call to "exec" (thanks to Sergei
Golovan) * src/msgs/ru.msg: Updated (thanks to Sergei Golovan) * src/mod_vcard.erl: Support for searching of prefix substring and limiting of result items (thanks to Sergei Golovan) * src/mod_offline.erl: Support for message expiration (JEP-0023) (thanks to Sergei Golovan) * src/jlib.hrl: Added NS_EXPIRE macros (thanks to Sergei Golovan) * src/ejabberd_logger_h.erl: Added reopen_log/0 (thanks to Sergei Golovan) * src/ejabberd_ctl.erl: Added return codes, updated "reopen-log" command, added "delete-expired-messages" and "status" commands (thanks to Sergei Golovan) * doc/guide.tex: Updated (thanks to Sergei Golovan) SVN Revision: 264
This commit is contained in:
parent
210a9a689b
commit
e0ede61e0f
27
ChangeLog
27
ChangeLog
@ -1,3 +1,30 @@
|
|||||||
|
2004-09-10 Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
|
||||||
|
* tools/ejabberdctl: Added call to "exec" (thanks to Sergei
|
||||||
|
Golovan)
|
||||||
|
|
||||||
|
* src/msgs/ru.msg: Updated (thanks to Sergei Golovan)
|
||||||
|
|
||||||
|
* src/mod_vcard.erl: Support for searching of prefix substring and
|
||||||
|
limiting of result items (thanks to Sergei Golovan)
|
||||||
|
|
||||||
|
* src/mod_offline.erl: Support for message expiration (JEP-0023)
|
||||||
|
(thanks to Sergei Golovan)
|
||||||
|
* src/jlib.hrl: Added NS_EXPIRE macros (thanks to Sergei Golovan)
|
||||||
|
|
||||||
|
* src/ejabberd_logger_h.erl: Added reopen_log/0 (thanks to Sergei
|
||||||
|
Golovan)
|
||||||
|
|
||||||
|
* src/ejabberd_ctl.erl: Added return codes, updated "reopen-log"
|
||||||
|
command, added "delete-expired-messages" and "status" commands
|
||||||
|
(thanks to Sergei Golovan)
|
||||||
|
|
||||||
|
* doc/guide.tex: Updated (thanks to Sergei Golovan)
|
||||||
|
|
||||||
|
2004-09-04 Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
|
||||||
|
* src/mod_roster.erl: Removed useless transactions
|
||||||
|
|
||||||
2004-08-28 Alexey Shchepin <alexey@sevcom.net>
|
2004-08-28 Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
|
||||||
* doc/guide.tex: Fix (thanks to Sander Devrieze)
|
* doc/guide.tex: Fix (thanks to Sander Devrieze)
|
||||||
|
@ -1131,6 +1131,8 @@ Options:
|
|||||||
\titem{search} Specifies wheather search is enabled (value is \term{true}, default) or
|
\titem{search} Specifies wheather search is enabled (value is \term{true}, default) or
|
||||||
disabled (value is \term{false}) by the service. If \term{search} is set to \term{false},
|
disabled (value is \term{false}) by the service. If \term{search} is set to \term{false},
|
||||||
option \term{host} is ignored and service does not appear in Jabber Discovery items.
|
option \term{host} is ignored and service does not appear in Jabber Discovery items.
|
||||||
|
\titem{matches} Limits the number of reported search results. If value is set to
|
||||||
|
\term{infinity} then all search results are reported. Default value is \term{30}.
|
||||||
\end{description}
|
\end{description}
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@ -1138,7 +1140,7 @@ Example:
|
|||||||
{modules,
|
{modules,
|
||||||
[
|
[
|
||||||
...
|
...
|
||||||
{mod_vcard, [{search, false}]}
|
{mod_vcard, [{search, false}, {matches, 20}]}
|
||||||
...
|
...
|
||||||
]}.
|
]}.
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
|
@ -11,124 +11,166 @@
|
|||||||
|
|
||||||
-export([start/0]).
|
-export([start/0]).
|
||||||
|
|
||||||
|
-define(STATUS_SUCCESS, 0).
|
||||||
|
-define(STATUS_ERROR, 1).
|
||||||
|
-define(STATUS_USAGE, 2).
|
||||||
|
-define(STATUS_BADRPC, 3).
|
||||||
|
|
||||||
start() ->
|
start() ->
|
||||||
case init:get_plain_arguments() of
|
case init:get_plain_arguments() of
|
||||||
[SNode | Args] ->
|
[SNode | Args] ->
|
||||||
Node = list_to_atom(SNode),
|
Node = list_to_atom(SNode),
|
||||||
process(Node, Args);
|
Status = process(Node, Args),
|
||||||
|
halt(Status);
|
||||||
_ ->
|
_ ->
|
||||||
print_usage()
|
print_usage(),
|
||||||
end,
|
halt(?STATUS_USAGE)
|
||||||
halt().
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
process(Node, ["status"]) ->
|
||||||
|
case rpc:call(Node, init, get_status, []) of
|
||||||
|
{badrpc, Reason} ->
|
||||||
|
io:format("Can't get node ~p status: ~p~n",
|
||||||
|
[Node, Reason]),
|
||||||
|
?STATUS_BADRPC;
|
||||||
|
{InternalStatus, ProvidedStatus} ->
|
||||||
|
io:format("Node ~p is ~p. Status: ~p~n",
|
||||||
|
[Node, InternalStatus, ProvidedStatus]),
|
||||||
|
?STATUS_SUCCESS
|
||||||
|
end;
|
||||||
|
|
||||||
process(Node, ["stop"]) ->
|
process(Node, ["stop"]) ->
|
||||||
case rpc:call(Node, init, stop, []) of
|
case rpc:call(Node, init, stop, []) of
|
||||||
{badrpc, Reason} ->
|
{badrpc, Reason} ->
|
||||||
io:format("Can't stop node ~p: ~p~n",
|
io:format("Can't stop node ~p: ~p~n",
|
||||||
[Node, Reason]);
|
[Node, Reason]),
|
||||||
|
?STATUS_BADRPC;
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
?STATUS_SUCCESS
|
||||||
end;
|
end;
|
||||||
|
|
||||||
process(Node, ["restart"]) ->
|
process(Node, ["restart"]) ->
|
||||||
case rpc:call(Node, init, restart, []) of
|
case rpc:call(Node, init, restart, []) of
|
||||||
{badrpc, Reason} ->
|
{badrpc, Reason} ->
|
||||||
io:format("Can't restart node ~p: ~p~n",
|
io:format("Can't restart node ~p: ~p~n",
|
||||||
[Node, Reason]);
|
[Node, Reason]),
|
||||||
|
?STATUS_BADRPC;
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
?STATUS_SUCCESS
|
||||||
end;
|
end;
|
||||||
|
|
||||||
process(Node, ["reopen-log"]) ->
|
process(Node, ["reopen-log"]) ->
|
||||||
{error_logger, Node} ! {emulator, noproc, reopen};
|
case rpc:call(Node, ejabberd_logger_h, reopen_log, []) of
|
||||||
|
{badrpc, Reason} ->
|
||||||
|
io:format("Can't reopen node ~p log: ~p~n",
|
||||||
|
[Node, Reason]),
|
||||||
|
?STATUS_BADRPC;
|
||||||
|
_ ->
|
||||||
|
?STATUS_SUCCESS
|
||||||
|
end;
|
||||||
|
|
||||||
process(Node, ["register", User, Password]) ->
|
process(Node, ["register", User, Password]) ->
|
||||||
case rpc:call(Node, ejabberd_auth, try_register, [User, Password]) of
|
case rpc:call(Node, ejabberd_auth, try_register, [User, Password]) of
|
||||||
{atomic, ok} ->
|
{atomic, ok} ->
|
||||||
ok;
|
?STATUS_SUCCESS;
|
||||||
{atomic, exists} ->
|
{atomic, exists} ->
|
||||||
io:format("User ~p already registered on node ~p~n",
|
io:format("User ~p already registered on node ~p~n",
|
||||||
[User, Node]);
|
[User, Node]),
|
||||||
|
?STATUS_ERROR;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
io:format("Can't register user ~p on node ~p: ~p~n",
|
io:format("Can't register user ~p on node ~p: ~p~n",
|
||||||
[User, Node, Reason]);
|
[User, Node, Reason]),
|
||||||
|
?STATUS_ERROR;
|
||||||
{badrpc, Reason} ->
|
{badrpc, Reason} ->
|
||||||
io:format("Can't register user ~p on node ~p: ~p~n",
|
io:format("Can't register user ~p on node ~p: ~p~n",
|
||||||
[User, Node, Reason])
|
[User, Node, Reason]),
|
||||||
|
?STATUS_BADRPC
|
||||||
end;
|
end;
|
||||||
|
|
||||||
process(Node, ["unregister", User]) ->
|
process(Node, ["unregister", User]) ->
|
||||||
case rpc:call(Node, ejabberd_auth, remove_user, [User]) of
|
case rpc:call(Node, ejabberd_auth, remove_user, [User]) of
|
||||||
{atomic, ok} ->
|
{atomic, ok} ->
|
||||||
ok;
|
?STATUS_SUCCESS;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
io:format("Can't unregister user ~p on node ~p: ~p~n",
|
io:format("Can't unregister user ~p on node ~p: ~p~n",
|
||||||
[User, Node, Reason]);
|
[User, Node, Reason]),
|
||||||
|
?STATUS_ERROR;
|
||||||
{badrpc, Reason} ->
|
{badrpc, Reason} ->
|
||||||
io:format("Can't unregister user ~p on node ~p: ~p~n",
|
io:format("Can't unregister user ~p on node ~p: ~p~n",
|
||||||
[User, Node, Reason])
|
[User, Node, Reason]),
|
||||||
|
?STATUS_BADRPC
|
||||||
end;
|
end;
|
||||||
|
|
||||||
process(Node, ["backup", Path]) ->
|
process(Node, ["backup", Path]) ->
|
||||||
case rpc:call(Node, mnesia, backup, [Path]) of
|
case rpc:call(Node, mnesia, backup, [Path]) of
|
||||||
ok ->
|
ok ->
|
||||||
ok;
|
?STATUS_SUCCESS;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
io:format("Can't store backup in ~p on node ~p: ~p~n",
|
io:format("Can't store backup in ~p on node ~p: ~p~n",
|
||||||
[Path, Node, Reason]);
|
[Path, Node, Reason]),
|
||||||
|
?STATUS_ERROR;
|
||||||
{badrpc, Reason} ->
|
{badrpc, Reason} ->
|
||||||
io:format("Can't store backup in ~p on node ~p: ~p~n",
|
io:format("Can't store backup in ~p on node ~p: ~p~n",
|
||||||
[Path, Node, Reason])
|
[Path, Node, Reason]),
|
||||||
|
?STATUS_BADRPC
|
||||||
end;
|
end;
|
||||||
|
|
||||||
process(Node, ["dump", Path]) ->
|
process(Node, ["dump", Path]) ->
|
||||||
case rpc:call(Node, mnesia, dump_to_textfile, [Path]) of
|
case rpc:call(Node, mnesia, dump_to_textfile, [Path]) of
|
||||||
ok ->
|
ok ->
|
||||||
ok;
|
?STATUS_SUCCESS;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
io:format("Can't store dump in ~p on node ~p: ~p~n",
|
io:format("Can't store dump in ~p on node ~p: ~p~n",
|
||||||
[Path, Node, Reason]);
|
[Path, Node, Reason]),
|
||||||
|
?STATUS_ERROR;
|
||||||
{badrpc, Reason} ->
|
{badrpc, Reason} ->
|
||||||
io:format("Can't store dump in ~p on node ~p: ~p~n",
|
io:format("Can't store dump in ~p on node ~p: ~p~n",
|
||||||
[Path, Node, Reason])
|
[Path, Node, Reason]),
|
||||||
|
?STATUS_BADRPC
|
||||||
end;
|
end;
|
||||||
|
|
||||||
process(Node, ["load", Path]) ->
|
process(Node, ["load", Path]) ->
|
||||||
case rpc:call(Node, mnesia, load_textfile, [Path]) of
|
case rpc:call(Node, mnesia, load_textfile, [Path]) of
|
||||||
ok ->
|
ok ->
|
||||||
ok;
|
?STATUS_SUCCESS;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
io:format("Can't load dump in ~p on node ~p: ~p~n",
|
io:format("Can't load dump in ~p on node ~p: ~p~n",
|
||||||
[Path, Node, Reason]);
|
[Path, Node, Reason]),
|
||||||
|
?STATUS_ERROR;
|
||||||
{badrpc, Reason} ->
|
{badrpc, Reason} ->
|
||||||
io:format("Can't load dump in ~p on node ~p: ~p~n",
|
io:format("Can't load dump in ~p on node ~p: ~p~n",
|
||||||
[Path, Node, Reason])
|
[Path, Node, Reason]),
|
||||||
|
?STATUS_BADRPC
|
||||||
end;
|
end;
|
||||||
|
|
||||||
process(Node, ["restore", Path]) ->
|
process(Node, ["restore", Path]) ->
|
||||||
case rpc:call(Node,
|
case rpc:call(Node,
|
||||||
mnesia, restore, [Path, [{default_op, keep_tables}]]) of
|
mnesia, restore, [Path, [{default_op, keep_tables}]]) of
|
||||||
{atomic, ok} ->
|
{atomic, ok} ->
|
||||||
ok;
|
?STATUS_SUCCESS;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
io:format("Can't restore backup from ~p on node ~p: ~p~n",
|
io:format("Can't restore backup from ~p on node ~p: ~p~n",
|
||||||
[Path, Node, Reason]);
|
[Path, Node, Reason]),
|
||||||
|
?STATUS_ERROR;
|
||||||
{badrpc, Reason} ->
|
{badrpc, Reason} ->
|
||||||
io:format("Can't restore backup from ~p on node ~p: ~p~n",
|
io:format("Can't restore backup from ~p on node ~p: ~p~n",
|
||||||
[Path, Node, Reason])
|
[Path, Node, Reason]),
|
||||||
|
?STATUS_BADRPC
|
||||||
end;
|
end;
|
||||||
|
|
||||||
process(Node, ["install-fallback", Path]) ->
|
process(Node, ["install-fallback", Path]) ->
|
||||||
case rpc:call(Node, mnesia, install_fallback, [Path]) of
|
case rpc:call(Node, mnesia, install_fallback, [Path]) of
|
||||||
{atomic, ok} ->
|
{atomic, ok} ->
|
||||||
ok;
|
?STATUS_SUCCESS;
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
io:format("Can't install fallback from ~p on node ~p: ~p~n",
|
io:format("Can't install fallback from ~p on node ~p: ~p~n",
|
||||||
[Path, Node, Reason]);
|
[Path, Node, Reason]),
|
||||||
|
?STATUS_ERROR;
|
||||||
{badrpc, Reason} ->
|
{badrpc, Reason} ->
|
||||||
io:format("Can't install fallback from ~p on node ~p: ~p~n",
|
io:format("Can't install fallback from ~p on node ~p: ~p~n",
|
||||||
[Path, Node, Reason])
|
[Path, Node, Reason]),
|
||||||
|
?STATUS_BADRPC
|
||||||
end;
|
end;
|
||||||
|
|
||||||
process(Node, ["registered-users"]) ->
|
process(Node, ["registered-users"]) ->
|
||||||
@ -138,14 +180,30 @@ process(Node, ["registered-users"]) ->
|
|||||||
SUsers = lists:sort(Users),
|
SUsers = lists:sort(Users),
|
||||||
FUsers = lists:map(fun(U) -> [U, NewLine] end, SUsers),
|
FUsers = lists:map(fun(U) -> [U, NewLine] end, SUsers),
|
||||||
io:format("~s", [FUsers]),
|
io:format("~s", [FUsers]),
|
||||||
ok;
|
?STATUS_SUCCESS;
|
||||||
{ErrorTag, Reason} when (ErrorTag == error) or (ErrorTag == badrpc) ->
|
{error, Reason} ->
|
||||||
io:format("Can't get list of registered users on node ~p: ~p~n",
|
io:format("Can't get list of registered users on node ~p: ~p~n",
|
||||||
[Node, Reason])
|
[Node, Reason]),
|
||||||
|
?STATUS_ERROR;
|
||||||
|
{badrpc, Reason} ->
|
||||||
|
io:format("Can't get list of registered users on node ~p: ~p~n",
|
||||||
|
[Node, Reason]),
|
||||||
|
?STATUS_BADRPC
|
||||||
|
end;
|
||||||
|
|
||||||
|
process(Node, ["delete-expired-messages"]) ->
|
||||||
|
case rpc:call(Node, mod_offline, remove_expired_messages, []) of
|
||||||
|
{badrpc, Reason} ->
|
||||||
|
io:format("Can't delete expired messages at node ~p: ~p~n",
|
||||||
|
[Node, Reason]),
|
||||||
|
?STATUS_BADRPC;
|
||||||
|
_ ->
|
||||||
|
?STATUS_SUCCESS
|
||||||
end;
|
end;
|
||||||
|
|
||||||
process(_Node, _Args) ->
|
process(_Node, _Args) ->
|
||||||
print_usage().
|
print_usage(),
|
||||||
|
?STATUS_USAGE.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -154,6 +212,7 @@ print_usage() ->
|
|||||||
"Usage: ejabberdctl node command~n"
|
"Usage: ejabberdctl node command~n"
|
||||||
"~n"
|
"~n"
|
||||||
"Available commands:~n"
|
"Available commands:~n"
|
||||||
|
" status\t\t\tget ejabberd status~n"
|
||||||
" stop\t\t\t\tstop ejabberd~n"
|
" stop\t\t\t\tstop ejabberd~n"
|
||||||
" restart\t\t\trestart ejabberd~n"
|
" restart\t\t\trestart ejabberd~n"
|
||||||
" reopen-log\t\t\treopen log file~n"
|
" reopen-log\t\t\treopen log file~n"
|
||||||
@ -165,6 +224,7 @@ print_usage() ->
|
|||||||
" dump file\t\t\tdump a database in a text file~n"
|
" dump file\t\t\tdump a database in a text file~n"
|
||||||
" load file\t\t\trestore a database from a text file~n"
|
" load file\t\t\trestore a database from a text file~n"
|
||||||
" registered-users\t\tlist all registered users~n"
|
" registered-users\t\tlist all registered users~n"
|
||||||
|
" delete-expired-messages\tdelete expired offline messages from database~n"
|
||||||
"~n"
|
"~n"
|
||||||
"Example:~n"
|
"Example:~n"
|
||||||
" ejabberdctl ejabberd@host restart~n"
|
" ejabberdctl ejabberd@host restart~n"
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
%% gen_event callbacks
|
%% gen_event callbacks
|
||||||
-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2,
|
-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2,
|
||||||
code_change/3]).
|
code_change/3, reopen_log/0]).
|
||||||
|
|
||||||
-record(state, {fd, file}).
|
-record(state, {fd, file}).
|
||||||
|
|
||||||
@ -89,6 +89,9 @@ terminate(_Reason, _State) ->
|
|||||||
code_change(_OldVsn, State, _Extra) ->
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
{ok, State}.
|
{ok, State}.
|
||||||
|
|
||||||
|
reopen_log() ->
|
||||||
|
error_logger ! {emulator, noproc, reopen}.
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
-define(NS_XDATA, "jabber:x:data").
|
-define(NS_XDATA, "jabber:x:data").
|
||||||
-define(NS_IQDATA, "jabber:iq:data").
|
-define(NS_IQDATA, "jabber:iq:data").
|
||||||
-define(NS_DELAY, "jabber:x:delay").
|
-define(NS_DELAY, "jabber:x:delay").
|
||||||
|
-define(NS_EXPIRE, "jabber:x:expire").
|
||||||
-define(NS_EVENT, "jabber:x:event").
|
-define(NS_EVENT, "jabber:x:event").
|
||||||
-define(NS_XCONFERENCE, "jabber:x:conference").
|
-define(NS_XCONFERENCE, "jabber:x:conference").
|
||||||
-define(NS_STATS, "http://jabber.org/protocol/stats").
|
-define(NS_STATS, "http://jabber.org/protocol/stats").
|
||||||
|
@ -17,12 +17,14 @@
|
|||||||
store_packet/3,
|
store_packet/3,
|
||||||
resend_offline_messages/1,
|
resend_offline_messages/1,
|
||||||
pop_offline_messages/2,
|
pop_offline_messages/2,
|
||||||
|
remove_expired_messages/0,
|
||||||
remove_old_messages/1,
|
remove_old_messages/1,
|
||||||
remove_user/1]).
|
remove_user/1]).
|
||||||
|
|
||||||
|
-include("ejabberd.hrl").
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
|
|
||||||
-record(offline_msg, {user, timestamp, from, to, packet}).
|
-record(offline_msg, {user, timestamp, expire, from, to, packet}).
|
||||||
|
|
||||||
-define(PROCNAME, ejabberd_offline).
|
-define(PROCNAME, ejabberd_offline).
|
||||||
-define(OFFLINE_TABLE_LOCK_THRESHOLD, 1000).
|
-define(OFFLINE_TABLE_LOCK_THRESHOLD, 1000).
|
||||||
@ -32,6 +34,7 @@ start(_) ->
|
|||||||
[{disc_only_copies, [node()]},
|
[{disc_only_copies, [node()]},
|
||||||
{type, bag},
|
{type, bag},
|
||||||
{attributes, record_info(fields, offline_msg)}]),
|
{attributes, record_info(fields, offline_msg)}]),
|
||||||
|
update_table(),
|
||||||
ejabberd_hooks:add(offline_message_hook,
|
ejabberd_hooks:add(offline_message_hook,
|
||||||
?MODULE, store_packet, 50),
|
?MODULE, store_packet, 50),
|
||||||
ejabberd_hooks:add(offline_subscription_hook,
|
ejabberd_hooks:add(offline_subscription_hook,
|
||||||
@ -92,8 +95,11 @@ store_packet(From, To, Packet) ->
|
|||||||
true ->
|
true ->
|
||||||
#jid{luser = LUser} = To,
|
#jid{luser = LUser} = To,
|
||||||
TimeStamp = now(),
|
TimeStamp = now(),
|
||||||
|
{xmlelement, _Name, _Attrs, Els} = Packet,
|
||||||
|
Expire = find_x_expire(TimeStamp, Els),
|
||||||
?PROCNAME ! #offline_msg{user = LUser,
|
?PROCNAME ! #offline_msg{user = LUser,
|
||||||
timestamp = TimeStamp,
|
timestamp = TimeStamp,
|
||||||
|
expire = Expire,
|
||||||
from = From,
|
from = From,
|
||||||
to = To,
|
to = To,
|
||||||
packet = Packet},
|
packet = Packet},
|
||||||
@ -150,6 +156,34 @@ find_x_event([El | Els]) ->
|
|||||||
find_x_event(Els)
|
find_x_event(Els)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
find_x_expire(_, []) ->
|
||||||
|
never;
|
||||||
|
find_x_expire(TimeStamp, [{xmlcdata, _} | Els]) ->
|
||||||
|
find_x_expire(TimeStamp, Els);
|
||||||
|
find_x_expire(TimeStamp, [El | Els]) ->
|
||||||
|
case xml:get_tag_attr_s("xmlns", El) of
|
||||||
|
?NS_EXPIRE ->
|
||||||
|
case xml:get_tag_attr_s("seconds", El) of
|
||||||
|
Val ->
|
||||||
|
case catch list_to_integer(Val) of
|
||||||
|
{'EXIT', _} ->
|
||||||
|
never;
|
||||||
|
Int when Int > 0 ->
|
||||||
|
{MegaSecs, Secs, MicroSecs} = TimeStamp,
|
||||||
|
S = MegaSecs * 1000000 + Secs + Int,
|
||||||
|
MegaSecs1 = S div 1000000,
|
||||||
|
Secs1 = S rem 1000000,
|
||||||
|
{MegaSecs1, Secs1, MicroSecs};
|
||||||
|
_ ->
|
||||||
|
never
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
never
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
find_x_expire(TimeStamp, Els)
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
resend_offline_messages(User) ->
|
resend_offline_messages(User) ->
|
||||||
LUser = jlib:nodeprep(User),
|
LUser = jlib:nodeprep(User),
|
||||||
@ -187,23 +221,54 @@ pop_offline_messages(Ls, User) ->
|
|||||||
end,
|
end,
|
||||||
case mnesia:transaction(F) of
|
case mnesia:transaction(F) of
|
||||||
{atomic, Rs} ->
|
{atomic, Rs} ->
|
||||||
lists:map(
|
TS = now(),
|
||||||
fun(R) ->
|
Ls ++ lists:map(
|
||||||
{xmlelement, Name, Attrs, Els} = R#offline_msg.packet,
|
fun(R) ->
|
||||||
{route,
|
{xmlelement, Name, Attrs, Els} = R#offline_msg.packet,
|
||||||
R#offline_msg.from,
|
{route,
|
||||||
R#offline_msg.to,
|
R#offline_msg.from,
|
||||||
{xmlelement, Name, Attrs,
|
R#offline_msg.to,
|
||||||
Els ++
|
{xmlelement, Name, Attrs,
|
||||||
[jlib:timestamp_to_xml(
|
Els ++
|
||||||
calendar:now_to_universal_time(
|
[jlib:timestamp_to_xml(
|
||||||
R#offline_msg.timestamp))]}}
|
calendar:now_to_universal_time(
|
||||||
end,
|
R#offline_msg.timestamp))]}}
|
||||||
Ls ++ lists:keysort(#offline_msg.timestamp, Rs));
|
end,
|
||||||
|
lists:filter(
|
||||||
|
fun(R) ->
|
||||||
|
case R#offline_msg.expire of
|
||||||
|
never ->
|
||||||
|
true;
|
||||||
|
TimeStamp ->
|
||||||
|
TS < TimeStamp
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
lists:keysort(#offline_msg.timestamp, Rs)));
|
||||||
_ ->
|
_ ->
|
||||||
Ls
|
Ls
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
remove_expired_messages() ->
|
||||||
|
TimeStamp = now(),
|
||||||
|
F = fun() ->
|
||||||
|
mnesia:write_lock_table(offline_msg),
|
||||||
|
mnesia:foldl(
|
||||||
|
fun(Rec, _Acc) ->
|
||||||
|
case Rec#offline_msg.expire of
|
||||||
|
never ->
|
||||||
|
ok;
|
||||||
|
TS ->
|
||||||
|
if
|
||||||
|
TS < TimeStamp ->
|
||||||
|
mnesia:delete_object(Rec);
|
||||||
|
true ->
|
||||||
|
ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end, ok, offline_msg)
|
||||||
|
end,
|
||||||
|
mnesia:transaction(F).
|
||||||
|
|
||||||
remove_old_messages(Days) ->
|
remove_old_messages(Days) ->
|
||||||
{MegaSecs, Secs, _MicroSecs} = now(),
|
{MegaSecs, Secs, _MicroSecs} = now(),
|
||||||
S = MegaSecs * 1000000 + Secs - 60 * 60 * 24 * Days,
|
S = MegaSecs * 1000000 + Secs - 60 * 60 * 24 * Days,
|
||||||
@ -227,3 +292,29 @@ remove_user(User) ->
|
|||||||
mnesia:delete({offline_msg, LUser})
|
mnesia:delete({offline_msg, LUser})
|
||||||
end,
|
end,
|
||||||
mnesia:transaction(F).
|
mnesia:transaction(F).
|
||||||
|
|
||||||
|
update_table() ->
|
||||||
|
Fields = record_info(fields, offline_msg),
|
||||||
|
case mnesia:table_info(offline_msg, attributes) of
|
||||||
|
Fields ->
|
||||||
|
ok;
|
||||||
|
[user, timestamp, from, to, packet] ->
|
||||||
|
?INFO_MSG("Converting offline_msg table from "
|
||||||
|
"{user, timestamp, from, to, packet} format", []),
|
||||||
|
mnesia:transform_table(
|
||||||
|
offline_msg,
|
||||||
|
fun({_, U, TS, F, T, P}) ->
|
||||||
|
{xmlelement, _Name, _Attrs, Els} = P,
|
||||||
|
Expire = find_x_expire(TS, Els),
|
||||||
|
#offline_msg{user = U,
|
||||||
|
timestamp = TS,
|
||||||
|
expire = Expire,
|
||||||
|
from = F,
|
||||||
|
to = T,
|
||||||
|
packet = P}
|
||||||
|
end, Fields);
|
||||||
|
_ ->
|
||||||
|
?INFO_MSG("Recreating offline_msg table", []),
|
||||||
|
mnesia:transform_table(last_activity, ignore, Fields)
|
||||||
|
end.
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% File : mod_roster.erl
|
%%% File : mod_roster.erl
|
||||||
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||||
%%% Purpose :
|
%%% Purpose : Roster management
|
||||||
%%% Created : 11 Dec 2002 by Alexey Shchepin <alexey@sevcom.net>
|
%%% Created : 11 Dec 2002 by Alexey Shchepin <alexey@sevcom.net>
|
||||||
%%% Id : $Id$
|
%%% Id : $Id$
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
@ -90,11 +90,8 @@ process_local_iq(From, To, #iq{type = Type} = IQ) ->
|
|||||||
|
|
||||||
process_iq_get(From, _To, #iq{sub_el = SubEl} = IQ) ->
|
process_iq_get(From, _To, #iq{sub_el = SubEl} = IQ) ->
|
||||||
#jid{luser = LUser} = From,
|
#jid{luser = LUser} = From,
|
||||||
F = fun() ->
|
case catch mnesia:dirty_index_read(roster, LUser, #roster.user) of
|
||||||
mnesia:index_read(roster, LUser, #roster.user)
|
Items when is_list(Items) ->
|
||||||
end,
|
|
||||||
case mnesia:transaction(F) of
|
|
||||||
{atomic, Items} ->
|
|
||||||
XItems = lists:map(fun item_to_xml/1, Items),
|
XItems = lists:map(fun item_to_xml/1, Items),
|
||||||
IQ#iq{type = result,
|
IQ#iq{type = result,
|
||||||
sub_el = [{xmlelement, "query",
|
sub_el = [{xmlelement, "query",
|
||||||
@ -316,11 +313,8 @@ push_item(User, Resource, From, Item) ->
|
|||||||
|
|
||||||
get_subscription_lists(User) ->
|
get_subscription_lists(User) ->
|
||||||
LUser = jlib:nodeprep(User),
|
LUser = jlib:nodeprep(User),
|
||||||
F = fun() ->
|
case mnesia:dirty_index_read(roster, LUser, #roster.user) of
|
||||||
mnesia:index_read(roster, LUser, #roster.user)
|
Items when is_list(Items) ->
|
||||||
end,
|
|
||||||
case mnesia:transaction(F) of
|
|
||||||
{atomic, Items} ->
|
|
||||||
fill_subscription_lists(Items, [], []);
|
fill_subscription_lists(Items, [], []);
|
||||||
_ ->
|
_ ->
|
||||||
{[], []}
|
{[], []}
|
||||||
|
@ -22,7 +22,8 @@
|
|||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
|
|
||||||
|
|
||||||
%-define(JUD_ALLOW_RETURN_ALL, true)
|
%-define(JUD_ALLOW_RETURN_ALL, true).
|
||||||
|
-define(JUD_MATCHES, 30).
|
||||||
|
|
||||||
-record(vcard_search, {user, luser,
|
-record(vcard_search, {user, luser,
|
||||||
fn, lfn,
|
fn, lfn,
|
||||||
@ -234,8 +235,10 @@ set_vcard(User, VCARD) ->
|
|||||||
[{xmlcdata, translate:translate(Lang, "Search users in ") ++
|
[{xmlcdata, translate:translate(Lang, "Search users in ") ++
|
||||||
jlib:jid_to_string(JID)}]},
|
jlib:jid_to_string(JID)}]},
|
||||||
{xmlelement, "instructions", [],
|
{xmlelement, "instructions", [],
|
||||||
[{xmlcdata, translate:translate(Lang, "Fill in fields to search "
|
[{xmlcdata, translate:translate(Lang, "Fill in the form to search "
|
||||||
"for any matching Jabber User")}]},
|
"for any matching Jabber User "
|
||||||
|
"(Add * to the end of field to "
|
||||||
|
"match substring)")}]},
|
||||||
?TLFIELD("text-single", "User", "user"),
|
?TLFIELD("text-single", "User", "user"),
|
||||||
?TLFIELD("text-single", "Full Name", "fn"),
|
?TLFIELD("text-single", "Full Name", "fn"),
|
||||||
?TLFIELD("text-single", "Name", "given"),
|
?TLFIELD("text-single", "Name", "given"),
|
||||||
@ -452,7 +455,17 @@ search(Data) ->
|
|||||||
?ERROR_MSG("~p", [Reason]),
|
?ERROR_MSG("~p", [Reason]),
|
||||||
[];
|
[];
|
||||||
Rs ->
|
Rs ->
|
||||||
Rs
|
case gen_mod:get_module_opt(?MODULE, matches, 30) of
|
||||||
|
infinity ->
|
||||||
|
Rs;
|
||||||
|
Val when is_integer(Val) and Val > 0 ->
|
||||||
|
lists:sublist(Rs, Val);
|
||||||
|
Val ->
|
||||||
|
?ERROR_MSG("Illegal option value ~p. "
|
||||||
|
"Default value ~p substituted.",
|
||||||
|
[{matches, Val}, ?JUD_MATCHES]),
|
||||||
|
lists:sublist(Rs, ?JUD_MATCHES)
|
||||||
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-else.
|
-else.
|
||||||
@ -469,7 +482,17 @@ search(Data) ->
|
|||||||
?ERROR_MSG("~p", [Reason]),
|
?ERROR_MSG("~p", [Reason]),
|
||||||
[];
|
[];
|
||||||
Rs ->
|
Rs ->
|
||||||
Rs
|
case gen_mod:get_module_opt(?MODULE, matches, ?JUD_MATCHES) of
|
||||||
|
infinity ->
|
||||||
|
Rs;
|
||||||
|
Val when is_integer(Val) and (Val > 0) ->
|
||||||
|
lists:sublist(Rs, Val);
|
||||||
|
Val ->
|
||||||
|
?ERROR_MSG("Illegal option value ~p. "
|
||||||
|
"Default value ~p substituted.",
|
||||||
|
[{matches, Val}, ?JUD_MATCHES]),
|
||||||
|
lists:sublist(Rs, ?JUD_MATCHES)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
@ -499,24 +522,31 @@ filter_fields([{SVar, [Val]} | Ds], Match)
|
|||||||
when is_list(Val) and (Val /= "") ->
|
when is_list(Val) and (Val /= "") ->
|
||||||
LVal = stringprep:tolower(Val),
|
LVal = stringprep:tolower(Val),
|
||||||
NewMatch = case SVar of
|
NewMatch = case SVar of
|
||||||
"user" -> Match#vcard_search{luser = LVal};
|
"user" -> Match#vcard_search{luser = make_val(LVal)};
|
||||||
"fn" -> Match#vcard_search{lfn = LVal};
|
"fn" -> Match#vcard_search{lfn = make_val(LVal)};
|
||||||
"family" -> Match#vcard_search{lfamily = LVal};
|
"family" -> Match#vcard_search{lfamily = make_val(LVal)};
|
||||||
"given" -> Match#vcard_search{lgiven = LVal};
|
"given" -> Match#vcard_search{lgiven = make_val(LVal)};
|
||||||
"middle" -> Match#vcard_search{lmiddle = LVal};
|
"middle" -> Match#vcard_search{lmiddle = make_val(LVal)};
|
||||||
"nickname" -> Match#vcard_search{lnickname = LVal};
|
"nickname" -> Match#vcard_search{lnickname = make_val(LVal)};
|
||||||
"bday" -> Match#vcard_search{lbday = LVal};
|
"bday" -> Match#vcard_search{lbday = make_val(LVal)};
|
||||||
"ctry" -> Match#vcard_search{lctry = LVal};
|
"ctry" -> Match#vcard_search{lctry = make_val(LVal)};
|
||||||
"locality" -> Match#vcard_search{llocality = LVal};
|
"locality" -> Match#vcard_search{llocality = make_val(LVal)};
|
||||||
"email" -> Match#vcard_search{lemail = LVal};
|
"email" -> Match#vcard_search{lemail = make_val(LVal)};
|
||||||
"orgname" -> Match#vcard_search{lorgname = LVal};
|
"orgname" -> Match#vcard_search{lorgname = make_val(LVal)};
|
||||||
"orgunit" -> Match#vcard_search{lorgunit = LVal};
|
"orgunit" -> Match#vcard_search{lorgunit = make_val(LVal)};
|
||||||
_ -> Match
|
_ -> Match
|
||||||
end,
|
end,
|
||||||
filter_fields(Ds, NewMatch);
|
filter_fields(Ds, NewMatch);
|
||||||
filter_fields([_ | Ds], Match) ->
|
filter_fields([_ | Ds], Match) ->
|
||||||
filter_fields(Ds, Match).
|
filter_fields(Ds, Match).
|
||||||
|
|
||||||
|
make_val(Val) ->
|
||||||
|
case lists:suffix("*", Val) of
|
||||||
|
true ->
|
||||||
|
lists:sublist(Val, length(Val) - 1) ++ '_';
|
||||||
|
_ ->
|
||||||
|
Val
|
||||||
|
end.
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
@ -74,8 +74,8 @@
|
|||||||
{"You need an x:data capable client to search",
|
{"You need an x:data capable client to search",
|
||||||
"Чтобы воспользоваться поиском, требуется x:data-совместимый клиент"}.
|
"Чтобы воспользоваться поиском, требуется x:data-совместимый клиент"}.
|
||||||
{"Search users in ", "Поиск пользователей в "}.
|
{"Search users in ", "Поиск пользователей в "}.
|
||||||
{"Fill in fields to search for any matching Jabber User",
|
{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)",
|
||||||
"Заполните поля для поиска пользователя Jabber"}.
|
"Заполните форму для поиска пользователя Jabber (Если добавить * в конец поля, то происходит поиск подстроки)"}.
|
||||||
{"Results of search in ", "Результаты поиска в "}.
|
{"Results of search in ", "Результаты поиска в "}.
|
||||||
|
|
||||||
{"User", "Пользователь"}.
|
{"User", "Пользователь"}.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
erl -noinput -sname ejabberdctl -s ejabberd_ctl -extra $@
|
exec erl -noinput -sname ejabberdctl -s ejabberd_ctl -extra $@
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user