3 |
%%% Author : Badlop <badlop@ono.com> |
%%% Author : Badlop <badlop@ono.com> |
4 |
%%% Purpose : Adds more commands to ejabberd_ctl |
%%% Purpose : Adds more commands to ejabberd_ctl |
5 |
%%% Created : 30 Nov 2006 by Badlop <badlop@ono.com> |
%%% Created : 30 Nov 2006 by Badlop <badlop@ono.com> |
6 |
%%% Id : $Id$ |
%%% Id : $Id: mod_ctlextra.erl 873 2009-02-09 18:30:21Z badlop $ |
7 |
%%%---------------------------------------------------------------------- |
%%%---------------------------------------------------------------------- |
8 |
|
|
9 |
-module(mod_ctlextra). |
-module(mod_ctlextra). |
10 |
-author('badlop@ono.com'). |
-author('badlop@ono.com'). |
|
-vsn('$Revision$ '). |
|
11 |
|
|
12 |
-behaviour(gen_mod). |
-behaviour(gen_mod). |
13 |
|
|
22 |
-include("jlib.hrl"). |
-include("jlib.hrl"). |
23 |
-include("mod_roster.hrl"). |
-include("mod_roster.hrl"). |
24 |
|
|
25 |
-record(session, {sid, usr, us, priority}). % copied from ejabberd_sm.erl |
%% Copied from ejabberd_sm.erl |
26 |
|
-record(session, {sid, usr, us, priority, info}). |
27 |
|
|
28 |
|
-compile(export_all). |
29 |
|
|
30 |
|
%%------------- |
31 |
|
%% gen_mod |
32 |
|
%%------------- |
33 |
|
|
34 |
start(Host, _Opts) -> |
start(Host, _Opts) -> |
35 |
ejabberd_ctl:register_commands([ |
ejabberd_ctl:register_commands(commands_global(), ?MODULE, ctl_process), |
36 |
{"compile file", "recompile and reload file"}, |
ejabberd_ctl:register_commands(Host, commands_host(), ?MODULE, ctl_process). |
|
{"load-config file", "load config from file"}, |
|
|
{"remove-node nodename", "remove an ejabberd node from the database"}, |
|
|
|
|
|
%% ejabberd_auth |
|
|
{"delete-older-users days", "delete users that have not logged in the last 'days'"}, |
|
|
{"set-password user server password", "set password to user@server"}, |
|
|
|
|
|
%% ejd2odbc |
|
|
{"export2odbc server output", "export Mnesia tables on server to files on output directory"}, |
|
|
|
|
|
%% mod_offline |
|
|
{"delete-older-messages days", "delete offline messages older than 'days'"}, |
|
|
|
|
|
%% mod_shared_roster |
|
|
{"srg-create group host name description display", "create the group with options"}, |
|
|
{"srg-delete group host", "delete the group"}, |
|
|
{"srg-user-add user server group host", "add user@server to group on host"}, |
|
|
{"srg-user-del user server group host", "delete user@server from group on host"}, |
|
|
|
|
|
%% mod_vcard |
|
|
{"vcard-get user host data [data2]", "get data from the vCard of the user"}, |
|
|
{"vcard-set user host data [data2] content", "set data to content on the vCard"}, |
|
|
|
|
|
%% mod_announce |
|
|
%% announce_send_online host message |
|
|
%% announce_send_all host, message |
|
|
|
|
|
%% mod_muc |
|
|
%% muc-add room opts |
|
|
%% muc-del room |
|
|
{"muc-purge days", "destroy rooms with not activity on the last 'days'"}, |
|
|
{"muc-online-rooms", "list existing rooms"}, |
|
|
|
|
|
%% mod_roster |
|
|
{"add-rosteritem user1 server1 user2 server2 nick group subs", "Add user2@server2 to user1@server1's roster"}, |
|
|
%%{"", "subs= none, from, to or both"}, |
|
|
%%{"", "example: add-roster peter localhost mike server.com MiKe Employees both"}, |
|
|
%%{"", "will add mike@server.com to peter@localhost roster"}, |
|
|
{"rem-rosteritem user1 server1 user2 server2", "Remove user2@server2 from user1@server1's roster"}, |
|
|
{"pushroster file user server", "push template roster in file to user@server"}, |
|
|
{"pushroster-all file", "push template roster in file to all those users"}, |
|
|
{"push-alltoall server group", "adds all the users to all the users in Group"}, |
|
|
|
|
|
{"status-list status", "list the logged users with status"}, |
|
|
{"status-num status", "number of logged users with status"}, |
|
|
|
|
|
{"stats registeredusers", "number of registered users"}, |
|
|
{"stats onlineusers", "number of logged users"}, |
|
|
{"stats uptime-seconds", "uptime of ejabberd node in seconds"}, |
|
|
|
|
|
%% misc |
|
|
{"get-cookie", "get the Erlang cookie of this node"}, |
|
|
{"killsession user server resource", "kill a user session"} |
|
|
], ?MODULE, ctl_process), |
|
|
ejabberd_ctl:register_commands(Host, [ |
|
|
%% mod_muc |
|
|
{"muc-purge days", "destroy rooms with not activity on the last 'days'"}, |
|
|
{"muc-online-rooms", "list existing rooms"}, |
|
|
|
|
|
%% mod_last |
|
|
{"num-active-users days", "number of users active in the last 'days'"}, |
|
|
{"status-list status", "list the logged users with status"}, |
|
|
{"status-num status", "number of logged users with status"}, |
|
|
{"stats registeredusers", "number of registered users"}, |
|
|
{"stats onlineusers", "number of logged users"} |
|
|
], ?MODULE, ctl_process), |
|
|
ok. |
|
|
|
|
|
stop(_Host) -> |
|
|
ok. |
|
|
|
|
|
|
|
|
ctl_process(_Val, ["blo"]) -> |
|
|
FResources = "eeeaaa aaa", |
|
|
io:format("~s", [FResources]), |
|
|
?STATUS_SUCCESS; |
|
37 |
|
|
38 |
ctl_process(_Val, ["delete-older-messages", Days]) -> |
stop(Host) -> |
39 |
mod_offline:remove_old_messages(list_to_integer(Days)), |
ejabberd_ctl:unregister_commands(commands_global(), ?MODULE, ctl_process), |
40 |
?STATUS_SUCCESS; |
ejabberd_ctl:unregister_commands(Host, commands_host(), ?MODULE, ctl_process). |
41 |
|
|
42 |
|
commands_global() -> |
43 |
|
[ |
44 |
|
{"compile file", "recompile and reload file"}, |
45 |
|
{"load-config file", "load config from file"}, |
46 |
|
{"remove-node nodename", "remove an ejabberd node from the database"}, |
47 |
|
|
48 |
|
%% ejabberd_auth |
49 |
|
{"delete-older-users days", "delete users that have not logged in the last 'days'"}, |
50 |
|
{"delete-older-users-vhost host days", "delete users that not logged in last 'days' in 'host'"}, |
51 |
|
{"set-password user server password", "set password to user@server"}, |
52 |
|
|
53 |
|
%% ejd2odbc |
54 |
|
{"export2odbc server output", "export Mnesia tables on server to files on output directory"}, |
55 |
|
|
56 |
|
%% mod_shared_roster |
57 |
|
{"srg-create group host name description display", "create the group with options"}, |
58 |
|
{"srg-delete group host", "delete the group"}, |
59 |
|
{"srg-user-add user server group host", "add user@server to group on host"}, |
60 |
|
{"srg-user-del user server group host", "delete user@server from group on host"}, |
61 |
|
{"srg-list-groups host", "list the shared roster groups from host"}, |
62 |
|
{"srg-get-info group host", "get info of a specific group on host"}, |
63 |
|
|
64 |
|
%% mod_vcard |
65 |
|
{"vcard-get user host data [data2]", "get data from the vCard of the user"}, |
66 |
|
{"vcard-set user host data [data2] content", "set data to content on the vCard"}, |
67 |
|
|
68 |
|
%% mod_announce |
69 |
|
%% announce_send_online host message |
70 |
|
%% announce_send_all host, message |
71 |
|
|
72 |
|
%% mod_roster |
73 |
|
{"add-rosteritem user1 server1 user2 server2 nick group subs", "Add user2@server2 to user1@server1's roster"}, |
74 |
|
%%{"", "subs= none, from, to or both"}, |
75 |
|
%%{"", "example: add-roster peter localhost mike server.com MiKe Employees both"}, |
76 |
|
%%{"", "will add mike@server.com to peter@localhost roster"}, |
77 |
|
{"rem-rosteritem user1 server1 user2 server2", "Remove user2@server2 from user1@server1's roster"}, |
78 |
|
{"rosteritem-purge [options]", "Purge all rosteritems that match filtering options"}, |
79 |
|
{"pushroster file user server", "push template roster in file to user@server"}, |
80 |
|
{"pushroster-all file", "push template roster in file to all those users"}, |
81 |
|
{"push-alltoall server group", "adds all the users to all the users in Group"}, |
82 |
|
|
83 |
|
{"status-list status", "list the logged users with status"}, |
84 |
|
{"status-num status", "number of logged users with status"}, |
85 |
|
|
86 |
|
{"stats registeredusers", "number of registered users"}, |
87 |
|
{"stats onlineusers", "number of logged users"}, |
88 |
|
{"stats onlineusersnode", "number of logged users in the ejabberd node"}, |
89 |
|
{"stats uptime-seconds", "uptime of ejabberd node in seconds"}, |
90 |
|
|
91 |
|
%% misc |
92 |
|
{"get-cookie", "get the Erlang cookie of this node"}, |
93 |
|
{"killsession user server resource", "kill a user session"} |
94 |
|
]. |
95 |
|
|
96 |
|
commands_host() -> |
97 |
|
[ |
98 |
|
%% mod_last |
99 |
|
{"num-active-users days", "number of users active in the last 'days'"}, |
100 |
|
{"status-list status", "list the logged users with status"}, |
101 |
|
{"status-num status", "number of logged users with status"}, |
102 |
|
{"stats registeredusers", "number of registered users"}, |
103 |
|
{"stats onlineusers", "number of logged users"}, |
104 |
|
|
105 |
|
%% misc |
106 |
|
{"ban-account username [reason]", "ban account: kick sessions and change password"} |
107 |
|
]. |
108 |
|
|
109 |
|
|
110 |
|
%%------------- |
111 |
|
%% Commands global |
112 |
|
%%------------- |
113 |
|
|
114 |
ctl_process(_Val, ["delete-older-users", Days]) -> |
ctl_process(_Val, ["delete-older-users", Days]) -> |
115 |
{removed, N, UR} = delete_older_users(list_to_integer(Days)), |
{removed, N, UR} = delete_older_users(list_to_integer(Days)), |
116 |
io:format("Deleted ~p users: ~p~n", [N, UR]), |
io:format("Deleted ~p users: ~p~n", [N, UR]), |
117 |
?STATUS_SUCCESS; |
?STATUS_SUCCESS; |
118 |
|
|
119 |
|
ctl_process(_Val, ["delete-older-users-vhost", Host, Days]) -> |
120 |
|
{removed, N, UR} = delete_older_users_vhost(Host, list_to_integer(Days)), |
121 |
|
io:format("Deleted ~p users: ~p~n", [N, UR]), |
122 |
|
?STATUS_SUCCESS; |
123 |
|
|
124 |
ctl_process(_Val, ["export2odbc", Server, Output]) -> |
ctl_process(_Val, ["export2odbc", Server, Output]) -> |
125 |
Tables = [ |
Tables = [ |
126 |
{export_last, last}, |
{export_last, last}, |
133 |
Export = fun({TableFun, Table}) -> |
Export = fun({TableFun, Table}) -> |
134 |
Filename = filename:join([Output, atom_to_list(Table)++".txt"]), |
Filename = filename:join([Output, atom_to_list(Table)++".txt"]), |
135 |
io:format("Trying to export Mnesia table '~p' on server '~s' to file '~s'~n", [Table, Server, Filename]), |
io:format("Trying to export Mnesia table '~p' on server '~s' to file '~s'~n", [Table, Server, Filename]), |
136 |
catch ejd2odbc:TableFun(Server, Filename) |
Res = (catch ejd2odbc:TableFun(Server, Filename)), |
137 |
|
io:format(" Result: ~p~n", [Res]) |
138 |
end, |
end, |
139 |
lists:foreach(Export, Tables), |
lists:foreach(Export, Tables), |
140 |
?STATUS_SUCCESS; |
?STATUS_SUCCESS; |
171 |
mnesia:del_table_copy(schema, list_to_atom(Node)), |
mnesia:del_table_copy(schema, list_to_atom(Node)), |
172 |
?STATUS_SUCCESS; |
?STATUS_SUCCESS; |
173 |
|
|
174 |
ctl_process(_Val, ["srg-create", Group, Host, Name, Description, Display]) -> |
ctl_process(_Val, ["srg-create" | Parameters]) -> |
175 |
|
[Group, Host, Name, Description, Display] = group_parameters(Parameters, "'"), |
176 |
Opts = [{name, Name}, {displayed_groups, [Display]}, {description, Description}], |
Opts = [{name, Name}, {displayed_groups, [Display]}, {description, Description}], |
177 |
{atomic, ok} = mod_shared_roster:create_group(Host, Group, Opts), |
{atomic, ok} = mod_shared_roster:create_group(Host, Group, Opts), |
178 |
?STATUS_SUCCESS; |
?STATUS_SUCCESS; |
189 |
{atomic, ok} = mod_shared_roster:remove_user_from_group(Host, {User, Server}, Group), |
{atomic, ok} = mod_shared_roster:remove_user_from_group(Host, {User, Server}, Group), |
190 |
?STATUS_SUCCESS; |
?STATUS_SUCCESS; |
191 |
|
|
192 |
ctl_process(_Val, ["muc-purge", Days]) -> |
ctl_process(_Val, ["srg-list-groups", Host]) -> |
193 |
{purged, Num_total, Num_purged, Names_purged} = muc_purge(list_to_integer(Days)), |
lists:foreach( |
194 |
io:format("Purged ~p chatrooms from a total of ~p on the server:~n~p~n", [Num_purged, Num_total, Names_purged]), |
fun(SrgGroup) -> |
195 |
|
io:format("~s~n",[SrgGroup]) |
196 |
|
end, |
197 |
|
lists:sort(mod_shared_roster:list_groups(Host))), |
198 |
?STATUS_SUCCESS; |
?STATUS_SUCCESS; |
199 |
|
|
200 |
ctl_process(_Val, ["muc-online-rooms"]) -> |
ctl_process(_Val, ["srg-get-info", Group, Host]) -> |
201 |
format_print_room(all, ets:tab2list(muc_online_room)), |
Opts = mod_shared_roster:get_group_opts(Host,Group), |
202 |
|
[io:format("~s: ~p~n", [Title, Value]) || {Title , Value} <- Opts], |
203 |
|
|
204 |
|
Members = mod_shared_roster:get_group_explicit_users(Host,Group), |
205 |
|
Members_string = [ " " ++ jlib:jid_to_string(jlib:make_jid(MUser, MServer, "")) |
206 |
|
|| {MUser, MServer} <- Members], |
207 |
|
io:format("members:~s~n", [Members_string]), |
208 |
|
|
209 |
?STATUS_SUCCESS; |
?STATUS_SUCCESS; |
210 |
|
|
211 |
ctl_process(_Val, ["add-rosteritem", LocalUser, LocalServer, RemoteUser, RemoteServer, Nick, Group, Subs]) -> |
ctl_process(_Val, ["add-rosteritem", LocalUser, LocalServer, RemoteUser, RemoteServer, Nick, Group, Subs]) -> |
236 |
?STATUS_BADRPC |
?STATUS_BADRPC |
237 |
end; |
end; |
238 |
|
|
239 |
|
ctl_process(_Val, ["rosteritem-purge"]) -> |
240 |
|
io:format("Rosteritems that match all the filtering will be removed.~n"), |
241 |
|
io:format("Options for filtering:~n"), |
242 |
|
io:format("~n"), |
243 |
|
io:format(" -subs none|from|to|both~n"), |
244 |
|
io:format(" Subscription type. By default all values~n"), |
245 |
|
io:format("~n"), |
246 |
|
io:format(" -ask none|out|in~n"), |
247 |
|
io:format(" Pending subscription. By default all values~n"), |
248 |
|
io:format("~n"), |
249 |
|
io:format(" -user JID~n"), |
250 |
|
io:format(" The JID of the local user.~n"), |
251 |
|
io:format(" Can use these globs: *, ? and [...].~n"), |
252 |
|
io:format(" By default it is: * *@*~n"), |
253 |
|
io:format("~n"), |
254 |
|
io:format(" -contact JID~n"), |
255 |
|
io:format(" Similar to 'user', but for the contact JID.~n"), |
256 |
|
io:format("~n"), |
257 |
|
io:format("Example:~n"), |
258 |
|
io:format(" ejabberdctl rosteritem-purge -subs none from to -ask out in -contact *@*icq*~n"), |
259 |
|
io:format("~n"), |
260 |
|
?STATUS_SUCCESS; |
261 |
|
ctl_process(_Val, ["rosteritem-purge" | Options_list]) -> |
262 |
|
Options_prop_list = lists:foldl( |
263 |
|
fun(O, R) -> |
264 |
|
case O of |
265 |
|
[$- | K] -> |
266 |
|
[{K, []} | R]; |
267 |
|
V -> |
268 |
|
[{K, Vs} | RT] = R, |
269 |
|
[{K, [V|Vs]} | RT] |
270 |
|
end |
271 |
|
end, |
272 |
|
[], |
273 |
|
Options_list), |
274 |
|
|
275 |
|
Subs = [list_to_atom(S) |
276 |
|
|| S <- proplists:get_value("subs", |
277 |
|
Options_prop_list, |
278 |
|
["none", "from", "to", "both"])], |
279 |
|
Asks = [list_to_atom(S) |
280 |
|
|| S <- |
281 |
|
proplists:get_value("ask", |
282 |
|
Options_prop_list, |
283 |
|
["none", "out", "in"])], |
284 |
|
User = proplists:get_value("user", Options_prop_list, ["*", "*@*"]), |
285 |
|
Contact = proplists:get_value("contact", Options_prop_list, ["*", "*@*"]), |
286 |
|
|
287 |
|
case rosteritem_purge({Subs, Asks, User, Contact}) of |
288 |
|
{atomic, ok} -> |
289 |
|
?STATUS_SUCCESS; |
290 |
|
{error, Reason} -> |
291 |
|
io:format("Error purging rosteritems: ~p~n", |
292 |
|
[Reason]), |
293 |
|
?STATUS_ERROR; |
294 |
|
{badrpc, Reason} -> |
295 |
|
io:format("BadRPC purging rosteritems: ~p~n", |
296 |
|
[Reason]), |
297 |
|
?STATUS_BADRPC |
298 |
|
end; |
299 |
|
|
300 |
ctl_process(_Val, ["pushroster", File, User, Server]) -> |
ctl_process(_Val, ["pushroster", File, User, Server]) -> |
301 |
case pushroster(File, User, Server) of |
case pushroster(File, User, Server) of |
302 |
ok -> |
ok -> |
356 |
ctl_process(_Val, ["stats", Stat]) -> |
ctl_process(_Val, ["stats", Stat]) -> |
357 |
Res = case Stat of |
Res = case Stat of |
358 |
"uptime-seconds" -> uptime_seconds(); |
"uptime-seconds" -> uptime_seconds(); |
359 |
"registeredusers" -> mnesia:table_info(passwd, size); |
"registeredusers" -> length(ejabberd_auth:dirty_get_registered_users()); |
360 |
"onlineusers" -> mnesia:table_info(session, size) |
"onlineusersnode" -> length(ejabberd_sm:dirty_get_my_sessions_list()); |
361 |
|
"onlineusers" -> length(ejabberd_sm:dirty_get_sessions_list()) |
362 |
end, |
end, |
363 |
io:format("~p~n", [Res]), |
io:format("~p~n", [Res]), |
364 |
?STATUS_SUCCESS; |
?STATUS_SUCCESS; |
373 |
io:format("~s~n", [atom_to_list(erlang:get_cookie())]), |
io:format("~s~n", [atom_to_list(erlang:get_cookie())]), |
374 |
?STATUS_SUCCESS; |
?STATUS_SUCCESS; |
375 |
|
|
376 |
ctl_process(_Val, ["killsession", User, Server, Resource]) -> |
ctl_process(_Val, ["killsession", User, Server, Resource | Tail]) -> |
377 |
ejabberd_router:route( |
kick_session(User, Server, Resource, prepare_reason(Tail)), |
|
jlib:make_jid("", "", ""), |
|
|
jlib:make_jid(User, Server, Resource), |
|
|
{xmlelement, "broadcast", [], [{exit, "killed"}]}), |
|
378 |
?STATUS_SUCCESS; |
?STATUS_SUCCESS; |
379 |
|
|
380 |
ctl_process(Val, _Args) -> |
ctl_process(Val, _Args) -> |
381 |
Val. |
Val. |
382 |
|
|
383 |
|
|
384 |
ctl_process(_Val, Host, ["muc-purge", Days]) -> |
%%------------- |
385 |
{purged, Num_total, Num_purged, Names_purged} = muc_purge(Host, list_to_integer(Days)), |
%% Commands vhost |
386 |
io:format("Purged ~p chatrooms from a total of ~p on the host ~p:~n~p~n", [Num_purged, Num_total, Host, Names_purged]), |
%%------------- |
|
?STATUS_SUCCESS; |
|
|
|
|
|
ctl_process(_Val, ServerHost, ["muc-online-rooms"]) -> |
|
|
MUCHost = find_host(ServerHost), |
|
|
format_print_room(MUCHost, ets:tab2list(muc_online_room)), |
|
|
?STATUS_SUCCESS; |
|
387 |
|
|
388 |
ctl_process(_Val, Host, ["num-active-users", Days]) -> |
ctl_process(_Val, Host, ["num-active-users", Days]) -> |
389 |
Number = num_active_users(Host, list_to_integer(Days)), |
Number = num_active_users(Host, list_to_integer(Days)), |
408 |
[ io:format("~s@~s ~s ~p \"~s\"~n", [U, S, R, P, St]) || {U, S, R, P, St} <- Res], |
[ io:format("~s@~s ~s ~p \"~s\"~n", [U, S, R, P, St]) || {U, S, R, P, St} <- Res], |
409 |
?STATUS_SUCCESS; |
?STATUS_SUCCESS; |
410 |
|
|
411 |
|
ctl_process(_Val, Host, ["ban-account", User | Tail]) -> |
412 |
|
ban_account(User, Host, prepare_reason(Tail)), |
413 |
|
?STATUS_SUCCESS; |
414 |
|
|
415 |
ctl_process(Val, _Host, _Args) -> |
ctl_process(Val, _Host, _Args) -> |
416 |
Val. |
Val. |
417 |
|
|
418 |
|
|
419 |
%%------------- |
%%------------- |
420 |
%% UTILS |
%% Utils |
421 |
%%------------- |
%%------------- |
422 |
|
|
423 |
|
uptime_seconds() -> |
424 |
|
trunc(element(1, erlang:statistics(wall_clock))/1000). |
425 |
|
|
426 |
get_status_list(Host, Status_required) -> |
get_status_list(Host, Status_required) -> |
427 |
%% Get list of all logged users |
%% Get list of all logged users |
428 |
Sessions = ejabberd_sm:dirty_get_my_sessions_list(), |
Sessions = ejabberd_sm:dirty_get_my_sessions_list(), |
497 |
Packet = {xmlelement, "iq", [{"type", "set"}, {"to", ToS}], [Query]}, |
Packet = {xmlelement, "iq", [{"type", "set"}, {"to", ToS}], [Query]}, |
498 |
ejabberd_router:route(LJID, LJID, Packet). |
ejabberd_router:route(LJID, LJID, Packet). |
499 |
|
|
500 |
|
|
501 |
|
%%----------------------------- |
502 |
|
%% Ban user |
503 |
|
%%----------------------------- |
504 |
|
|
505 |
|
ban_account(User, Server, Reason) -> |
506 |
|
kick_sessions(User, Server, Reason), |
507 |
|
set_random_password(User, Server, Reason). |
508 |
|
|
509 |
|
kick_sessions(User, Server, Reason) -> |
510 |
|
lists:map( |
511 |
|
fun(Resource) -> |
512 |
|
kick_session(User, Server, Resource, Reason) |
513 |
|
end, |
514 |
|
get_resources(User, Server)). |
515 |
|
|
516 |
|
kick_session(User, Server, Resource, Reason) -> |
517 |
|
ejabberd_router:route( |
518 |
|
jlib:make_jid("", "", ""), |
519 |
|
jlib:make_jid(User, Server, Resource), |
520 |
|
{xmlelement, "broadcast", [], [{exit, Reason}]}). |
521 |
|
|
522 |
|
get_resources(User, Server) -> |
523 |
|
lists:map( |
524 |
|
fun(Session) -> |
525 |
|
element(3, Session#session.usr) |
526 |
|
end, |
527 |
|
get_sessions(User, Server)). |
528 |
|
|
529 |
|
get_sessions(User, Server) -> |
530 |
|
LUser = jlib:nodeprep(User), |
531 |
|
LServer = jlib:nameprep(Server), |
532 |
|
Sessions = mnesia:dirty_index_read(session, {LUser, LServer}, #session.us), |
533 |
|
true = is_list(Sessions), |
534 |
|
Sessions. |
535 |
|
|
536 |
|
set_random_password(User, Server, Reason) -> |
537 |
|
NewPass = build_random_password(Reason), |
538 |
|
set_password(User, Server, NewPass). |
539 |
|
|
540 |
|
build_random_password(Reason) -> |
541 |
|
Date = jlib:timestamp_to_iso(calendar:universal_time()), |
542 |
|
RandomString = randoms:get_string(), |
543 |
|
"BANNED_ACCOUNT--" ++ Date ++ "--" ++ RandomString ++ "--" ++ Reason. |
544 |
|
|
545 |
|
set_password(User, Server, Password) -> |
546 |
|
{atomic, ok} = ejabberd_auth:set_password(User, Server, Password). |
547 |
|
|
548 |
|
prepare_reason([]) -> |
549 |
|
"Kicked by administrator"; |
550 |
|
prepare_reason([Reason]) -> |
551 |
|
Reason; |
552 |
|
prepare_reason(StringList) -> |
553 |
|
string:join(StringList, "_"). |
554 |
|
|
555 |
|
|
556 |
|
%%----------------------------- |
557 |
|
%% Purge roster items |
558 |
|
%%----------------------------- |
559 |
|
|
560 |
|
rosteritem_purge(Options) -> |
561 |
|
Num_rosteritems = mnesia:table_info(roster, size), |
562 |
|
io:format("There are ~p roster items in total.~n", [Num_rosteritems]), |
563 |
|
Key = mnesia:dirty_first(roster), |
564 |
|
ok = rip(Key, Options, {0, Num_rosteritems, 0, 0}), |
565 |
|
{atomic, ok}. |
566 |
|
|
567 |
|
rip('$end_of_table', _Options, Counters) -> |
568 |
|
print_progress_line(Counters), |
569 |
|
ok; |
570 |
|
rip(Key, Options, {Pr, NT, NV, ND}) -> |
571 |
|
Key_next = mnesia:dirty_next(roster, Key), |
572 |
|
ND2 = case decide_rip(Key, Options) of |
573 |
|
true -> |
574 |
|
mnesia:dirty_delete(roster, Key), |
575 |
|
ND+1; |
576 |
|
false -> |
577 |
|
ND |
578 |
|
end, |
579 |
|
NV2 = NV+1, |
580 |
|
Pr2 = print_progress_line({Pr, NT, NV2, ND2}), |
581 |
|
rip(Key_next, Options, {Pr2, NT, NV2, ND2}). |
582 |
|
|
583 |
|
print_progress_line({Pr, NT, NV, ND}) -> |
584 |
|
Pr2 = trunc((NV/NT)*100), |
585 |
|
case Pr == Pr2 of |
586 |
|
true -> |
587 |
|
ok; |
588 |
|
false -> |
589 |
|
io:format("Progress ~p% - visited ~p - deleted ~p~n", [Pr2, NV, ND]) |
590 |
|
end, |
591 |
|
Pr2. |
592 |
|
|
593 |
|
decide_rip(Key, {Subs, Asks, User, Contact}) -> |
594 |
|
case catch mnesia:dirty_read(roster, Key) of |
595 |
|
[RI] -> |
596 |
|
lists:member(RI#roster.subscription, Subs) |
597 |
|
andalso lists:member(RI#roster.ask, Asks) |
598 |
|
andalso decide_rip_jid(RI#roster.us, User) |
599 |
|
andalso decide_rip_jid(RI#roster.jid, Contact); |
600 |
|
_ -> |
601 |
|
false |
602 |
|
end. |
603 |
|
|
604 |
|
%% Returns true if the server of the JID is included in the servers |
605 |
|
decide_rip_jid({UName, UServer, _UResource}, Match_list) -> |
606 |
|
decide_rip_jid({UName, UServer}, Match_list); |
607 |
|
decide_rip_jid({UName, UServer}, Match_list) -> |
608 |
|
lists:any( |
609 |
|
fun(Match_string) -> |
610 |
|
MJID = jlib:string_to_jid(Match_string), |
611 |
|
MName = MJID#jid.luser, |
612 |
|
MServer = MJID#jid.lserver, |
613 |
|
Is_server = is_glob_match(UServer, MServer), |
614 |
|
case MName of |
615 |
|
[] when UName == [] -> |
616 |
|
Is_server; |
617 |
|
[] -> |
618 |
|
false; |
619 |
|
_ -> |
620 |
|
Is_server |
621 |
|
andalso is_glob_match(UName, MName) |
622 |
|
end |
623 |
|
end, |
624 |
|
Match_list). |
625 |
|
|
626 |
|
%% Copied from ejabberd-2.0.0/src/acl.erl |
627 |
|
is_regexp_match(String, RegExp) -> |
628 |
|
case regexp:first_match(String, RegExp) of |
629 |
|
nomatch -> |
630 |
|
false; |
631 |
|
{match, _, _} -> |
632 |
|
true; |
633 |
|
{error, ErrDesc} -> |
634 |
|
io:format( |
635 |
|
"Wrong regexp ~p in ACL: ~p", |
636 |
|
[RegExp, lists:flatten(regexp:format_error(ErrDesc))]), |
637 |
|
false |
638 |
|
end. |
639 |
|
is_glob_match(String, Glob) -> |
640 |
|
is_regexp_match(String, regexp:sh_to_awk(Glob)). |
641 |
|
|
642 |
|
|
643 |
|
%%----------------------------- |
644 |
|
%% Push Roster from file |
645 |
|
%%----------------------------- |
646 |
|
|
647 |
pushroster(File, User, Server) -> |
pushroster(File, User, Server) -> |
648 |
{ok, [Roster]} = file:consult(File), |
{ok, [Roster]} = file:consult(File), |
649 |
subscribe_roster({User, Server, "", User}, Roster). |
subscribe_roster({User, Server, "", User}, Roster). |
751 |
-record(last_activity, {us, timestamp, status}). |
-record(last_activity, {us, timestamp, status}). |
752 |
|
|
753 |
delete_older_users(Days) -> |
delete_older_users(Days) -> |
754 |
|
%% Get the list of registered users |
755 |
|
Users = ejabberd_auth:dirty_get_registered_users(), |
756 |
|
delete_older_users(Days, Users). |
757 |
|
|
758 |
|
delete_older_users_vhost(Host, Days) -> |
759 |
|
%% Get the list of registered users |
760 |
|
Users = ejabberd_auth:get_vh_registered_users(Host), |
761 |
|
delete_older_users(Days, Users). |
762 |
|
|
763 |
|
delete_older_users(Days, Users) -> |
764 |
%% Convert older time |
%% Convert older time |
765 |
SecOlder = Days*24*60*60, |
SecOlder = Days*24*60*60, |
766 |
|
|
768 |
{MegaSecs, Secs, _MicroSecs} = now(), |
{MegaSecs, Secs, _MicroSecs} = now(), |
769 |
TimeStamp_now = MegaSecs * 1000000 + Secs, |
TimeStamp_now = MegaSecs * 1000000 + Secs, |
770 |
|
|
|
%% Get the list of registered users |
|
|
Users = ejabberd_auth:dirty_get_registered_users(), |
|
|
|
|
771 |
%% For a user, remove if required and answer true |
%% For a user, remove if required and answer true |
772 |
F = fun({LUser, LServer}) -> |
F = fun({LUser, LServer}) -> |
773 |
%% Check if the user is logged |
%% Check if the user is logged |
865 |
lists:reverse(Hist) |
lists:reverse(Hist) |
866 |
end. |
end. |
867 |
|
|
868 |
|
group_parameters(Ps, [Char]) -> |
869 |
format_print_room(Host1, Rooms)-> |
{none, Grouped_Ps} = lists:foldl( |
870 |
lists:foreach( |
fun(P, {State, Res}) -> |
871 |
fun({_, {Roomname, Host},_}) -> |
case State of |
872 |
case Host1 of |
none -> |
873 |
all -> |
case P of |
874 |
io:format("~s ~s ~n", [Roomname, Host]); |
[Char | PTail]-> |
875 |
Host -> |
{building, [PTail | Res]}; |
876 |
io:format("~s ~s ~n", [Roomname, Host]); |
_ -> |
877 |
_ -> |
{none, [P | Res]} |
878 |
ok |
end; |
879 |
end |
building -> |
880 |
end, |
[ResHead | ResTail] = Res, |
881 |
Rooms). |
case lists:last(P) of |
882 |
|
Char -> |
883 |
|
P2 = lists:sublist(P, length(P)-1), |
884 |
%%---------------------------- |
{none, [ResHead ++ " " ++ P2 | ResTail]}; |
885 |
%% Purge MUC |
_ -> |
886 |
%%---------------------------- |
{building, [ResHead ++ " " ++ P | ResTail]} |
887 |
|
end |
888 |
%% Required for muc_purge |
end |
889 |
%% Copied from mod_muc/mod_muc_room.erl |
end, |
890 |
-define(DICT, dict). |
{none, []}, |
891 |
-record(muc_online_room, {name_host, pid}). |
Ps), |
892 |
-record(lqueue, {queue, len, max}). |
lists:reverse(Grouped_Ps). |
|
-record(config, {title = "", |
|
|
allow_change_subj = true, |
|
|
allow_query_users = true, |
|
|
allow_private_messages = true, |
|
|
public = true, |
|
|
public_list = true, |
|
|
persistent = false, |
|
|
moderated = false, % TODO |
|
|
members_by_default = true, |
|
|
members_only = false, |
|
|
allow_user_invites = false, |
|
|
password_protected = false, |
|
|
password = "", |
|
|
anonymous = true, |
|
|
logging = false |
|
|
}). |
|
|
-record(state, {room, |
|
|
host, |
|
|
server_host, |
|
|
access, |
|
|
jid, |
|
|
config = #config{}, |
|
|
users, |
|
|
affiliations, |
|
|
history, |
|
|
subject = "", |
|
|
subject_author = "", |
|
|
just_created = false}). |
|
|
|
|
|
muc_purge(Days) -> |
|
|
ServerHost = global, |
|
|
Host = global, |
|
|
muc_purge2(ServerHost, Host, Days). |
|
|
|
|
|
muc_purge(ServerHost, Days) -> |
|
|
Host = find_host(ServerHost), |
|
|
muc_purge2(ServerHost, Host, Days). |
|
|
|
|
|
muc_purge2(ServerHost, Host, Last_allowed) -> |
|
|
Room_names = get_room_names(Host), |
|
|
|
|
|
Decide = fun(N) -> decide(N, Last_allowed) end, |
|
|
Rooms_to_delete = lists:filter(Decide, Room_names), |
|
|
|
|
|
Num_rooms = length(Room_names), |
|
|
Num_rooms_to_delete = length(Rooms_to_delete), |
|
|
|
|
|
Rooms_to_delete_full = fill_serverhost(Rooms_to_delete, ServerHost), |
|
|
|
|
|
Delete = fun({N, H, SH}) -> |
|
|
mod_muc:room_destroyed(H, N, SH), |
|
|
mod_muc:forget_room(H, N) |
|
|
end, |
|
|
lists:foreach(Delete, Rooms_to_delete_full), |
|
|
{purged, Num_rooms, Num_rooms_to_delete, Rooms_to_delete}. |
|
|
|
|
|
fill_serverhost(Rooms_to_delete, global) -> |
|
|
ServerHosts1 = ?MYHOSTS, |
|
|
ServerHosts2 = [ {ServerHost, find_host(ServerHost)} || ServerHost <- ServerHosts1], |
|
|
[ {Name, Host, find_serverhost(Host, ServerHosts2)} || {Name, Host} <- Rooms_to_delete]; |
|
|
fill_serverhost(Rooms_to_delete, ServerHost) -> |
|
|
[ {Name, Host, ServerHost}|| {Name, Host} <- Rooms_to_delete]. |
|
|
|
|
|
find_serverhost(Host, ServerHosts) -> |
|
|
{value, {ServerHost, Host}} = lists:keysearch(Host, 2, ServerHosts), |
|
|
ServerHost. |
|
|
|
|
|
find_host(ServerHost) -> |
|
|
gen_mod:get_module_opt(ServerHost, mod_muc, host, "conference." ++ ServerHost). |
|
|
|
|
|
decide({Room_name, Host}, Last_allowed) -> |
|
|
Room_pid = get_room_pid(Room_name, Host), |
|
|
|
|
|
C = get_room_config(Room_pid), |
|
|
Persistent = C#config.persistent, |
|
|
|
|
|
S = get_room_state(Room_pid), |
|
|
Just_created = S#state.just_created, |
|
|
|
|
|
Room_users = S#state.users, |
|
|
Num_users = length(?DICT:to_list(Room_users)), |
|
|
|
|
|
History = (S#state.history)#lqueue.queue, |
|
|
Ts_now = calendar:now_to_universal_time(now()), |
|
|
Ts_uptime = element(1, erlang:statistics(wall_clock))/1000, |
|
|
{Have_history, Last} = case queue:is_empty(History) of |
|
|
true -> |
|
|
{false, Ts_uptime}; |
|
|
false -> |
|
|
Last_message = queue:last(History), |
|
|
{_, _, _, Ts_last, _} = Last_message, |
|
|
Ts_diff = |
|
|
calendar:datetime_to_gregorian_seconds(Ts_now) |
|
|
- calendar:datetime_to_gregorian_seconds(Ts_last), |
|
|
{true, Ts_diff} |
|
|
end, |
|
|
|
|
|
case {Persistent, Just_created, Num_users, Have_history, seconds_to_days(Last)} of |
|
|
{true, false, 0, _, Last_days} |
|
|
when Last_days > Last_allowed -> |
|
|
true; |
|
|
_ -> |
|
|
false |
|
|
end. |
|
|
|
|
|
seconds_to_days(S) -> |
|
|
round(S) div 60*60*24. |
|
|
|
|
|
uptime_seconds() -> |
|
|
trunc(element(1, erlang:statistics(wall_clock))/1000). |
|
|
|
|
|
get_room_names(Host) -> |
|
|
Get_room_names = fun(Room_reg, Names) -> |
|
|
case {Host, Room_reg#muc_online_room.name_host} of |
|
|
{Host, {Name1, Host}} -> |
|
|
[{Name1, Host} | Names]; |
|
|
{global, {Name1, Host1}} -> |
|
|
[{Name1, Host1} | Names]; |
|
|
_ -> |
|
|
Names |
|
|
end |
|
|
end, |
|
|
ets:foldr(Get_room_names, [], muc_online_room). |
|
|
|
|
|
get_room_pid(Name, Host) -> |
|
|
[Room_ets] = ets:lookup(muc_online_room, {Name, Host}), |
|
|
Room_ets#muc_online_room.pid. |
|
|
|
|
|
get_room_config(Room_pid) -> |
|
|
gen_fsm:sync_send_all_state_event(Room_pid, get_config). |
|
|
|
|
|
get_room_state(Room_pid) -> |
|
|
gen_fsm:sync_send_all_state_event(Room_pid, get_state). |
|