Link Here
|
|
|
1 |
%%%------------------------------------------------------------------- |
2 |
%%% File : mod_admin_extra.erl |
3 |
%%% Author : Badlop <badlop@process-one.net> |
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., 59 Temple Place, Suite 330, Boston, MA |
23 |
%%% 02111-1307 USA |
24 |
%%% |
25 |
%%%------------------------------------------------------------------- |
26 |
|
27 |
-module(mod_admin_extra). |
28 |
-author('badlop@process-one.net'). |
29 |
|
30 |
-behaviour(gen_mod). |
31 |
|
32 |
-export([start/2, stop/1, |
33 |
%% Node |
34 |
compile/1, |
35 |
load_config/1, |
36 |
get_cookie/0, |
37 |
remove_node/1, |
38 |
export2odbc/2, |
39 |
%% Accounts |
40 |
set_password/3, |
41 |
check_password_hash/4, |
42 |
delete_old_users/1, |
43 |
delete_old_users_vhost/2, |
44 |
ban_account/3, |
45 |
num_active_users/2, |
46 |
%% Sessions |
47 |
num_resources/2, |
48 |
resource_num/3, |
49 |
kick_session/4, |
50 |
status_num/2, status_num/1, |
51 |
status_list/2, status_list/1, |
52 |
connected_users_info/0, |
53 |
connected_users_vhost/1, |
54 |
set_presence/7, |
55 |
user_sessions_info/2, |
56 |
%% Vcard |
57 |
set_nickname/3, |
58 |
get_vcard/3, |
59 |
get_vcard/4, |
60 |
get_vcard_multi/4, |
61 |
set_vcard/4, |
62 |
set_vcard/5, |
63 |
%% Roster |
64 |
add_rosteritem/7, |
65 |
delete_rosteritem/4, |
66 |
process_rosteritems/5, |
67 |
get_roster/2, |
68 |
push_roster/3, |
69 |
push_roster_all/1, |
70 |
push_alltoall/2, |
71 |
%% mod_last |
72 |
set_last/4, |
73 |
%% mod_private |
74 |
private_get/4, |
75 |
private_set/3, |
76 |
%% mod_shared_roster |
77 |
srg_create/5, |
78 |
srg_delete/2, |
79 |
srg_list/1, |
80 |
srg_get_info/2, |
81 |
srg_get_members/2, |
82 |
srg_user_add/4, |
83 |
srg_user_del/4, |
84 |
%% Stanza |
85 |
send_message_headline/4, |
86 |
send_message_chat/3, |
87 |
send_stanza_c2s/4, |
88 |
privacy_set/3, |
89 |
%% Stats |
90 |
stats/1, stats/2 |
91 |
]). |
92 |
|
93 |
-include("ejabberd.hrl"). |
94 |
-include("ejabberd_commands.hrl"). |
95 |
-include("mod_roster.hrl"). |
96 |
-include("jlib.hrl"). |
97 |
|
98 |
%% Copied from ejabberd_sm.erl |
99 |
-record(session, {sid, usr, us, priority, info}). |
100 |
|
101 |
|
102 |
%%% |
103 |
%%% gen_mod |
104 |
%%% |
105 |
|
106 |
start(_Host, _Opts) -> |
107 |
ejabberd_commands:register_commands(commands()). |
108 |
|
109 |
stop(_Host) -> |
110 |
ejabberd_commands:unregister_commands(commands()). |
111 |
|
112 |
|
113 |
%%% |
114 |
%%% Register commands |
115 |
%%% |
116 |
|
117 |
commands() -> |
118 |
Vcard1FieldsString = "Some vcard field names in get/set_vcard are:\n" |
119 |
" FN - Full Name\n" |
120 |
" NICKNAME - Nickname\n" |
121 |
" BDAY - Birthday\n" |
122 |
" TITLE - Work: Position\n" |
123 |
" ROLE - Work: Role", |
124 |
|
125 |
Vcard2FieldsString = "Some vcard field names and subnames in get/set_vcard2 are:\n" |
126 |
" N FAMILY - Family name\n" |
127 |
" N GIVEN - Given name\n" |
128 |
" N MIDDLE - Middle name\n" |
129 |
" ADR CTRY - Address: Country\n" |
130 |
" ADR LOCALITY - Address: City\n" |
131 |
" EMAIL USERID - E-Mail Address\n" |
132 |
" ORG ORGNAME - Work: Company\n" |
133 |
" ORG ORGUNIT - Work: Department", |
134 |
|
135 |
VcardXEP = "For a full list of vCard fields check XEP-0054: vcard-temp at " |
136 |
"http://www.xmpp.org/extensions/xep-0054.html", |
137 |
|
138 |
[ |
139 |
#ejabberd_commands{name = compile, tags = [erlang], |
140 |
desc = "Recompile and reload Erlang source code file", |
141 |
module = ?MODULE, function = compile, |
142 |
args = [{file, string}], |
143 |
result = {res, rescode}}, |
144 |
#ejabberd_commands{name = load_config, tags = [server], |
145 |
desc = "Load ejabberd configuration file", |
146 |
module = ?MODULE, function = load_config, |
147 |
args = [{file, string}], |
148 |
result = {res, rescode}}, |
149 |
#ejabberd_commands{name = get_cookie, tags = [erlang], |
150 |
desc = "Get the Erlang cookie of this node", |
151 |
module = ?MODULE, function = get_cookie, |
152 |
args = [], |
153 |
result = {cookie, string}}, |
154 |
#ejabberd_commands{name = remove_node, tags = [erlang], |
155 |
desc = "Remove an ejabberd node from Mnesia clustering config", |
156 |
module = ?MODULE, function = remove_node, |
157 |
args = [{node, string}], |
158 |
result = {res, rescode}}, |
159 |
#ejabberd_commands{name = export2odbc, tags = [mnesia], |
160 |
desc = "Export Mnesia tables to files in directory", |
161 |
module = ?MODULE, function = export2odbc, |
162 |
args = [{host, string}, {path, string}], |
163 |
result = {res, rescode}}, |
164 |
|
165 |
#ejabberd_commands{name = num_active_users, tags = [accounts, stats], |
166 |
desc = "Get number of users active in the last days", |
167 |
module = ?MODULE, function = num_active_users, |
168 |
args = [{host, string}, {days, integer}], |
169 |
result = {users, integer}}, |
170 |
#ejabberd_commands{name = delete_old_users, tags = [accounts, purge], |
171 |
desc = "Delete users that didn't log in last days, or that never logged", |
172 |
module = ?MODULE, function = delete_old_users, |
173 |
args = [{days, integer}], |
174 |
result = {res, restuple}}, |
175 |
#ejabberd_commands{name = delete_old_users_vhost, tags = [accounts, purge], |
176 |
desc = "Delete users that didn't log in last days in vhost, or that never logged", |
177 |
module = ?MODULE, function = delete_old_users_vhost, |
178 |
args = [{host, string}, {days, integer}], |
179 |
result = {res, restuple}}, |
180 |
|
181 |
#ejabberd_commands{name = check_account, tags = [accounts], |
182 |
desc = "Check if an account exists or not", |
183 |
module = ejabberd_auth, function = is_user_exists, |
184 |
args = [{user, string}, {host, string}], |
185 |
result = {res, rescode}}, |
186 |
#ejabberd_commands{name = check_password, tags = [accounts], |
187 |
desc = "Check if a password is correct", |
188 |
module = ejabberd_auth, function = check_password, |
189 |
args = [{user, string}, {host, string}, {password, string}], |
190 |
result = {res, rescode}}, |
191 |
#ejabberd_commands{name = check_password_hash, tags = [accounts], |
192 |
desc = "Check if the password hash is correct", |
193 |
longdesc = "Allowed hash methods: md5, sha.", |
194 |
module = ?MODULE, function = check_password_hash, |
195 |
args = [{user, string}, {host, string}, {passwordhash, string}, {hashmethod, string}], |
196 |
result = {res, rescode}}, |
197 |
#ejabberd_commands{name = change_password, tags = [accounts], |
198 |
desc = "Change the password of an account", |
199 |
module = ?MODULE, function = set_password, |
200 |
args = [{user, string}, {host, string}, {newpass, string}], |
201 |
result = {res, rescode}}, |
202 |
#ejabberd_commands{name = ban_account, tags = [accounts], |
203 |
desc = "Ban an account: kick sessions and set random password", |
204 |
module = ?MODULE, function = ban_account, |
205 |
args = [{user, string}, {host, string}, {reason, string}], |
206 |
result = {res, rescode}}, |
207 |
|
208 |
#ejabberd_commands{name = num_resources, tags = [session], |
209 |
desc = "Get the number of resources of a user", |
210 |
module = ?MODULE, function = num_resources, |
211 |
args = [{user, string}, {host, string}], |
212 |
result = {resources, integer}}, |
213 |
#ejabberd_commands{name = resource_num, tags = [session], |
214 |
desc = "Resource string of a session number", |
215 |
module = ?MODULE, function = resource_num, |
216 |
args = [{user, string}, {host, string}, {num, integer}], |
217 |
result = {resource, string}}, |
218 |
#ejabberd_commands{name = kick_session, tags = [session], |
219 |
desc = "Kick a user session", |
220 |
module = ?MODULE, function = kick_session, |
221 |
args = [{user, string}, {host, string}, {resource, string}, {reason, string}], |
222 |
result = {res, rescode}}, |
223 |
#ejabberd_commands{name = status_num_host, tags = [session, stats], |
224 |
desc = "Number of logged users with this status in host", |
225 |
module = ?MODULE, function = status_num, |
226 |
args = [{host, string}, {status, string}], |
227 |
result = {users, integer}}, |
228 |
#ejabberd_commands{name = status_num, tags = [session, stats], |
229 |
desc = "Number of logged users with this status", |
230 |
module = ?MODULE, function = status_num, |
231 |
args = [{status, string}], |
232 |
result = {users, integer}}, |
233 |
#ejabberd_commands{name = status_list_host, tags = [session], |
234 |
desc = "List of users logged in host with their statuses", |
235 |
module = ?MODULE, function = status_list, |
236 |
args = [{host, string}, {status, string}], |
237 |
result = {users, {list, |
238 |
{userstatus, {tuple, [ |
239 |
{user, string}, |
240 |
{host, string}, |
241 |
{resource, string}, |
242 |
{priority, integer}, |
243 |
{status, string} |
244 |
]}} |
245 |
}}}, |
246 |
#ejabberd_commands{name = status_list, tags = [session], |
247 |
desc = "List of logged users with this status", |
248 |
module = ?MODULE, function = status_list, |
249 |
args = [{status, string}], |
250 |
result = {users, {list, |
251 |
{userstatus, {tuple, [ |
252 |
{user, string}, |
253 |
{host, string}, |
254 |
{resource, string}, |
255 |
{priority, integer}, |
256 |
{status, string} |
257 |
]}} |
258 |
}}}, |
259 |
#ejabberd_commands{name = connected_users_info, |
260 |
tags = [session], |
261 |
desc = "List all established sessions and their information", |
262 |
module = ?MODULE, function = connected_users_info, |
263 |
args = [], |
264 |
result = {connected_users_info, |
265 |
{list, |
266 |
{sessions, {tuple, |
267 |
[{jid, string}, |
268 |
{connection, string}, |
269 |
{ip, string}, |
270 |
{port, integer}, |
271 |
{priority, integer}, |
272 |
{node, string}, |
273 |
{uptime, integer} |
274 |
]}} |
275 |
}}}, |
276 |
#ejabberd_commands{name = connected_users_vhost, |
277 |
tags = [session], |
278 |
desc = "Get the list of established sessions in a vhost", |
279 |
module = ?MODULE, function = connected_users_vhost, |
280 |
args = [{host, string}], |
281 |
result = {connected_users_vhost, {list, {sessions, string}}}}, |
282 |
#ejabberd_commands{name = user_sessions_info, |
283 |
tags = [session], |
284 |
desc = "Get information about all sessions of a user", |
285 |
module = ?MODULE, function = user_sessions_info, |
286 |
args = [{user, string}, {host, string}], |
287 |
result = {sessions_info, |
288 |
{list, |
289 |
{session, {tuple, |
290 |
[{connection, string}, |
291 |
{ip, string}, |
292 |
{port, integer}, |
293 |
{priority, integer}, |
294 |
{node, string}, |
295 |
{uptime, integer}, |
296 |
{status, string}, |
297 |
{resource, string}, |
298 |
{statustext, string} |
299 |
]}} |
300 |
}}}, |
301 |
|
302 |
#ejabberd_commands{name = set_presence, |
303 |
tags = [session], |
304 |
desc = "Set presence of a session", |
305 |
module = ?MODULE, function = set_presence, |
306 |
args = [{user, string}, {host, string}, |
307 |
{resource, string}, {type, string}, |
308 |
{show, string}, {status, string}, |
309 |
{priority, string}], |
310 |
result = {res, rescode}}, |
311 |
|
312 |
#ejabberd_commands{name = set_nickname, tags = [vcard], |
313 |
desc = "Set nickname in a user's vCard", |
314 |
module = ?MODULE, function = set_nickname, |
315 |
args = [{user, string}, {host, string}, {nickname, string}], |
316 |
result = {res, rescode}}, |
317 |
|
318 |
#ejabberd_commands{name = get_vcard, tags = [vcard], |
319 |
desc = "Get content from a vCard field", |
320 |
longdesc = Vcard1FieldsString ++ "\n" ++ Vcard2FieldsString ++ "\n\n" ++ VcardXEP, |
321 |
module = ?MODULE, function = get_vcard, |
322 |
args = [{user, string}, {host, string}, {name, string}], |
323 |
result = {content, string}}, |
324 |
#ejabberd_commands{name = get_vcard2, tags = [vcard], |
325 |
desc = "Get content from a vCard field", |
326 |
longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++ "\n" ++ VcardXEP, |
327 |
module = ?MODULE, function = get_vcard, |
328 |
args = [{user, string}, {host, string}, {name, string}, {subname, string}], |
329 |
result = {content, string}}, |
330 |
#ejabberd_commands{name = get_vcard2_multi, tags = [vcard], |
331 |
desc = "Get multiple contents from a vCard field (requires exmpp installed)", |
332 |
longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++ "\n" ++ VcardXEP, |
333 |
module = ?MODULE, function = get_vcard_multi, |
334 |
args = [{user, string}, {host, string}, {name, string}, {subname, string}], |
335 |
result = {contents, {list, string}}}, |
336 |
|
337 |
#ejabberd_commands{name = set_vcard, tags = [vcard], |
338 |
desc = "Set content in a vCard field", |
339 |
longdesc = Vcard1FieldsString ++ "\n" ++ Vcard2FieldsString ++ "\n\n" ++ VcardXEP, |
340 |
module = ?MODULE, function = set_vcard, |
341 |
args = [{user, string}, {host, string}, {name, string}, {content, string}], |
342 |
result = {res, rescode}}, |
343 |
#ejabberd_commands{name = set_vcard2, tags = [vcard], |
344 |
desc = "Set content in a vCard subfield", |
345 |
longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++ "\n" ++ VcardXEP, |
346 |
module = ?MODULE, function = set_vcard, |
347 |
args = [{user, string}, {host, string}, {name, string}, {subname, string}, {content, string}], |
348 |
result = {res, rescode}}, |
349 |
#ejabberd_commands{name = set_vcard2_multi, tags = [vcard], |
350 |
desc = "Set multiple contents in a vCard subfield", |
351 |
longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++ "\n" ++ VcardXEP, |
352 |
module = ?MODULE, function = set_vcard, |
353 |
args = [{user, string}, {host, string}, {name, string}, {subname, string}, {contents, {list, string}}], |
354 |
result = {res, rescode}}, |
355 |
|
356 |
#ejabberd_commands{name = add_rosteritem, tags = [roster], |
357 |
desc = "Add an item to a user's roster (supports ODBC)", |
358 |
module = ?MODULE, function = add_rosteritem, |
359 |
args = [{localuser, string}, {localserver, string}, |
360 |
{user, string}, {server, string}, |
361 |
{nick, string}, {group, string}, |
362 |
{subs, string}], |
363 |
result = {res, rescode}}, |
364 |
%%{"", "subs= none, from, to or both"}, |
365 |
%%{"", "example: add-roster peter localhost mike server.com MiKe Employees both"}, |
366 |
%%{"", "will add mike@server.com to peter@localhost roster"}, |
367 |
#ejabberd_commands{name = delete_rosteritem, tags = [roster], |
368 |
desc = "Delete an item from a user's roster (supports ODBC)", |
369 |
module = ?MODULE, function = delete_rosteritem, |
370 |
args = [{localuser, string}, {localserver, string}, |
371 |
{user, string}, {server, string}], |
372 |
result = {res, rescode}}, |
373 |
#ejabberd_commands{name = process_rosteritems, tags = [roster], |
374 |
desc = "List or delete rosteritems that match filtering options", |
375 |
longdesc = "Explanation of each argument:\n" |
376 |
" - action: what to do with each rosteritem that " |
377 |
"matches all the filtering options\n" |
378 |
" - subs: subscription type\n" |
379 |
" - asks: pending subscription\n" |
380 |
" - users: the JIDs of the local user\n" |
381 |
" - contacts: the JIDs of the contact in the roster\n" |
382 |
"\n" |
383 |
"Allowed values in the arguments:\n" |
384 |
" ACTION = list | delete\n" |
385 |
" SUBS = SUB[:SUB]* | any\n" |
386 |
" SUB = none | from | to | both\n" |
387 |
" ASKS = ASK[:ASK]* | any\n" |
388 |
" ASK = none | out | in\n" |
389 |
" USERS = JID[:JID]* | any\n" |
390 |
" CONTACTS = JID[:JID]* | any\n" |
391 |
" JID = characters valid in a JID, and can use the " |
392 |
"globs: *, ?, ! and [...]\n" |
393 |
"\n" |
394 |
"This example will list roster items with subscription " |
395 |
"'none', 'from' or 'to' that have any ask property, of " |
396 |
"local users which JID is in the virtual host " |
397 |
"'example.org' and that the contact JID is either a " |
398 |
"bare server name (without user part) or that has a " |
399 |
"user part and the server part contains the word 'icq'" |
400 |
":\n list none:from:to any *@example.org *:*@*icq*", |
401 |
module = ?MODULE, function = process_rosteritems, |
402 |
args = [{action, string}, {subs, string}, |
403 |
{asks, string}, {users, string}, |
404 |
{contacts, string}], |
405 |
result = {res, rescode}}, |
406 |
#ejabberd_commands{name = get_roster, tags = [roster], |
407 |
desc = "Get roster of a local user", |
408 |
module = ?MODULE, function = get_roster, |
409 |
args = [{user, string}, {host, string}], |
410 |
result = {contacts, {list, {contact, {tuple, [ |
411 |
{jid, string}, |
412 |
{nick, string}, |
413 |
{subscription, string}, |
414 |
{ask, string}, |
415 |
{group, string} |
416 |
]}}}}}, |
417 |
#ejabberd_commands{name = push_roster, tags = [roster], |
418 |
desc = "Push template roster from file to a user", |
419 |
module = ?MODULE, function = push_roster, |
420 |
args = [{file, string}, {user, string}, {host, string}], |
421 |
result = {res, rescode}}, |
422 |
#ejabberd_commands{name = push_roster_all, tags = [roster], |
423 |
desc = "Push template roster from file to all those users", |
424 |
module = ?MODULE, function = push_roster_all, |
425 |
args = [{file, string}], |
426 |
result = {res, rescode}}, |
427 |
#ejabberd_commands{name = push_alltoall, tags = [roster], |
428 |
desc = "Add all the users to all the users of Host in Group", |
429 |
module = ?MODULE, function = push_alltoall, |
430 |
args = [{host, string}, {group, string}], |
431 |
result = {res, rescode}}, |
432 |
|
433 |
#ejabberd_commands{name = set_last, tags = [last], |
434 |
desc = "Set last activity information", |
435 |
longdesc = "Timestamp is the seconds since" |
436 |
"1970-01-01 00:00:00 UTC, for example: date +%s", |
437 |
module = ?MODULE, function = set_last, |
438 |
args = [{user, string}, {host, string}, {timestamp, integer}, {status, string}], |
439 |
result = {res, rescode}}, |
440 |
|
441 |
#ejabberd_commands{name = private_get, tags = [private], |
442 |
desc = "Get some information from a user private storage", |
443 |
module = ?MODULE, function = private_get, |
444 |
args = [{user, string}, {host, string}, {element, string}, {ns, string}], |
445 |
result = {res, string}}, |
446 |
#ejabberd_commands{name = private_set, tags = [private], |
447 |
desc = "Set to the user private storage", |
448 |
module = ?MODULE, function = private_set, |
449 |
args = [{user, string}, {host, string}, {element, string}], |
450 |
result = {res, rescode}}, |
451 |
|
452 |
#ejabberd_commands{name = srg_create, tags = [shared_roster_group], |
453 |
desc = "Create a Shared Roster Group", |
454 |
longdesc = "If you want to specify several group " |
455 |
"identifiers in the Display argument,\n" |
456 |
"put \\ \" around the argument and\nseparate the " |
457 |
"identifiers with \\ \\ n\n" |
458 |
"For example:\n" |
459 |
" ejabberdctl srg_create group3 localhost " |
460 |
"name desc \\\"group1\\\\ngroup2\\\"", |
461 |
module = ?MODULE, function = srg_create, |
462 |
args = [{group, string}, {host, string}, |
463 |
{name, string}, {description, string}, {display, string}], |
464 |
result = {res, rescode}}, |
465 |
#ejabberd_commands{name = srg_delete, tags = [shared_roster_group], |
466 |
desc = "Delete a Shared Roster Group", |
467 |
module = ?MODULE, function = srg_delete, |
468 |
args = [{group, string}, {host, string}], |
469 |
result = {res, rescode}}, |
470 |
#ejabberd_commands{name = srg_list, tags = [shared_roster_group], |
471 |
desc = "List the Shared Roster Groups in Host", |
472 |
module = ?MODULE, function = srg_list, |
473 |
args = [{host, string}], |
474 |
result = {groups, {list, {id, string}}}}, |
475 |
#ejabberd_commands{name = srg_get_info, tags = [shared_roster_group], |
476 |
desc = "Get info of a Shared Roster Group", |
477 |
module = ?MODULE, function = srg_get_info, |
478 |
args = [{group, string}, {host, string}], |
479 |
result = {informations, {list, {information, {tuple, [{key, string}, {value, string}]}}}}}, |
480 |
#ejabberd_commands{name = srg_get_members, tags = [shared_roster_group], |
481 |
desc = "Get members of a Shared Roster Group", |
482 |
module = ?MODULE, function = srg_get_members, |
483 |
args = [{group, string}, {host, string}], |
484 |
result = {members, {list, {member, string}}}}, |
485 |
#ejabberd_commands{name = srg_user_add, tags = [shared_roster_group], |
486 |
desc = "Add the JID user@host to the Shared Roster Group", |
487 |
module = ?MODULE, function = srg_user_add, |
488 |
args = [{user, string}, {host, string}, {group, string}, {grouphost, string}], |
489 |
result = {res, rescode}}, |
490 |
#ejabberd_commands{name = srg_user_del, tags = [shared_roster_group], |
491 |
desc = "Delete this JID user@host from the Shared Roster Group", |
492 |
module = ?MODULE, function = srg_user_del, |
493 |
args = [{user, string}, {host, string}, {group, string}, {grouphost, string}], |
494 |
result = {res, rescode}}, |
495 |
|
496 |
#ejabberd_commands{name = send_message_chat, tags = [stanza], |
497 |
desc = "Send a chat message to a local or remote bare of full JID", |
498 |
module = ?MODULE, function = send_message_chat, |
499 |
args = [{from, string}, {to, string}, {body, string}], |
500 |
result = {res, rescode}}, |
501 |
#ejabberd_commands{name = send_message_headline, tags = [stanza], |
502 |
desc = "Send a headline message to a local or remote bare of full JID", |
503 |
module = ?MODULE, function = send_message_headline, |
504 |
args = [{from, string}, {to, string}, |
505 |
{subject, string}, {body, string}], |
506 |
result = {res, rescode}}, |
507 |
#ejabberd_commands{name = send_stanza_c2s, tags = [stanza], |
508 |
desc = "Send a stanza as if sent from a c2s session", |
509 |
module = ?MODULE, function = send_stanza_c2s, |
510 |
args = [{user, string}, {host, string}, {resource, string}, {stanza, string}], |
511 |
result = {res, rescode}}, |
512 |
#ejabberd_commands{name = privacy_set, tags = [stanza], |
513 |
desc = "Send a IQ set privacy stanza for a local account", |
514 |
module = ?MODULE, function = privacy_set, |
515 |
args = [{user, string}, {host, string}, {xmlquery, string}], |
516 |
result = {res, rescode}}, |
517 |
|
518 |
#ejabberd_commands{name = stats, tags = [stats], |
519 |
desc = "Get statistical value: registeredusers onlineusers onlineusersnode uptimeseconds", |
520 |
module = ?MODULE, function = stats, |
521 |
args = [{name, string}], |
522 |
result = {stat, integer}}, |
523 |
#ejabberd_commands{name = stats_host, tags = [stats], |
524 |
desc = "Get statistical value for this host: registeredusers onlineusers", |
525 |
module = ?MODULE, function = stats, |
526 |
args = [{name, string}, {host, string}], |
527 |
result = {stat, integer}} |
528 |
]. |
529 |
|
530 |
|
531 |
%%% |
532 |
%%% Node |
533 |
%%% |
534 |
|
535 |
compile(File) -> |
536 |
case compile:file(File) of |
537 |
ok -> ok; |
538 |
_ -> error |
539 |
end. |
540 |
|
541 |
load_config(Path) -> |
542 |
ok = ejabberd_config:load_file(Path). |
543 |
|
544 |
get_cookie() -> |
545 |
atom_to_list(erlang:get_cookie()). |
546 |
|
547 |
remove_node(Node) -> |
548 |
mnesia:del_table_copy(schema, list_to_atom(Node)), |
549 |
ok. |
550 |
|
551 |
export2odbc(Host, Directory) -> |
552 |
Tables = [ |
553 |
{export_last, last}, |
554 |
{export_offline, offline}, |
555 |
{export_passwd, passwd}, |
556 |
{export_private_storage, private_storage}, |
557 |
{export_roster, roster}, |
558 |
{export_vcard, vcard}, |
559 |
{export_vcard_search, vcard_search}], |
560 |
Export = fun({TableFun, Table}) -> |
561 |
Filename = filename:join([Directory, atom_to_list(Table)++".txt"]), |
562 |
io:format("Trying to export Mnesia table '~p' on Host '~s' to file '~s'~n", [Table, Host, Filename]), |
563 |
Res = (catch ejd2odbc:TableFun(Host, Filename)), |
564 |
io:format(" Result: ~p~n", [Res]) |
565 |
end, |
566 |
lists:foreach(Export, Tables), |
567 |
ok. |
568 |
|
569 |
|
570 |
%%% |
571 |
%%% Accounts |
572 |
%%% |
573 |
|
574 |
set_password(User, Host, Password) -> |
575 |
case ejabberd_auth:set_password(User, Host, Password) of |
576 |
ok -> |
577 |
ok; |
578 |
_ -> |
579 |
error |
580 |
end. |
581 |
|
582 |
%% Copied some code from ejabberd_commands.erl |
583 |
check_password_hash(User, Host, PasswordHash, HashMethod) -> |
584 |
AccountPass = ejabberd_auth:get_password_s(User, Host), |
585 |
AccountPassHash = case HashMethod of |
586 |
"md5" -> get_md5(AccountPass); |
587 |
"sha" -> get_sha(AccountPass); |
588 |
_ -> undefined |
589 |
end, |
590 |
case AccountPassHash of |
591 |
undefined -> error; |
592 |
PasswordHash -> ok; |
593 |
_ -> error |
594 |
end. |
595 |
get_md5(AccountPass) -> |
596 |
lists:flatten([io_lib:format("~.16B", [X]) |
597 |
|| X <- binary_to_list(crypto:md5(AccountPass))]). |
598 |
get_sha(AccountPass) -> |
599 |
lists:flatten([io_lib:format("~.16B", [X]) |
600 |
|| X <- binary_to_list(crypto:sha(AccountPass))]). |
601 |
|
602 |
num_active_users(Host, Days) -> |
603 |
list_last_activity(Host, true, Days). |
604 |
|
605 |
%% Code based on ejabberd/src/web/ejabberd_web_admin.erl |
606 |
list_last_activity(Host, Integral, Days) -> |
607 |
{MegaSecs, Secs, _MicroSecs} = now(), |
608 |
TimeStamp = MegaSecs * 1000000 + Secs, |
609 |
TS = TimeStamp - Days * 86400, |
610 |
case catch mnesia:dirty_select( |
611 |
last_activity, [{{last_activity, {'_', Host}, '$1', '_'}, |
612 |
[{'>', '$1', TS}], |
613 |
[{'trunc', {'/', |
614 |
{'-', TimeStamp, '$1'}, |
615 |
86400}}]}]) of |
616 |
{'EXIT', _Reason} -> |
617 |
[]; |
618 |
Vals -> |
619 |
Hist = histogram(Vals, Integral), |
620 |
if |
621 |
Hist == [] -> |
622 |
0; |
623 |
true -> |
624 |
Left = Days - length(Hist), |
625 |
Tail = if |
626 |
Integral -> |
627 |
lists:duplicate(Left, lists:last(Hist)); |
628 |
true -> |
629 |
lists:duplicate(Left, 0) |
630 |
end, |
631 |
lists:nth(Days, Hist ++ Tail) |
632 |
end |
633 |
end. |
634 |
histogram(Values, Integral) -> |
635 |
histogram(lists:sort(Values), Integral, 0, 0, []). |
636 |
histogram([H | T], Integral, Current, Count, Hist) when Current == H -> |
637 |
histogram(T, Integral, Current, Count + 1, Hist); |
638 |
histogram([H | _] = Values, Integral, Current, Count, Hist) when Current < H -> |
639 |
if |
640 |
Integral -> |
641 |
histogram(Values, Integral, Current + 1, Count, [Count | Hist]); |
642 |
true -> |
643 |
histogram(Values, Integral, Current + 1, 0, [Count | Hist]) |
644 |
end; |
645 |
histogram([], _Integral, _Current, Count, Hist) -> |
646 |
if |
647 |
Count > 0 -> |
648 |
lists:reverse([Count | Hist]); |
649 |
true -> |
650 |
lists:reverse(Hist) |
651 |
end. |
652 |
|
653 |
|
654 |
delete_old_users(Days) -> |
655 |
%% Get the list of registered users |
656 |
Users = ejabberd_auth:dirty_get_registered_users(), |
657 |
|
658 |
{removed, N, UR} = delete_old_users(Days, Users), |
659 |
{ok, io_lib:format("Deleted ~p users: ~p", [N, UR])}. |
660 |
|
661 |
delete_old_users_vhost(Host, Days) -> |
662 |
%% Get the list of registered users |
663 |
Users = ejabberd_auth:get_vh_registered_users(Host), |
664 |
|
665 |
{removed, N, UR} = delete_old_users(Days, Users), |
666 |
{ok, io_lib:format("Deleted ~p users: ~p", [N, UR])}. |
667 |
|
668 |
delete_old_users(Days, Users) -> |
669 |
%% Convert older time |
670 |
SecOlder = Days*24*60*60, |
671 |
|
672 |
%% Get current time |
673 |
{MegaSecs, Secs, _MicroSecs} = now(), |
674 |
TimeStamp_now = MegaSecs * 1000000 + Secs, |
675 |
|
676 |
%% For a user, remove if required and answer true |
677 |
F = fun({LUser, LServer}) -> |
678 |
%% Check if the user is logged |
679 |
case ejabberd_sm:get_user_resources(LUser, LServer) of |
680 |
%% If it isnt |
681 |
[] -> |
682 |
%% Look for his last_activity |
683 |
case (get_lastactivity_module(LServer)):get_last_info(LUser, LServer) of |
684 |
%% If it is |
685 |
%% existent: |
686 |
{ok, TimeStamp, _Status} -> |
687 |
%% get his age |
688 |
Sec = TimeStamp_now - TimeStamp, |
689 |
%% If he is |
690 |
if |
691 |
%% younger than SecOlder: |
692 |
Sec < SecOlder -> |
693 |
%% do nothing |
694 |
false; |
695 |
%% older: |
696 |
true -> |
697 |
%% remove the user |
698 |
ejabberd_auth:remove_user(LUser, LServer), |
699 |
true |
700 |
end; |
701 |
%% nonexistent: |
702 |
not_found -> |
703 |
%% remove the user |
704 |
ejabberd_auth:remove_user(LUser, LServer), |
705 |
true |
706 |
end; |
707 |
%% Else |
708 |
_ -> |
709 |
%% do nothing |
710 |
false |
711 |
end |
712 |
end, |
713 |
%% Apply the function to every user in the list |
714 |
Users_removed = lists:filter(F, Users), |
715 |
{removed, length(Users_removed), Users_removed}. |
716 |
|
717 |
get_lastactivity_module(Server) -> |
718 |
case lists:member(mod_last, gen_mod:loaded_modules(Server)) of |
719 |
true -> mod_last; |
720 |
_ -> mod_last_odbc |
721 |
end. |
722 |
|
723 |
|
724 |
%% |
725 |
%% Ban account |
726 |
|
727 |
ban_account(User, Host, ReasonText) -> |
728 |
Reason = prepare_reason(ReasonText), |
729 |
kick_sessions(User, Host, Reason), |
730 |
set_random_password(User, Host, Reason), |
731 |
ok. |
732 |
|
733 |
kick_sessions(User, Server, Reason) -> |
734 |
lists:map( |
735 |
fun(Resource) -> |
736 |
kick_this_session(User, Server, Resource, Reason) |
737 |
end, |
738 |
get_resources(User, Server)). |
739 |
|
740 |
get_resources(User, Server) -> |
741 |
lists:map( |
742 |
fun(Session) -> |
743 |
element(3, Session#session.usr) |
744 |
end, |
745 |
get_sessions(User, Server)). |
746 |
|
747 |
get_sessions(User, Server) -> |
748 |
LUser = jlib:nodeprep(User), |
749 |
LServer = jlib:nameprep(Server), |
750 |
Sessions = mnesia:dirty_index_read(session, {LUser, LServer}, #session.us), |
751 |
true = is_list(Sessions), |
752 |
Sessions. |
753 |
|
754 |
set_random_password(User, Server, Reason) -> |
755 |
NewPass = build_random_password(Reason), |
756 |
set_password_auth(User, Server, NewPass). |
757 |
|
758 |
build_random_password(Reason) -> |
759 |
Date = jlib:timestamp_to_iso(calendar:universal_time()), |
760 |
RandomString = randoms:get_string(), |
761 |
"BANNED_ACCOUNT--" ++ Date ++ "--" ++ RandomString ++ "--" ++ Reason. |
762 |
|
763 |
set_password_auth(User, Server, Password) -> |
764 |
ok = ejabberd_auth:set_password(User, Server, Password). |
765 |
|
766 |
prepare_reason([]) -> |
767 |
"Kicked by administrator"; |
768 |
prepare_reason([Reason]) -> |
769 |
Reason; |
770 |
prepare_reason(Reason) when is_list(Reason) -> |
771 |
Reason; |
772 |
prepare_reason(StringList) -> |
773 |
string:join(StringList, "_"). |
774 |
|
775 |
|
776 |
%%% |
777 |
%%% Sessions |
778 |
%%% |
779 |
|
780 |
num_resources(User, Host) -> |
781 |
length(ejabberd_sm:get_user_resources(User, Host)). |
782 |
|
783 |
resource_num(User, Host, Num) -> |
784 |
Resources = ejabberd_sm:get_user_resources(User, Host), |
785 |
case (0<Num) and (Num=<length(Resources)) of |
786 |
true -> |
787 |
lists:nth(Num, Resources); |
788 |
false -> |
789 |
lists:flatten(io_lib:format("Error: Wrong resource number: ~p", [Num])) |
790 |
end. |
791 |
|
792 |
kick_session(User, Server, Resource, ReasonText) -> |
793 |
kick_this_session(User, Server, Resource, prepare_reason(ReasonText)), |
794 |
ok. |
795 |
|
796 |
kick_this_session(User, Server, Resource, Reason) -> |
797 |
ejabberd_router:route( |
798 |
jlib:make_jid("", "", ""), |
799 |
jlib:make_jid(User, Server, Resource), |
800 |
{xmlelement, "broadcast", [], [{exit, Reason}]}). |
801 |
|
802 |
|
803 |
status_num(Host, Status) -> |
804 |
length(get_status_list(Host, Status)). |
805 |
status_num(Status) -> |
806 |
status_num("all", Status). |
807 |
status_list(Host, Status) -> |
808 |
Res = get_status_list(Host, Status), |
809 |
[{U, S, R, P, St} || {U, S, R, P, St} <- Res]. |
810 |
status_list(Status) -> |
811 |
status_list("all", Status). |
812 |
|
813 |
|
814 |
get_status_list(Host, Status_required) -> |
815 |
%% Get list of all logged users |
816 |
Sessions = ejabberd_sm:dirty_get_my_sessions_list(), |
817 |
%% Reformat the list |
818 |
Sessions2 = [ {Session#session.usr, Session#session.sid, Session#session.priority} || Session <- Sessions], |
819 |
Fhost = case Host of |
820 |
"all" -> |
821 |
%% All hosts are requested, so dont filter at all |
822 |
fun(_, _) -> true end; |
823 |
_ -> |
824 |
%% Filter the list, only Host is interesting |
825 |
fun(A, B) -> A == B end |
826 |
end, |
827 |
Sessions3 = [ {Pid, Server, Priority} || {{_User, Server, _Resource}, {_, Pid}, Priority} <- Sessions2, apply(Fhost, [Server, Host])], |
828 |
%% For each Pid, get its presence |
829 |
Sessions4 = [ {ejabberd_c2s:get_presence(Pid), Server, Priority} || {Pid, Server, Priority} <- Sessions3], |
830 |
%% Filter by status |
831 |
Fstatus = case Status_required of |
832 |
"all" -> |
833 |
fun(_, _) -> true end; |
834 |
_ -> |
835 |
fun(A, B) -> A == B end |
836 |
end, |
837 |
[{User, Server, Resource, Priority, stringize(Status_text)} |
838 |
|| {{User, Resource, Status, Status_text}, Server, Priority} <- Sessions4, |
839 |
apply(Fstatus, [Status, Status_required])]. |
840 |
|
841 |
connected_users_info() -> |
842 |
USRIs = dirty_get_sessions_list2(), |
843 |
CurrentSec = calendar:datetime_to_gregorian_seconds({date(), time()}), |
844 |
lists:map( |
845 |
fun([{U, S, R}, {Now, Pid}, Priority, Info]) -> |
846 |
Conn = proplists:get_value(conn, Info), |
847 |
{Ip, Port} = proplists:get_value(ip, Info), |
848 |
IPS = inet_parse:ntoa(Ip), |
849 |
NodeS = atom_to_list(node(Pid)), |
850 |
Uptime = CurrentSec - calendar:datetime_to_gregorian_seconds( |
851 |
calendar:now_to_local_time(Now)), |
852 |
{[U, $@, S, $/, R], atom_to_list(Conn), IPS, Port, Priority, NodeS, Uptime} |
853 |
end, |
854 |
USRIs). |
855 |
|
856 |
connected_users_vhost(Host) -> |
857 |
USRs = ejabberd_sm:get_vh_session_list(Host), |
858 |
[ [U, $@, S, $/, R] || {U, S, R} <- USRs]. |
859 |
|
860 |
%% Code copied from ejabberd_sm.erl and customized |
861 |
dirty_get_sessions_list2() -> |
862 |
mnesia:dirty_select( |
863 |
session, |
864 |
[{#session{usr = '$1', sid = '$2', priority = '$3', info = '$4', _ = '_'}, |
865 |
[], |
866 |
[['$1', '$2', '$3', '$4']]}]). |
867 |
|
868 |
%% Make string more print-friendly |
869 |
stringize(String) -> |
870 |
%% Replace newline characters with other code |
871 |
ejabberd_regexp:greplace(String, "\n", "\\n"). |
872 |
|
873 |
set_presence(User, Host, Resource, Type, Show, Status, Priority) -> |
874 |
Pid = ejabberd_sm:get_session_pid(User, Host, Resource), |
875 |
USR = User ++ "@" ++ Host ++ "/" ++ Resource, |
876 |
US = User ++ "@" ++ Host, |
877 |
Message = {route_xmlstreamelement, |
878 |
{xmlelement, "presence", |
879 |
[{"from", USR}, {"to", US}, {"type", Type}], |
880 |
[{xmlelement, "show", [], [{xmlcdata, Show}]}, |
881 |
{xmlelement, "status", [], [{xmlcdata, Status}]}, |
882 |
{xmlelement, "priority", [], [{xmlcdata, Priority}]}]}}, |
883 |
Pid ! Message. |
884 |
|
885 |
user_sessions_info(User, Host) -> |
886 |
CurrentSec = calendar:datetime_to_gregorian_seconds({date(), time()}), |
887 |
US = {User, Host}, |
888 |
Sessions = case catch mnesia:dirty_index_read(session, US, #session.us) of |
889 |
{'EXIT', _Reason} -> |
890 |
[]; |
891 |
Ss -> |
892 |
Ss |
893 |
end, |
894 |
lists:map( |
895 |
fun(Session) -> |
896 |
{_U, _S, Resource} = Session#session.usr, |
897 |
{Now, Pid} = Session#session.sid, |
898 |
{_U, _Resource, Status, StatusText} = ejabberd_c2s:get_presence(Pid), |
899 |
Info = Session#session.info, |
900 |
Priority = Session#session.priority, |
901 |
Conn = proplists:get_value(conn, Info), |
902 |
{Ip, Port} = proplists:get_value(ip, Info), |
903 |
IPS = inet_parse:ntoa(Ip), |
904 |
NodeS = atom_to_list(node(Pid)), |
905 |
Uptime = CurrentSec - calendar:datetime_to_gregorian_seconds( |
906 |
calendar:now_to_local_time(Now)), |
907 |
{atom_to_list(Conn), IPS, Port, Priority, NodeS, Uptime, Status, Resource, StatusText} |
908 |
end, |
909 |
Sessions). |
910 |
|
911 |
|
912 |
%%% |
913 |
%%% Vcard |
914 |
%%% |
915 |
|
916 |
set_nickname(User, Host, Nickname) -> |
917 |
R = mod_vcard:process_sm_iq( |
918 |
{jid, User, Host, "", User, Host, ""}, |
919 |
{jid, User, Host, "", User, Host, ""}, |
920 |
{iq, "", set, "", "en", |
921 |
{xmlelement, "vCard", |
922 |
[{"xmlns", "vcard-temp"}], [ |
923 |
{xmlelement, "NICKNAME", [], [{xmlcdata, Nickname}]} |
924 |
] |
925 |
}}), |
926 |
case R of |
927 |
{iq, [], result, [], _L, []} -> |
928 |
ok; |
929 |
_ -> |
930 |
error |
931 |
end. |
932 |
|
933 |
get_vcard(User, Host, Name) -> |
934 |
[Res | _] = get_vcard_content(User, Host, [Name]), |
935 |
Res. |
936 |
|
937 |
get_vcard(User, Host, Name, Subname) -> |
938 |
[Res | _] = get_vcard_content(User, Host, [Name, Subname]), |
939 |
Res. |
940 |
|
941 |
get_vcard_multi(User, Host, Name, Subname) -> |
942 |
get_vcard_content(User, Host, [Name, Subname]). |
943 |
|
944 |
set_vcard(User, Host, Name, SomeContent) -> |
945 |
set_vcard_content(User, Host, [Name], SomeContent). |
946 |
|
947 |
set_vcard(User, Host, Name, Subname, SomeContent) -> |
948 |
set_vcard_content(User, Host, [Name, Subname], SomeContent). |
949 |
|
950 |
|
951 |
%% |
952 |
%% Internal vcard |
953 |
|
954 |
get_module_resource(Server) -> |
955 |
case gen_mod:get_module_opt(Server, ?MODULE, module_resource, none) of |
956 |
none -> atom_to_list(?MODULE); |
957 |
R when is_list(R) -> R |
958 |
end. |
959 |
|
960 |
get_vcard_content(User, Server, Data) -> |
961 |
[{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}), |
962 |
JID = jlib:make_jid(User, Server, get_module_resource(Server)), |
963 |
IQ = #iq{type = get, xmlns = ?NS_VCARD}, |
964 |
IQr = Module:Function(JID, JID, IQ), |
965 |
case IQr#iq.sub_el of |
966 |
[A1] -> |
967 |
case get_vcard(Data, A1) of |
968 |
[] -> throw(error_no_value_found_in_vcard); |
969 |
ElemList -> [xml:get_tag_cdata(Elem) || Elem <- ElemList] |
970 |
end; |
971 |
[] -> |
972 |
throw(error_no_vcard_found) |
973 |
end. |
974 |
|
975 |
get_vcard([Data1, Data2], A1) -> |
976 |
case get_subtag(A1, Data1) of |
977 |
false -> false; |
978 |
A2List -> lists:flatten([get_vcard([Data2], A2) || A2 <- A2List]) |
979 |
end; |
980 |
|
981 |
get_vcard([Data], A1) -> |
982 |
get_subtag(A1, Data). |
983 |
|
984 |
get_subtag(Xmlelement, Name) -> |
985 |
case code:ensure_loaded(exmpp_xml) of |
986 |
{error, _} -> |
987 |
[get_subtag_xml(Xmlelement, Name)]; |
988 |
{module, exmpp_xml} -> |
989 |
get_subtag_exmpp(Xmlelement, Name) |
990 |
end. |
991 |
|
992 |
get_subtag_xml(Xmlelement, Name) -> |
993 |
xml:get_subtag(Xmlelement, Name). |
994 |
|
995 |
get_subtag_exmpp(Xmlelement, Name) -> |
996 |
Xmlel = exmpp_xml:xmlelement_to_xmlel(Xmlelement), |
997 |
XmlelList = exmpp_xml:get_elements(Xmlel, Name), |
998 |
[exmpp_xml:xmlel_to_xmlelement(Xmlel2) || Xmlel2 <- XmlelList]. |
999 |
|
1000 |
set_vcard_content(User, Server, Data, SomeContent) -> |
1001 |
ContentList = case SomeContent of |
1002 |
[Char | _] when not is_list(Char) -> [SomeContent]; |
1003 |
[Char | _] when is_list(Char) -> SomeContent |
1004 |
end, |
1005 |
[{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}), |
1006 |
JID = jlib:make_jid(User, Server, get_module_resource(Server)), |
1007 |
IQ = #iq{type = get, xmlns = ?NS_VCARD}, |
1008 |
IQr = Module:Function(JID, JID, IQ), |
1009 |
|
1010 |
%% Get old vcard |
1011 |
A4 = case IQr#iq.sub_el of |
1012 |
[A1] -> |
1013 |
{_, _, _, A2} = A1, |
1014 |
update_vcard_els(Data, ContentList, A2); |
1015 |
[] -> |
1016 |
update_vcard_els(Data, ContentList, []) |
1017 |
end, |
1018 |
|
1019 |
%% Build new vcard |
1020 |
SubEl = {xmlelement, "vCard", [{"xmlns","vcard-temp"}], A4}, |
1021 |
IQ2 = #iq{type=set, sub_el = SubEl}, |
1022 |
|
1023 |
Module:Function(JID, JID, IQ2), |
1024 |
ok. |
1025 |
|
1026 |
update_vcard_els(Data, ContentList, Els1) -> |
1027 |
Els2 = lists:keysort(2, Els1), |
1028 |
[Data1 | Data2] = Data, |
1029 |
NewEls = case Data2 of |
1030 |
[] -> |
1031 |
[{xmlelement, Data1, [], [{xmlcdata,Content}]} || Content <- ContentList]; |
1032 |
[D2] -> |
1033 |
OldEl = case lists:keysearch(Data1, 2, Els2) of |
1034 |
{value, A} -> A; |
1035 |
false -> {xmlelement, Data1, [], []} |
1036 |
end, |
1037 |
{xmlelement, _, _, ContentOld1} = OldEl, |
1038 |
Content2 = [{xmlelement, D2, [], [{xmlcdata,Content}]} || Content <- ContentList], |
1039 |
ContentOld2 = [A || {_, X, _, _} = A <- ContentOld1, X/=D2], |
1040 |
ContentOld3 = lists:keysort(2, ContentOld2), |
1041 |
ContentNew = lists:keymerge(2, Content2, ContentOld3), |
1042 |
[{xmlelement, Data1, [], ContentNew}] |
1043 |
end, |
1044 |
Els3 = lists:keydelete(Data1, 2, Els2), |
1045 |
lists:keymerge(2, NewEls, Els3). |
1046 |
|
1047 |
|
1048 |
%%% |
1049 |
%%% Roster |
1050 |
%%% |
1051 |
|
1052 |
add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group, Subs) -> |
1053 |
case add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group, list_to_atom(Subs), []) of |
1054 |
{atomic, ok} -> |
1055 |
push_roster_item(LocalUser, LocalServer, User, Server, {add, Nick, Subs, Group}), |
1056 |
ok; |
1057 |
_ -> |
1058 |
error |
1059 |
end. |
1060 |
|
1061 |
add_rosteritem(LU, LS, User, Server, Nick, Group, Subscription, Xattrs) -> |
1062 |
subscribe(LU, LS, User, Server, Nick, Group, Subscription, Xattrs). |
1063 |
|
1064 |
subscribe(LU, LS, User, Server, Nick, Group, Subscription, _Xattrs) -> |
1065 |
SubscriptionS = case is_atom(Subscription) of |
1066 |
true -> atom_to_list(Subscription); |
1067 |
false -> Subscription |
1068 |
end, |
1069 |
ItemEl = build_roster_item(User, Server, {add, Nick, SubscriptionS, Group}), |
1070 |
{ok, M} = loaded_module(LS,[mod_roster_odbc,mod_roster]), |
1071 |
M:set_items( |
1072 |
LU, LS, |
1073 |
{xmlelement,"query", |
1074 |
[{"xmlns","jabber:iq:roster"}], |
1075 |
[ItemEl]}). |
1076 |
|
1077 |
delete_rosteritem(LocalUser, LocalServer, User, Server) -> |
1078 |
case unsubscribe(LocalUser, LocalServer, User, Server) of |
1079 |
{atomic, ok} -> |
1080 |
push_roster_item(LocalUser, LocalServer, User, Server, remove), |
1081 |
ok; |
1082 |
_ -> |
1083 |
error |
1084 |
end. |
1085 |
|
1086 |
unsubscribe(LU, LS, User, Server) -> |
1087 |
ItemEl = build_roster_item(User, Server, remove), |
1088 |
{ok, M} = loaded_module(LS,[mod_roster_odbc,mod_roster]), |
1089 |
M:set_items( |
1090 |
LU, LS, |
1091 |
{xmlelement,"query", |
1092 |
[{"xmlns","jabber:iq:roster"}], |
1093 |
[ItemEl]}). |
1094 |
|
1095 |
loaded_module(Domain,Options) -> |
1096 |
LoadedModules = gen_mod:loaded_modules(Domain), |
1097 |
case lists:filter(fun(Module) -> |
1098 |
lists:member(Module, LoadedModules) |
1099 |
end, Options) of |
1100 |
[M|_] -> {ok, M}; |
1101 |
[] -> {error,not_found} |
1102 |
end. |
1103 |
|
1104 |
%% ----------------------------- |
1105 |
%% Get Roster |
1106 |
%% ----------------------------- |
1107 |
|
1108 |
get_roster(User, Server) -> |
1109 |
Items = ejabberd_hooks:run_fold(roster_get, Server, [], [{User, Server}]), |
1110 |
make_roster_xmlrpc(Items). |
1111 |
|
1112 |
%% Note: if a contact is in several groups, the contact is returned |
1113 |
%% several times, each one in a different group. |
1114 |
make_roster_xmlrpc(Roster) -> |
1115 |
lists:foldl( |
1116 |
fun(Item, Res) -> |
1117 |
JIDS = jlib:jid_to_string(Item#roster.jid), |
1118 |
Nick = Item#roster.name, |
1119 |
Subs = atom_to_list(Item#roster.subscription), |
1120 |
Ask = atom_to_list(Item#roster.ask), |
1121 |
Groups = case Item#roster.groups of |
1122 |
[] -> [""]; |
1123 |
Gs -> Gs |
1124 |
end, |
1125 |
ItemsX = [{JIDS, Nick, Subs, Ask, Group} |
1126 |
|| Group <- Groups], |
1127 |
ItemsX ++ Res |
1128 |
end, |
1129 |
[], |
1130 |
Roster). |
1131 |
|
1132 |
|
1133 |
%%----------------------------- |
1134 |
%% Push Roster from file |
1135 |
%%----------------------------- |
1136 |
|
1137 |
push_roster(File, User, Server) -> |
1138 |
{ok, [Roster]} = file:consult(File), |
1139 |
subscribe_roster({User, Server, "", User}, Roster). |
1140 |
|
1141 |
push_roster_all(File) -> |
1142 |
{ok, [Roster]} = file:consult(File), |
1143 |
subscribe_all(Roster). |
1144 |
|
1145 |
subscribe_all(Roster) -> |
1146 |
subscribe_all(Roster, Roster). |
1147 |
subscribe_all([], _) -> |
1148 |
ok; |
1149 |
subscribe_all([User1 | Users], Roster) -> |
1150 |
subscribe_roster(User1, Roster), |
1151 |
subscribe_all(Users, Roster). |
1152 |
|
1153 |
subscribe_roster(_, []) -> |
1154 |
ok; |
1155 |
%% Do not subscribe a user to itself |
1156 |
subscribe_roster({Name, Server, Group, Nick}, [{Name, Server, _, _} | Roster]) -> |
1157 |
subscribe_roster({Name, Server, Group, Nick}, Roster); |
1158 |
%% Subscribe Name2 to Name1 |
1159 |
subscribe_roster({Name1, Server1, Group1, Nick1}, [{Name2, Server2, Group2, Nick2} | Roster]) -> |
1160 |
subscribe(Name1, Server1, Name2, Server2, Nick2, Group2, both, []), |
1161 |
subscribe_roster({Name1, Server1, Group1, Nick1}, Roster). |
1162 |
|
1163 |
push_alltoall(S, G) -> |
1164 |
Users = ejabberd_auth:get_vh_registered_users(S), |
1165 |
Users2 = build_list_users(G, Users, []), |
1166 |
subscribe_all(Users2), |
1167 |
ok. |
1168 |
|
1169 |
build_list_users(_Group, [], Res) -> |
1170 |
Res; |
1171 |
build_list_users(Group, [{User, Server}|Users], Res) -> |
1172 |
build_list_users(Group, Users, [{User, Server, Group, User}|Res]). |
1173 |
|
1174 |
%% @spec(LU, LS, U, S, Action) -> ok |
1175 |
%% Action = {add, Nick, Subs, Group} | remove |
1176 |
%% @doc Push to the roster of account LU@LS the contact U@S. |
1177 |
%% The specific action to perform is defined in Action. |
1178 |
push_roster_item(LU, LS, U, S, Action) -> |
1179 |
lists:foreach(fun(R) -> |
1180 |
push_roster_item(LU, LS, R, U, S, Action) |
1181 |
end, ejabberd_sm:get_user_resources(LU, LS)). |
1182 |
|
1183 |
push_roster_item(LU, LS, R, U, S, Action) -> |
1184 |
LJID = jlib:make_jid(LU, LS, R), |
1185 |
BroadcastEl = build_broadcast(U, S, Action), |
1186 |
ejabberd_router:route(LJID, LJID, BroadcastEl), |
1187 |
Item = build_roster_item(U, S, Action), |
1188 |
ResIQ = build_iq_roster_push(Item), |
1189 |
ejabberd_router:route(LJID, LJID, ResIQ). |
1190 |
|
1191 |
build_roster_item(U, S, {add, Nick, Subs, Group}) -> |
1192 |
{xmlelement, "item", |
1193 |
[{"jid", jlib:jid_to_string(jlib:make_jid(U, S, ""))}, |
1194 |
{"name", Nick}, |
1195 |
{"subscription", Subs}], |
1196 |
[{xmlelement, "group", [], [{xmlcdata, Group}]}] |
1197 |
}; |
1198 |
build_roster_item(U, S, remove) -> |
1199 |
{xmlelement, "item", |
1200 |
[{"jid", jlib:jid_to_string(jlib:make_jid(U, S, ""))}, |
1201 |
{"subscription", "remove"}], |
1202 |
[] |
1203 |
}. |
1204 |
|
1205 |
build_iq_roster_push(Item) -> |
1206 |
{xmlelement, "iq", |
1207 |
[{"type", "set"}, {"id", "push"}], |
1208 |
[{xmlelement, "query", |
1209 |
[{"xmlns", ?NS_ROSTER}], |
1210 |
[Item] |
1211 |
} |
1212 |
] |
1213 |
}. |
1214 |
|
1215 |
build_broadcast(U, S, {add, _Nick, Subs, _Group}) -> |
1216 |
build_broadcast(U, S, list_to_atom(Subs)); |
1217 |
build_broadcast(U, S, remove) -> |
1218 |
build_broadcast(U, S, none); |
1219 |
%% @spec (U::string(), S::string(), Subs::atom()) -> any() |
1220 |
%% Subs = both | from | to | none |
1221 |
build_broadcast(U, S, SubsAtom) when is_atom(SubsAtom) -> |
1222 |
{xmlelement, "broadcast", [], |
1223 |
[{item, {U, S, ""}, SubsAtom}] |
1224 |
}. |
1225 |
|
1226 |
%%% |
1227 |
%%% Last Activity |
1228 |
%%% |
1229 |
|
1230 |
set_last(User, Server, Timestamp, Status) -> |
1231 |
Mod = get_lastactivity_module(Server), |
1232 |
Mod:store_last_info(User, Server, Timestamp, Status). |
1233 |
|
1234 |
%%% |
1235 |
%%% Private Storage |
1236 |
%%% |
1237 |
|
1238 |
%% Example usage: |
1239 |
%% $ ejabberdctl private_set badlop localhost "\<aa\ xmlns=\'bb\'\>Cluth\</aa\>" |
1240 |
%% $ ejabberdctl private_get badlop localhost aa bb |
1241 |
%% <aa xmlns='bb'>Cluth</aa> |
1242 |
|
1243 |
private_get(Username, Host, Element, Ns) -> |
1244 |
From = jlib:make_jid(Username, Host, ""), |
1245 |
To = jlib:make_jid(Username, Host, ""), |
1246 |
IQ = {iq, "", get, ?NS_PRIVATE, "", |
1247 |
{xmlelement,"query", |
1248 |
[{"xmlns",?NS_PRIVATE}], |
1249 |
[{xmlelement, Element, [{"xmlns", Ns}], []}]}}, |
1250 |
ResIq = mod_private:process_sm_iq(From, To, IQ), |
1251 |
[{xmlelement,"query", |
1252 |
[{"xmlns","jabber:iq:private"}], |
1253 |
[SubEl]}] = ResIq#iq.sub_el, |
1254 |
xml:element_to_string(SubEl). |
1255 |
|
1256 |
private_set(Username, Host, ElementString) -> |
1257 |
case xml_stream:parse_element(ElementString) of |
1258 |
{error, Error} -> |
1259 |
io:format("Error found parsing the element:~n ~p~nError: ~p~n", |
1260 |
[ElementString, Error]), |
1261 |
error; |
1262 |
Xml -> |
1263 |
private_set2(Username, Host, Xml) |
1264 |
end. |
1265 |
|
1266 |
private_set2(Username, Host, Xml) -> |
1267 |
From = jlib:make_jid(Username, Host, ""), |
1268 |
To = jlib:make_jid(Username, Host, ""), |
1269 |
IQ = {iq, "", set, ?NS_PRIVATE, "", |
1270 |
{xmlelement,"query", |
1271 |
[{"xmlns",?NS_PRIVATE}], |
1272 |
[Xml]}}, |
1273 |
mod_private:process_sm_iq(From, To, IQ), |
1274 |
ok. |
1275 |
|
1276 |
%%% |
1277 |
%%% Shared Roster Groups |
1278 |
%%% |
1279 |
|
1280 |
srg_create(Group, Host, Name, Description, Display) -> |
1281 |
DisplayList = case Display of |
1282 |
[] -> []; |
1283 |
_ -> ejabberd_regexp:split(Display, "\\\\n") |
1284 |
end, |
1285 |
Opts = [{name, Name}, |
1286 |
{displayed_groups, DisplayList}, |
1287 |
{description, Description}], |
1288 |
{atomic, ok} = mod_shared_roster:create_group(Host, Group, Opts), |
1289 |
ok. |
1290 |
|
1291 |
srg_delete(Group, Host) -> |
1292 |
{atomic, ok} = mod_shared_roster:delete_group(Host, Group), |
1293 |
ok. |
1294 |
|
1295 |
srg_list(Host) -> |
1296 |
lists:sort(mod_shared_roster:list_groups(Host)). |
1297 |
|
1298 |
srg_get_info(Group, Host) -> |
1299 |
Opts = mod_shared_roster:get_group_opts(Host,Group), |
1300 |
[{io_lib:format("~p", [Title]), |
1301 |
io_lib:format("~p", [Value])} || {Title, Value} <- Opts]. |
1302 |
|
1303 |
srg_get_members(Group, Host) -> |
1304 |
Members = mod_shared_roster:get_group_explicit_users(Host,Group), |
1305 |
[jlib:jid_to_string(jlib:make_jid(MUser, MServer, "")) |
1306 |
|| {MUser, MServer} <- Members]. |
1307 |
|
1308 |
srg_user_add(User, Host, Group, GroupHost) -> |
1309 |
{atomic, ok} = mod_shared_roster:add_user_to_group(GroupHost, {User, Host}, Group), |
1310 |
ok. |
1311 |
|
1312 |
srg_user_del(User, Host, Group, GroupHost) -> |
1313 |
{atomic, ok} = mod_shared_roster:remove_user_from_group(GroupHost, {User, Host}, Group), |
1314 |
ok. |
1315 |
|
1316 |
|
1317 |
%%% |
1318 |
%%% Stanza |
1319 |
%%% |
1320 |
|
1321 |
%% @doc Send a chat message to a Jabber account. |
1322 |
%% @spec (From::string(), To::string(), Body::string()) -> ok |
1323 |
send_message_chat(From, To, Body) -> |
1324 |
Packet = build_packet(message_chat, [Body]), |
1325 |
send_packet_all_resources(From, To, Packet). |
1326 |
|
1327 |
%% @doc Send a headline message to a Jabber account. |
1328 |
%% @spec (From::string(), To::string(), Subject::string(), Body::string()) -> ok |
1329 |
send_message_headline(From, To, Subject, Body) -> |
1330 |
Packet = build_packet(message_headline, [Subject, Body]), |
1331 |
send_packet_all_resources(From, To, Packet). |
1332 |
|
1333 |
%% @doc Send a packet to a Jabber account. |
1334 |
%% If a resource was specified in the JID, |
1335 |
%% the packet is sent only to that specific resource. |
1336 |
%% If no resource was specified in the JID, |
1337 |
%% and the user is remote or local but offline, |
1338 |
%% the packet is sent to the bare JID. |
1339 |
%% If the user is local and is online in several resources, |
1340 |
%% the packet is sent to all its resources. |
1341 |
send_packet_all_resources(FromJIDString, ToJIDString, Packet) -> |
1342 |
FromJID = jlib:string_to_jid(FromJIDString), |
1343 |
ToJID = jlib:string_to_jid(ToJIDString), |
1344 |
ToUser = ToJID#jid.user, |
1345 |
ToServer = ToJID#jid.server, |
1346 |
case ToJID#jid.resource of |
1347 |
"" -> |
1348 |
send_packet_all_resources(FromJID, ToUser, ToServer, Packet); |
1349 |
Res -> |
1350 |
send_packet_all_resources(FromJID, ToUser, ToServer, Res, Packet) |
1351 |
end. |
1352 |
|
1353 |
send_packet_all_resources(FromJID, ToUser, ToServer, Packet) -> |
1354 |
case ejabberd_sm:get_user_resources(ToUser, ToServer) of |
1355 |
[] -> |
1356 |
send_packet_all_resources(FromJID, ToUser, ToServer, "", Packet); |
1357 |
ToResources -> |
1358 |
lists:foreach( |
1359 |
fun(ToResource) -> |
1360 |
send_packet_all_resources(FromJID, ToUser, ToServer, |
1361 |
ToResource, Packet) |
1362 |
end, |
1363 |
ToResources) |
1364 |
end. |
1365 |
|
1366 |
send_packet_all_resources(FromJID, ToU, ToS, ToR, Packet) -> |
1367 |
ToJID = jlib:make_jid(ToU, ToS, ToR), |
1368 |
ejabberd_router:route(FromJID, ToJID, Packet). |
1369 |
|
1370 |
|
1371 |
build_packet(message_chat, [Body]) -> |
1372 |
{xmlelement, "message", |
1373 |
[{"type", "chat"}, {"id", randoms:get_string()}], |
1374 |
[{xmlelement, "body", [], [{xmlcdata, Body}]}] |
1375 |
}; |
1376 |
build_packet(message_headline, [Subject, Body]) -> |
1377 |
{xmlelement, "message", |
1378 |
[{"type", "headline"}, {"id", randoms:get_string()}], |
1379 |
[{xmlelement, "subject", [], [{xmlcdata, Subject}]}, |
1380 |
{xmlelement, "body", [], [{xmlcdata, Body}]} |
1381 |
] |
1382 |
}. |
1383 |
|
1384 |
send_stanza_c2s(Username, Host, Resource, Stanza) -> |
1385 |
C2sPid = ejabberd_sm:get_session_pid(Username, Host, Resource), |
1386 |
XmlEl = xml_stream:parse_element(Stanza), |
1387 |
p1_fsm:send_event(C2sPid, {xmlstreamelement, XmlEl}). |
1388 |
|
1389 |
privacy_set(Username, Host, QueryS) -> |
1390 |
From = jlib:string_to_jid(Username ++ "@" ++ Host), |
1391 |
To = jlib:string_to_jid(Host), |
1392 |
QueryEl = xml_stream:parse_element(QueryS), |
1393 |
StanzaEl = {xmlelement, "iq", [{"type", "set"}], [QueryEl]}, |
1394 |
IQ = jlib:iq_query_info(StanzaEl), |
1395 |
ejabberd_hooks:run_fold( |
1396 |
privacy_iq_set, |
1397 |
Host, |
1398 |
{error, ?ERR_FEATURE_NOT_IMPLEMENTED}, |
1399 |
[From, To, IQ] |
1400 |
), |
1401 |
ok. |
1402 |
|
1403 |
%%% |
1404 |
%%% Stats |
1405 |
%%% |
1406 |
|
1407 |
stats(Name) -> |
1408 |
case Name of |
1409 |
"uptimeseconds" -> trunc(element(1, erlang:statistics(wall_clock))/1000); |
1410 |
"registeredusers" -> length(ejabberd_auth:dirty_get_registered_users()); |
1411 |
"onlineusersnode" -> length(ejabberd_sm:dirty_get_my_sessions_list()); |
1412 |
"onlineusers" -> length(ejabberd_sm:dirty_get_sessions_list()) |
1413 |
end. |
1414 |
|
1415 |
stats(Name, Host) -> |
1416 |
case Name of |
1417 |
"registeredusers" -> length(ejabberd_auth:get_vh_registered_users(Host)); |
1418 |
"onlineusers" -> length(ejabberd_sm:get_vh_session_list(Host)) |
1419 |
end. |
1420 |
|
1421 |
|
1422 |
|
1423 |
%%----------------------------- |
1424 |
%% Purge roster items |
1425 |
%%----------------------------- |
1426 |
|
1427 |
process_rosteritems(ActionS, SubsS, AsksS, UsersS, ContactsS) -> |
1428 |
Action = case ActionS of |
1429 |
"list" -> list; |
1430 |
"delete" -> delete |
1431 |
end, |
1432 |
|
1433 |
Subs = lists:foldl( |
1434 |
fun(any, _) -> [none, from, to, both]; |
1435 |
(Sub, Subs) -> [Sub | Subs] |
1436 |
end, |
1437 |
[], |
1438 |
[list_to_atom(S) || S <- string:tokens(SubsS, ":")] |
1439 |
), |
1440 |
|
1441 |
Asks = lists:foldl( |
1442 |
fun(any, _) -> [none, out, in]; |
1443 |
(Ask, Asks) -> [Ask | Asks] |
1444 |
end, |
1445 |
[], |
1446 |
[list_to_atom(S) || S <- string:tokens(AsksS, ":")] |
1447 |
), |
1448 |
|
1449 |
Users = lists:foldl( |
1450 |
fun("any", _) -> ["*", "*@*"]; |
1451 |
(U, Us) -> [U | Us] |
1452 |
end, |
1453 |
[], |
1454 |
[S || S <- string:tokens(UsersS, ":")] |
1455 |
), |
1456 |
|
1457 |
Contacts = lists:foldl( |
1458 |
fun("any", _) -> ["*", "*@*"]; |
1459 |
(U, Us) -> [U | Us] |
1460 |
end, |
1461 |
[], |
1462 |
[S || S <- string:tokens(ContactsS, ":")] |
1463 |
), |
1464 |
|
1465 |
case rosteritem_purge({Action, Subs, Asks, Users, Contacts}) of |
1466 |
{atomic, ok} -> |
1467 |
ok; |
1468 |
{error, Reason} -> |
1469 |
io:format("Error purging rosteritems: ~p~n", [Reason]), |
1470 |
error; |
1471 |
{badrpc, Reason} -> |
1472 |
io:format("BadRPC purging rosteritems: ~p~n", [Reason]), |
1473 |
error |
1474 |
end. |
1475 |
|
1476 |
%% @spec ({Action::atom(), Subs::[atom()], Asks::[atom()], User::string(), Contact::string()}) -> {atomic, ok} |
1477 |
rosteritem_purge(Options) -> |
1478 |
Num_rosteritems = mnesia:table_info(roster, size), |
1479 |
io:format("There are ~p roster items in total.~n", [Num_rosteritems]), |
1480 |
Key = mnesia:dirty_first(roster), |
1481 |
ok = rip(Key, Options, {0, Num_rosteritems, 0, 0}), |
1482 |
{atomic, ok}. |
1483 |
|
1484 |
rip('$end_of_table', _Options, Counters) -> |
1485 |
print_progress_line(Counters), |
1486 |
ok; |
1487 |
rip(Key, Options, {Pr, NT, NV, ND}) -> |
1488 |
Key_next = mnesia:dirty_next(roster, Key), |
1489 |
{Action, _, _, _, _} = Options, |
1490 |
ND2 = case decide_rip(Key, Options) of |
1491 |
true -> |
1492 |
apply_action(Action, Key), |
1493 |
ND+1; |
1494 |
false -> |
1495 |
ND |
1496 |
end, |
1497 |
NV2 = NV+1, |
1498 |
Pr2 = print_progress_line({Pr, NT, NV2, ND2}), |
1499 |
rip(Key_next, Options, {Pr2, NT, NV2, ND2}). |
1500 |
|
1501 |
apply_action(list, Key) -> |
1502 |
{User, Server, JID} = Key, |
1503 |
{RUser, RServer, _} = JID, |
1504 |
io:format("Matches: ~s@~s ~s@~s~n", [User, Server, RUser, RServer]); |
1505 |
apply_action(delete, Key) -> |
1506 |
apply_action(list, Key), |
1507 |
mnesia:dirty_delete(roster, Key). |
1508 |
|
1509 |
print_progress_line({Pr, NT, NV, ND}) -> |
1510 |
Pr2 = trunc((NV/NT)*100), |
1511 |
case Pr == Pr2 of |
1512 |
true -> |
1513 |
ok; |
1514 |
false -> |
1515 |
io:format("Progress ~p% - visited ~p - deleted ~p~n", [Pr2, NV, ND]) |
1516 |
end, |
1517 |
Pr2. |
1518 |
|
1519 |
decide_rip(Key, {_Action, Subs, Asks, User, Contact}) -> |
1520 |
case catch mnesia:dirty_read(roster, Key) of |
1521 |
[RI] -> |
1522 |
lists:member(RI#roster.subscription, Subs) |
1523 |
andalso lists:member(RI#roster.ask, Asks) |
1524 |
andalso decide_rip_jid(RI#roster.us, User) |
1525 |
andalso decide_rip_jid(RI#roster.jid, Contact); |
1526 |
_ -> |
1527 |
false |
1528 |
end. |
1529 |
|
1530 |
%% Returns true if the server of the JID is included in the servers |
1531 |
decide_rip_jid({UName, UServer, _UResource}, Match_list) -> |
1532 |
decide_rip_jid({UName, UServer}, Match_list); |
1533 |
decide_rip_jid({UName, UServer}, Match_list) -> |
1534 |
lists:any( |
1535 |
fun(Match_string) -> |
1536 |
MJID = jlib:string_to_jid(Match_string), |
1537 |
MName = MJID#jid.luser, |
1538 |
MServer = MJID#jid.lserver, |
1539 |
Is_server = is_glob_match(UServer, MServer), |
1540 |
case MName of |
1541 |
[] when UName == [] -> |
1542 |
Is_server; |
1543 |
[] -> |
1544 |
false; |
1545 |
_ -> |
1546 |
Is_server |
1547 |
andalso is_glob_match(UName, MName) |
1548 |
end |
1549 |
end, |
1550 |
Match_list). |
1551 |
|
1552 |
%% Copied from ejabberd-2.0.0/src/acl.erl |
1553 |
is_regexp_match(String, RegExp) -> |
1554 |
case ejabberd_regexp:run(String, RegExp) of |
1555 |
nomatch -> |
1556 |
false; |
1557 |
match -> |
1558 |
true; |
1559 |
{error, ErrDesc} -> |
1560 |
io:format( |
1561 |
"Wrong regexp ~p in ACL: ~p", |
1562 |
[RegExp, ErrDesc]), |
1563 |
false |
1564 |
end. |
1565 |
is_glob_match(String, [$! | Glob]) -> |
1566 |
not is_regexp_match(String, ejabberd_regexp:sh_to_awk(Glob)); |
1567 |
is_glob_match(String, Glob) -> |
1568 |
is_regexp_match(String, ejabberd_regexp:sh_to_awk(Glob)). |