./ct_report/coverage/service_admin_extra_sessions.COVER.html

1 %%%-------------------------------------------------------------------
2 %%% File : service_admin_extra_sessions.erl
3 %%% Author : Badlop <badlop@process-one.net>, Piotr Nosek <piotr.nosek@erlang-solutions.com>
4 %%% Purpose : Contributed administrative functions and commands
5 %%% Created : 10 Aug 2008 by Badlop <badlop@process-one.net>
6 %%%
7 %%%
8 %%% ejabberd, Copyright (C) 2002-2008 ProcessOne
9 %%%
10 %%% This program is free software; you can redistribute it and/or
11 %%% modify it under the terms of the GNU General Public License as
12 %%% published by the Free Software Foundation; either version 2 of the
13 %%% License, or (at your option) any later version.
14 %%%
15 %%% This program is distributed in the hope that it will be useful,
16 %%% but WITHOUT ANY WARRANTY; without even the implied warranty of
17 %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 %%% General Public License for more details.
19 %%%
20 %%% You should have received a copy of the GNU General Public License
21 %%% along with this program; if not, write to the Free Software
22 %%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 %%%
24 %%%-------------------------------------------------------------------
25
26 -module(service_admin_extra_sessions).
27 -author('badlop@process-one.net').
28
29 -export([
30 commands/0,
31
32 num_resources/2,
33 resource_num/3,
34 kick_session/2,
35 kick_session/4,
36 status_num/2, status_num/1,
37 status_list/2, status_list/1,
38 connected_users_info/0,
39 connected_users_info/1,
40 set_presence/7,
41 user_sessions_info/2
42 ]).
43
44 -ignore_xref([
45 commands/0, num_resources/2, resource_num/3, kick_session/2, kick_session/4,
46 status_num/2, status_num/1, status_list/2, status_list/1,
47 connected_users_info/0, connected_users_info/1, set_presence/7,
48 user_sessions_info/2
49 ]).
50
51 -include("mongoose.hrl").
52 -include("ejabberd_commands.hrl").
53 -include("jlib.hrl").
54 -include("session.hrl").
55 -include_lib("exml/include/exml.hrl").
56
57 -type status() :: binary().
58 -type u_s_r_p_st() :: { User :: jid:user(),
59 Server :: jid:server(),
60 Res :: jid:resource(),
61 Prio :: ejabberd_sm:priority(),
62 Status :: status()}.
63 -type formatted_user_info() :: {USR :: string(),
64 Conn :: string(),
65 IPS :: string(),
66 Port :: inet:port_number(),
67 Prio :: ejabberd_sm:priority(),
68 NodeS :: string(),
69 Uptime :: integer()}.
70 %%%
71 %%% Register commands
72 %%%
73
74 -spec commands() -> [ejabberd_commands:cmd(), ...].
75 commands() ->
76 160 SessionDisplay = {list,
77 {sessions, {tuple,
78 [{jid, string},
79 {connection, string},
80 {ip, string},
81 {port, integer},
82 {priority, integer},
83 {node, string},
84 {uptime, integer}
85 ]}}
86 },
87
88 160 [
89 #ejabberd_commands{name = num_resources, tags = [session],
90 desc = "Get the number of resources of a user",
91 module = ?MODULE, function = num_resources,
92 args = [{user, binary}, {host, binary}],
93 result = {resources, integer}},
94 #ejabberd_commands{name = resource_num, tags = [session],
95 desc = "Resource string of a session number",
96 module = ?MODULE, function = resource_num,
97 args = [{user, binary}, {host, binary}, {num, integer}],
98 result = {resource, binary}},
99 #ejabberd_commands{name = kick_session, tags = [session],
100 desc = "Kick a user session",
101 module = ?MODULE, function = kick_session,
102 args = [{user, binary}, {host, binary},
103 {resource, binary}, {reason, binary}],
104 result = {res, rescode}},
105 #ejabberd_commands{name = status_num_host, tags = [session, stats],
106 desc = "Number of logged users with this status in host",
107 module = ?MODULE, function = status_num,
108 args = [{host, binary}, {status, binary}],
109 result = {users, integer}},
110 #ejabberd_commands{name = status_num, tags = [session, stats],
111 desc = "Number of logged users with this status",
112 module = ?MODULE, function = status_num,
113 args = [{status, binary}],
114 result = {users, integer}},
115 #ejabberd_commands{name = status_list_host, tags = [session],
116 desc = "List of users logged in host with their statuses",
117 module = ?MODULE, function = status_list,
118 args = [{host, binary}, {status, binary}],
119 result = {users, {list,
120 {userstatus, {tuple, [
121 {user, string},
122 {host, string},
123 {resource, string},
124 {priority, integer},
125 {status, string}
126 ]}}
127 }}},
128 #ejabberd_commands{name = status_list, tags = [session],
129 desc = "List of logged users with this status",
130 module = ?MODULE, function = status_list,
131 args = [{status, binary}],
132 result = {users, {list,
133 {userstatus, {tuple, [
134 {user, string},
135 {host, string},
136 {resource, string},
137 {priority, integer},
138 {status, string}
139 ]}}
140 }}},
141 #ejabberd_commands{name = connected_users_info,
142 tags = [session],
143 desc = "List all established sessions and their information",
144 module = ?MODULE, function = connected_users_info,
145 args = [],
146 result = {connected_users_info, SessionDisplay}},
147 #ejabberd_commands{name = connected_users_vhost,
148 tags = [session],
149 desc = "Get the list of established sessions in a vhost",
150 module = ?MODULE, function = connected_users_info,
151 args = [{host, binary}],
152 result = {connected_users_vhost, SessionDisplay}},
153 #ejabberd_commands{name = user_sessions_info,
154 tags = [session],
155 desc = "Get information about all sessions of a user",
156 module = ?MODULE, function = user_sessions_info,
157 args = [{user, binary}, {host, binary}],
158 result = {user_sessions_info, SessionDisplay}},
159
160 #ejabberd_commands{name = set_presence,
161 tags = [session],
162 desc = "Set presence of a session",
163 module = ?MODULE, function = set_presence,
164 args = [{user, binary}, {host, binary},
165 {resource, binary}, {type, binary},
166 {show, binary}, {status, binary},
167 {priority, binary}],
168 result = {res, rescode}}
169 ].
170
171 %%%
172 %%% Sessions
173 %%%
174
175 -spec num_resources(jid:user(), jid:server()) -> non_neg_integer().
176 num_resources(User, Host) ->
177 1 JID = jid:make(User, Host, <<>>),
178 1 length(ejabberd_sm:get_user_resources(JID)).
179
180
181 -spec resource_num(jid:user(), jid:server(), integer()) -> binary() | string().
182 resource_num(User, Host, Num) ->
183 1 JID = jid:make(User, Host, <<>>),
184 1 Resources = ejabberd_sm:get_user_resources(JID),
185 1 case (0 < Num) and (Num =< length(Resources)) of
186 true ->
187 1 lists:nth(Num, Resources);
188 false ->
189
:-(
lists:flatten(io_lib:format("Error: Wrong resource number: ~p", [Num]))
190 end.
191
192 -spec kick_session(jid:jid(), binary() | list()) -> ok.
193 kick_session(JID, ReasonText) ->
194 2 mongoose_session_api:kick_session(JID, ReasonText).
195
196 -spec kick_session(jid:user(), jid:server(), jid:resource(), list() | binary()) -> ok.
197 kick_session(User, Server, Resource, ReasonText) ->
198 1 mongoose_session_api:kick_session(User, Server, Resource, ReasonText).
199
200 -spec status_num('all' | jid:server(), status()) -> non_neg_integer().
201 status_num(Host, Status) ->
202 3 length(get_status_list(Host, Status)).
203
204
205 -spec status_num(status()) -> non_neg_integer().
206 status_num(Status) ->
207 1 status_num(all, Status).
208
209
210 -spec status_list('all' | jid:server(), status()) -> [u_s_r_p_st()].
211 status_list(Host, Status) ->
212 3 Res = get_status_list(Host, Status),
213 3 [{U, S, R, P, St} || {U, S, R, P, St} <- Res].
214
215
216 -spec status_list(binary()) -> [u_s_r_p_st()].
217 status_list(Status) ->
218 1 status_list(all, Status).
219
220
221 -spec get_status_list('all' | jid:server(), status()) -> [u_s_r_p_st()].
222 get_status_list(Host, StatusRequired) ->
223 6 Sessions0 = case Host of
224 2 all -> ejabberd_sm:get_full_session_list();
225 4 _ -> ejabberd_sm:get_vh_session_list(Host)
226 end,
227 6 Sessions = [ {catch ejabberd_c2s:get_presence(Pid), S, P}
228 || #session{sid = {_, Pid}, usr = {_, S, _}, priority = P}
229 6 <- Sessions0 ],
230
231 %% Filter by status
232 6 Fstatus = case StatusRequired of
233
:-(
all -> fun(_, _) -> true end;
234 6 _ -> fun(A, B) -> A == B end
235 end,
236 6 [{User, Server, Resource, Priority, StatusText}
237 6 || {{User, Resource, Status, StatusText}, Server, Priority} <- Sessions,
238 12 apply(Fstatus, [Status, StatusRequired])].
239
240
241 -spec connected_users_info() -> [formatted_user_info()].
242 connected_users_info() ->
243 1 connected_users_info(all).
244
245
246 -spec connected_users_info('all' | jid:server()) -> [formatted_user_info()].
247 connected_users_info(Host) ->
248 3 USRIs = case Host of
249 1 all -> ejabberd_sm:get_full_session_list();
250 2 _ -> ejabberd_sm:get_vh_session_list(Host)
251 end,
252 3 lists:map(fun format_user_info/1, USRIs).
253
254
255 -spec set_presence(jid:user(), jid:server(), jid:resource(),
256 Type :: binary(), Show :: binary() | string(), Status :: binary() | string(),
257 Prio :: binary() | string()) -> 'ok'.
258 set_presence(User, Host, Resource, Type, Show, Status, Priority) ->
259 1 Pid = ejabberd_sm:get_session_pid(jid:make(User, Host, Resource)),
260 1 USR = <<User/binary, $@, Host/binary, $/, Resource/binary>>,
261 1 US = <<User/binary, $@, Host/binary>>,
262 1 Message = {xmlstreamelement,
263 #xmlel{ name = <<"presence">>,
264 attrs = [{<<"from">>, USR}, {<<"to">>, US}, {<<"type">>, Type}],
265 children = [#xmlel{ name = <<"show">>,
266 children = [#xmlcdata{content = Show}]},
267 #xmlel{ name = <<"status">>,
268 children = [#xmlcdata{content = Status}]},
269 #xmlel{ name = <<"priority">>,
270 children = [#xmlcdata{content = Priority}]}]}},
271 1 p1_fsm_old:send_event(Pid, Message).
272
273
274 -spec user_sessions_info(jid:user(), jid:server()) -> [formatted_user_info()].
275 user_sessions_info(User, Host) ->
276 1 JID = jid:make(User, Host, <<>>),
277 1 Resources = ejabberd_sm:get_user_resources(JID),
278 1 lists:foldl(fun(Res, Acc) ->
279 1 RJID = jid:replace_resource(JID, Res),
280 1 case ejabberd_sm:get_session(RJID) of
281
:-(
offline -> Acc;
282 1 Session -> [format_user_info(Session) | Acc]
283 end
284 end, [], Resources).
285
286
287 -spec format_user_info(ejabberd_sm:session()) -> formatted_user_info().
288 format_user_info(#session{sid = {Microseconds, Pid}, usr = {U, S, R},
289 priority = Priority, info = Info}) ->
290 7 Conn = maps:get(conn, Info, undefined),
291 7 {Ip, Port} = maps:get(ip, Info, undefined),
292 7 IPS = inet_parse:ntoa(Ip),
293 7 NodeS = atom_to_list(node(Pid)),
294 7 Uptime = (erlang:system_time(microsecond) - Microseconds) div 1000000,
295 7 {[U, $@, S, $/, R], atom_to_list(Conn), IPS, Port, Priority, NodeS, Uptime}.
Line Hits Source