mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-22 17:28:25 +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>
|
||||
|
||||
* 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
|
||||
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.
|
||||
\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}
|
||||
|
||||
Example:
|
||||
@ -1138,7 +1140,7 @@ Example:
|
||||
{modules,
|
||||
[
|
||||
...
|
||||
{mod_vcard, [{search, false}]}
|
||||
{mod_vcard, [{search, false}, {matches, 20}]}
|
||||
...
|
||||
]}.
|
||||
\end{verbatim}
|
||||
|
@ -11,124 +11,166 @@
|
||||
|
||||
-export([start/0]).
|
||||
|
||||
-define(STATUS_SUCCESS, 0).
|
||||
-define(STATUS_ERROR, 1).
|
||||
-define(STATUS_USAGE, 2).
|
||||
-define(STATUS_BADRPC, 3).
|
||||
|
||||
start() ->
|
||||
case init:get_plain_arguments() of
|
||||
[SNode | Args] ->
|
||||
Node = list_to_atom(SNode),
|
||||
process(Node, Args);
|
||||
Status = process(Node, Args),
|
||||
halt(Status);
|
||||
_ ->
|
||||
print_usage()
|
||||
end,
|
||||
halt().
|
||||
print_usage(),
|
||||
halt(?STATUS_USAGE)
|
||||
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"]) ->
|
||||
case rpc:call(Node, init, stop, []) of
|
||||
{badrpc, Reason} ->
|
||||
io:format("Can't stop node ~p: ~p~n",
|
||||
[Node, Reason]);
|
||||
[Node, Reason]),
|
||||
?STATUS_BADRPC;
|
||||
_ ->
|
||||
ok
|
||||
?STATUS_SUCCESS
|
||||
end;
|
||||
|
||||
process(Node, ["restart"]) ->
|
||||
case rpc:call(Node, init, restart, []) of
|
||||
{badrpc, Reason} ->
|
||||
io:format("Can't restart node ~p: ~p~n",
|
||||
[Node, Reason]);
|
||||
[Node, Reason]),
|
||||
?STATUS_BADRPC;
|
||||
_ ->
|
||||
ok
|
||||
?STATUS_SUCCESS
|
||||
end;
|
||||
|
||||
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]) ->
|
||||
case rpc:call(Node, ejabberd_auth, try_register, [User, Password]) of
|
||||
{atomic, ok} ->
|
||||
ok;
|
||||
?STATUS_SUCCESS;
|
||||
{atomic, exists} ->
|
||||
io:format("User ~p already registered on node ~p~n",
|
||||
[User, Node]);
|
||||
[User, Node]),
|
||||
?STATUS_ERROR;
|
||||
{error, Reason} ->
|
||||
io:format("Can't register user ~p on node ~p: ~p~n",
|
||||
[User, Node, Reason]);
|
||||
[User, Node, Reason]),
|
||||
?STATUS_ERROR;
|
||||
{badrpc, Reason} ->
|
||||
io:format("Can't register user ~p on node ~p: ~p~n",
|
||||
[User, Node, Reason])
|
||||
[User, Node, Reason]),
|
||||
?STATUS_BADRPC
|
||||
end;
|
||||
|
||||
process(Node, ["unregister", User]) ->
|
||||
case rpc:call(Node, ejabberd_auth, remove_user, [User]) of
|
||||
{atomic, ok} ->
|
||||
ok;
|
||||
?STATUS_SUCCESS;
|
||||
{error, Reason} ->
|
||||
io:format("Can't unregister user ~p on node ~p: ~p~n",
|
||||
[User, Node, Reason]);
|
||||
[User, Node, Reason]),
|
||||
?STATUS_ERROR;
|
||||
{badrpc, Reason} ->
|
||||
io:format("Can't unregister user ~p on node ~p: ~p~n",
|
||||
[User, Node, Reason])
|
||||
[User, Node, Reason]),
|
||||
?STATUS_BADRPC
|
||||
end;
|
||||
|
||||
process(Node, ["backup", Path]) ->
|
||||
case rpc:call(Node, mnesia, backup, [Path]) of
|
||||
ok ->
|
||||
ok;
|
||||
?STATUS_SUCCESS;
|
||||
{error, Reason} ->
|
||||
io:format("Can't store backup in ~p on node ~p: ~p~n",
|
||||
[Path, Node, Reason]);
|
||||
[Path, Node, Reason]),
|
||||
?STATUS_ERROR;
|
||||
{badrpc, Reason} ->
|
||||
io:format("Can't store backup in ~p on node ~p: ~p~n",
|
||||
[Path, Node, Reason])
|
||||
[Path, Node, Reason]),
|
||||
?STATUS_BADRPC
|
||||
end;
|
||||
|
||||
process(Node, ["dump", Path]) ->
|
||||
case rpc:call(Node, mnesia, dump_to_textfile, [Path]) of
|
||||
ok ->
|
||||
ok;
|
||||
?STATUS_SUCCESS;
|
||||
{error, Reason} ->
|
||||
io:format("Can't store dump in ~p on node ~p: ~p~n",
|
||||
[Path, Node, Reason]);
|
||||
[Path, Node, Reason]),
|
||||
?STATUS_ERROR;
|
||||
{badrpc, Reason} ->
|
||||
io:format("Can't store dump in ~p on node ~p: ~p~n",
|
||||
[Path, Node, Reason])
|
||||
[Path, Node, Reason]),
|
||||
?STATUS_BADRPC
|
||||
end;
|
||||
|
||||
process(Node, ["load", Path]) ->
|
||||
case rpc:call(Node, mnesia, load_textfile, [Path]) of
|
||||
ok ->
|
||||
ok;
|
||||
?STATUS_SUCCESS;
|
||||
{error, Reason} ->
|
||||
io:format("Can't load dump in ~p on node ~p: ~p~n",
|
||||
[Path, Node, Reason]);
|
||||
[Path, Node, Reason]),
|
||||
?STATUS_ERROR;
|
||||
{badrpc, Reason} ->
|
||||
io:format("Can't load dump in ~p on node ~p: ~p~n",
|
||||
[Path, Node, Reason])
|
||||
[Path, Node, Reason]),
|
||||
?STATUS_BADRPC
|
||||
end;
|
||||
|
||||
process(Node, ["restore", Path]) ->
|
||||
case rpc:call(Node,
|
||||
mnesia, restore, [Path, [{default_op, keep_tables}]]) of
|
||||
{atomic, ok} ->
|
||||
ok;
|
||||
?STATUS_SUCCESS;
|
||||
{error, Reason} ->
|
||||
io:format("Can't restore backup from ~p on node ~p: ~p~n",
|
||||
[Path, Node, Reason]);
|
||||
[Path, Node, Reason]),
|
||||
?STATUS_ERROR;
|
||||
{badrpc, Reason} ->
|
||||
io:format("Can't restore backup from ~p on node ~p: ~p~n",
|
||||
[Path, Node, Reason])
|
||||
[Path, Node, Reason]),
|
||||
?STATUS_BADRPC
|
||||
end;
|
||||
|
||||
process(Node, ["install-fallback", Path]) ->
|
||||
case rpc:call(Node, mnesia, install_fallback, [Path]) of
|
||||
{atomic, ok} ->
|
||||
ok;
|
||||
?STATUS_SUCCESS;
|
||||
{error, Reason} ->
|
||||
io:format("Can't install fallback from ~p on node ~p: ~p~n",
|
||||
[Path, Node, Reason]);
|
||||
[Path, Node, Reason]),
|
||||
?STATUS_ERROR;
|
||||
{badrpc, Reason} ->
|
||||
io:format("Can't install fallback from ~p on node ~p: ~p~n",
|
||||
[Path, Node, Reason])
|
||||
[Path, Node, Reason]),
|
||||
?STATUS_BADRPC
|
||||
end;
|
||||
|
||||
process(Node, ["registered-users"]) ->
|
||||
@ -138,14 +180,30 @@ process(Node, ["registered-users"]) ->
|
||||
SUsers = lists:sort(Users),
|
||||
FUsers = lists:map(fun(U) -> [U, NewLine] end, SUsers),
|
||||
io:format("~s", [FUsers]),
|
||||
ok;
|
||||
{ErrorTag, Reason} when (ErrorTag == error) or (ErrorTag == badrpc) ->
|
||||
?STATUS_SUCCESS;
|
||||
{error, Reason} ->
|
||||
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;
|
||||
|
||||
process(_Node, _Args) ->
|
||||
print_usage().
|
||||
print_usage(),
|
||||
?STATUS_USAGE.
|
||||
|
||||
|
||||
|
||||
@ -154,6 +212,7 @@ print_usage() ->
|
||||
"Usage: ejabberdctl node command~n"
|
||||
"~n"
|
||||
"Available commands:~n"
|
||||
" status\t\t\tget ejabberd status~n"
|
||||
" stop\t\t\t\tstop ejabberd~n"
|
||||
" restart\t\t\trestart ejabberd~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"
|
||||
" load file\t\t\trestore a database from a text file~n"
|
||||
" registered-users\t\tlist all registered users~n"
|
||||
" delete-expired-messages\tdelete expired offline messages from database~n"
|
||||
"~n"
|
||||
"Example:~n"
|
||||
" ejabberdctl ejabberd@host restart~n"
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
%% gen_event callbacks
|
||||
-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}).
|
||||
|
||||
@ -89,6 +89,9 @@ terminate(_Reason, _State) ->
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
reopen_log() ->
|
||||
error_logger ! {emulator, noproc, reopen}.
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% Internal functions
|
||||
%%%----------------------------------------------------------------------
|
||||
|
@ -21,6 +21,7 @@
|
||||
-define(NS_XDATA, "jabber:x:data").
|
||||
-define(NS_IQDATA, "jabber:iq:data").
|
||||
-define(NS_DELAY, "jabber:x:delay").
|
||||
-define(NS_EXPIRE, "jabber:x:expire").
|
||||
-define(NS_EVENT, "jabber:x:event").
|
||||
-define(NS_XCONFERENCE, "jabber:x:conference").
|
||||
-define(NS_STATS, "http://jabber.org/protocol/stats").
|
||||
|
@ -17,12 +17,14 @@
|
||||
store_packet/3,
|
||||
resend_offline_messages/1,
|
||||
pop_offline_messages/2,
|
||||
remove_expired_messages/0,
|
||||
remove_old_messages/1,
|
||||
remove_user/1]).
|
||||
|
||||
-include("ejabberd.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(OFFLINE_TABLE_LOCK_THRESHOLD, 1000).
|
||||
@ -32,6 +34,7 @@ start(_) ->
|
||||
[{disc_only_copies, [node()]},
|
||||
{type, bag},
|
||||
{attributes, record_info(fields, offline_msg)}]),
|
||||
update_table(),
|
||||
ejabberd_hooks:add(offline_message_hook,
|
||||
?MODULE, store_packet, 50),
|
||||
ejabberd_hooks:add(offline_subscription_hook,
|
||||
@ -92,8 +95,11 @@ store_packet(From, To, Packet) ->
|
||||
true ->
|
||||
#jid{luser = LUser} = To,
|
||||
TimeStamp = now(),
|
||||
{xmlelement, _Name, _Attrs, Els} = Packet,
|
||||
Expire = find_x_expire(TimeStamp, Els),
|
||||
?PROCNAME ! #offline_msg{user = LUser,
|
||||
timestamp = TimeStamp,
|
||||
expire = Expire,
|
||||
from = From,
|
||||
to = To,
|
||||
packet = Packet},
|
||||
@ -150,6 +156,34 @@ find_x_event([El | Els]) ->
|
||||
find_x_event(Els)
|
||||
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) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
@ -187,23 +221,54 @@ pop_offline_messages(Ls, User) ->
|
||||
end,
|
||||
case mnesia:transaction(F) of
|
||||
{atomic, Rs} ->
|
||||
lists:map(
|
||||
fun(R) ->
|
||||
{xmlelement, Name, Attrs, Els} = R#offline_msg.packet,
|
||||
{route,
|
||||
R#offline_msg.from,
|
||||
R#offline_msg.to,
|
||||
{xmlelement, Name, Attrs,
|
||||
Els ++
|
||||
[jlib:timestamp_to_xml(
|
||||
calendar:now_to_universal_time(
|
||||
R#offline_msg.timestamp))]}}
|
||||
end,
|
||||
Ls ++ lists:keysort(#offline_msg.timestamp, Rs));
|
||||
TS = now(),
|
||||
Ls ++ lists:map(
|
||||
fun(R) ->
|
||||
{xmlelement, Name, Attrs, Els} = R#offline_msg.packet,
|
||||
{route,
|
||||
R#offline_msg.from,
|
||||
R#offline_msg.to,
|
||||
{xmlelement, Name, Attrs,
|
||||
Els ++
|
||||
[jlib:timestamp_to_xml(
|
||||
calendar:now_to_universal_time(
|
||||
R#offline_msg.timestamp))]}}
|
||||
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
|
||||
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) ->
|
||||
{MegaSecs, Secs, _MicroSecs} = now(),
|
||||
S = MegaSecs * 1000000 + Secs - 60 * 60 * 24 * Days,
|
||||
@ -227,3 +292,29 @@ remove_user(User) ->
|
||||
mnesia:delete({offline_msg, LUser})
|
||||
end,
|
||||
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
|
||||
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% Purpose :
|
||||
%%% Purpose : Roster management
|
||||
%%% Created : 11 Dec 2002 by Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% 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) ->
|
||||
#jid{luser = LUser} = From,
|
||||
F = fun() ->
|
||||
mnesia:index_read(roster, LUser, #roster.user)
|
||||
end,
|
||||
case mnesia:transaction(F) of
|
||||
{atomic, Items} ->
|
||||
case catch mnesia:dirty_index_read(roster, LUser, #roster.user) of
|
||||
Items when is_list(Items) ->
|
||||
XItems = lists:map(fun item_to_xml/1, Items),
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
@ -316,11 +313,8 @@ push_item(User, Resource, From, Item) ->
|
||||
|
||||
get_subscription_lists(User) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
F = fun() ->
|
||||
mnesia:index_read(roster, LUser, #roster.user)
|
||||
end,
|
||||
case mnesia:transaction(F) of
|
||||
{atomic, Items} ->
|
||||
case mnesia:dirty_index_read(roster, LUser, #roster.user) of
|
||||
Items when is_list(Items) ->
|
||||
fill_subscription_lists(Items, [], []);
|
||||
_ ->
|
||||
{[], []}
|
||||
|
@ -22,7 +22,8 @@
|
||||
-include("jlib.hrl").
|
||||
|
||||
|
||||
%-define(JUD_ALLOW_RETURN_ALL, true)
|
||||
%-define(JUD_ALLOW_RETURN_ALL, true).
|
||||
-define(JUD_MATCHES, 30).
|
||||
|
||||
-record(vcard_search, {user, luser,
|
||||
fn, lfn,
|
||||
@ -234,8 +235,10 @@ set_vcard(User, VCARD) ->
|
||||
[{xmlcdata, translate:translate(Lang, "Search users in ") ++
|
||||
jlib:jid_to_string(JID)}]},
|
||||
{xmlelement, "instructions", [],
|
||||
[{xmlcdata, translate:translate(Lang, "Fill in fields to search "
|
||||
"for any matching Jabber User")}]},
|
||||
[{xmlcdata, translate:translate(Lang, "Fill in the form to search "
|
||||
"for any matching Jabber User "
|
||||
"(Add * to the end of field to "
|
||||
"match substring)")}]},
|
||||
?TLFIELD("text-single", "User", "user"),
|
||||
?TLFIELD("text-single", "Full Name", "fn"),
|
||||
?TLFIELD("text-single", "Name", "given"),
|
||||
@ -452,7 +455,17 @@ search(Data) ->
|
||||
?ERROR_MSG("~p", [Reason]),
|
||||
[];
|
||||
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.
|
||||
|
||||
-else.
|
||||
@ -469,7 +482,17 @@ search(Data) ->
|
||||
?ERROR_MSG("~p", [Reason]),
|
||||
[];
|
||||
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.
|
||||
|
||||
@ -499,24 +522,31 @@ filter_fields([{SVar, [Val]} | Ds], Match)
|
||||
when is_list(Val) and (Val /= "") ->
|
||||
LVal = stringprep:tolower(Val),
|
||||
NewMatch = case SVar of
|
||||
"user" -> Match#vcard_search{luser = LVal};
|
||||
"fn" -> Match#vcard_search{lfn = LVal};
|
||||
"family" -> Match#vcard_search{lfamily = LVal};
|
||||
"given" -> Match#vcard_search{lgiven = LVal};
|
||||
"middle" -> Match#vcard_search{lmiddle = LVal};
|
||||
"nickname" -> Match#vcard_search{lnickname = LVal};
|
||||
"bday" -> Match#vcard_search{lbday = LVal};
|
||||
"ctry" -> Match#vcard_search{lctry = LVal};
|
||||
"locality" -> Match#vcard_search{llocality = LVal};
|
||||
"email" -> Match#vcard_search{lemail = LVal};
|
||||
"orgname" -> Match#vcard_search{lorgname = LVal};
|
||||
"orgunit" -> Match#vcard_search{lorgunit = LVal};
|
||||
"user" -> Match#vcard_search{luser = make_val(LVal)};
|
||||
"fn" -> Match#vcard_search{lfn = make_val(LVal)};
|
||||
"family" -> Match#vcard_search{lfamily = make_val(LVal)};
|
||||
"given" -> Match#vcard_search{lgiven = make_val(LVal)};
|
||||
"middle" -> Match#vcard_search{lmiddle = make_val(LVal)};
|
||||
"nickname" -> Match#vcard_search{lnickname = make_val(LVal)};
|
||||
"bday" -> Match#vcard_search{lbday = make_val(LVal)};
|
||||
"ctry" -> Match#vcard_search{lctry = make_val(LVal)};
|
||||
"locality" -> Match#vcard_search{llocality = make_val(LVal)};
|
||||
"email" -> Match#vcard_search{lemail = make_val(LVal)};
|
||||
"orgname" -> Match#vcard_search{lorgname = make_val(LVal)};
|
||||
"orgunit" -> Match#vcard_search{lorgunit = make_val(LVal)};
|
||||
_ -> Match
|
||||
end,
|
||||
filter_fields(Ds, NewMatch);
|
||||
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",
|
||||
"Чтобы воспользоваться поиском, требуется x:data-совместимый клиент"}.
|
||||
{"Search users in ", "Поиск пользователей в "}.
|
||||
{"Fill in fields to search for any matching Jabber User",
|
||||
"Заполните поля для поиска пользователя Jabber"}.
|
||||
{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)",
|
||||
"Заполните форму для поиска пользователя Jabber (Если добавить * в конец поля, то происходит поиск подстроки)"}.
|
||||
{"Results of search in ", "Результаты поиска в "}.
|
||||
|
||||
{"User", "Пользователь"}.
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/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