• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

processone / ejabberd / 603

17 Oct 2023 01:57PM UTC coverage: 32.654% (-0.4%) from 33.021%
603

push

github

badlop
Fixing minor typos in CHANGELOG

13497 of 41333 relevant lines covered (32.65%)

646.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

58.37
/src/mod_muc_sql.erl
1
%%%-------------------------------------------------------------------
2
%%% File    : mod_muc_sql.erl
3
%%% Author  : Evgeny Khramtsov <ekhramtsov@process-one.net>
4
%%% Created : 13 Apr 2016 by Evgeny Khramtsov <ekhramtsov@process-one.net>
5
%%%
6
%%%
7
%%% ejabberd, Copyright (C) 2002-2023   ProcessOne
8
%%%
9
%%% This program is free software; you can redistribute it and/or
10
%%% modify it under the terms of the GNU General Public License as
11
%%% published by the Free Software Foundation; either version 2 of the
12
%%% License, or (at your option) any later version.
13
%%%
14
%%% This program is distributed in the hope that it will be useful,
15
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
16
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
%%% General Public License for more details.
18
%%%
19
%%% You should have received a copy of the GNU General Public License along
20
%%% with this program; if not, write to the Free Software Foundation, Inc.,
21
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
%%%
23
%%%----------------------------------------------------------------------
24

25
-module(mod_muc_sql).
26

27

28
-behaviour(mod_muc).
29
-behaviour(mod_muc_room).
30

31
%% API
32
-export([init/2, store_room/5, store_changes/4,
33
         restore_room/3, forget_room/3,
34
         can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4,
35
         import/3, export/1]).
36
-export([register_online_room/4, unregister_online_room/4, find_online_room/3,
37
         get_online_rooms/3, count_online_rooms/2, rsm_supported/0,
38
         register_online_user/4, unregister_online_user/4,
39
         count_online_rooms_by_user/3, get_online_rooms_by_user/3,
40
         get_subscribed_rooms/3, get_rooms_without_subscribers/2,
41
         get_hibernated_rooms_older_than/3,
42
         find_online_room_by_pid/2, remove_user/2]).
43
-export([set_affiliation/6, set_affiliations/4, get_affiliation/5,
44
         get_affiliations/3, search_affiliation/4]).
45

46
-include_lib("xmpp/include/jid.hrl").
47
-include("mod_muc.hrl").
48
-include("logger.hrl").
49
-include("ejabberd_sql_pt.hrl").
50

51
%%%===================================================================
52
%%% API
53
%%%===================================================================
54
init(Host, Opts) ->
55
    ejabberd_sql_schema:update_schema(Host, ?MODULE, schemas()),
6✔
56
    case gen_mod:ram_db_mod(Opts, mod_muc) of
6✔
57
        ?MODULE ->
58
            clean_tables(Host);
6✔
59
        _ ->
60
            ok
×
61
    end.
62

63
schemas() ->
64
    [#sql_schema{
6✔
65
        version = 1,
66
        tables =
67
            [#sql_table{
68
                name = <<"muc_room">>,
69
                columns =
70
                    [#sql_column{name = <<"name">>, type = text},
71
                     #sql_column{name = <<"host">>, type = text},
72
                     #sql_column{name = <<"server_host">>, type = text},
73
                     #sql_column{name = <<"opts">>, type = {text, big}},
74
                     #sql_column{name = <<"created_at">>, type = timestamp,
75
                                 default = true}],
76
                indices = [#sql_index{
77
                              columns = [<<"name">>, <<"host">>],
78
                              unique = true},
79
                           #sql_index{
80
                              columns = [<<"host">>, <<"created_at">>]}]},
81
             #sql_table{
82
                name = <<"muc_registered">>,
83
                columns =
84
                    [#sql_column{name = <<"jid">>, type = text},
85
                     #sql_column{name = <<"host">>, type = text},
86
                     #sql_column{name = <<"server_host">>, type = text},
87
                     #sql_column{name = <<"nick">>, type = text},
88
                     #sql_column{name = <<"created_at">>, type = timestamp,
89
                                 default = true}],
90
                indices = [#sql_index{
91
                              columns = [<<"jid">>, <<"host">>],
92
                              unique = true},
93
                           #sql_index{
94
                              columns = [<<"nick">>]}]},
95
             #sql_table{
96
                name = <<"muc_online_room">>,
97
                columns =
98
                    [#sql_column{name = <<"name">>, type = text},
99
                     #sql_column{name = <<"host">>, type = text},
100
                     #sql_column{name = <<"server_host">>, type = text},
101
                     #sql_column{name = <<"node">>, type = text},
102
                     #sql_column{name = <<"pid">>, type = text}],
103
                indices = [#sql_index{
104
                              columns = [<<"name">>, <<"host">>],
105
                              unique = true}]},
106
             #sql_table{
107
                name = <<"muc_online_users">>,
108
                columns =
109
                    [#sql_column{name = <<"username">>, type = text},
110
                     #sql_column{name = <<"server">>, type = {text, 75}},
111
                     #sql_column{name = <<"resource">>, type = text},
112
                     #sql_column{name = <<"name">>, type = text},
113
                     #sql_column{name = <<"host">>, type = {text, 75}},
114
                     #sql_column{name = <<"server_host">>, type = text},
115
                     #sql_column{name = <<"node">>, type = text}],
116
                indices = [#sql_index{
117
                              columns = [<<"username">>, <<"server">>,
118
                                         <<"resource">>, <<"name">>,
119
                                         <<"host">>],
120
                              unique = true}]},
121
             #sql_table{
122
                name = <<"muc_room_subscribers">>,
123
                columns =
124
                    [#sql_column{name = <<"room">>, type = text},
125
                     #sql_column{name = <<"host">>, type = text},
126
                     #sql_column{name = <<"jid">>, type = text},
127
                     #sql_column{name = <<"nick">>, type = text},
128
                     #sql_column{name = <<"nodes">>, type = text},
129
                     #sql_column{name = <<"created_at">>, type = timestamp,
130
                                 default = true}],
131
                indices = [#sql_index{
132
                              columns = [<<"host">>, <<"room">>, <<"jid">>],
133
                              unique = true},
134
                           #sql_index{
135
                              columns = [<<"host">>, <<"jid">>]},
136
                           #sql_index{
137
                              columns = [<<"jid">>]}]}]}].
138

139
store_room(LServer, Host, Name, Opts, ChangesHints) ->
140
    {Subs, Opts2} = case lists:keytake(subscribers, 1, Opts) of
291✔
141
                        {value, {subscribers, S}, OptN} -> {S, OptN};
291✔
142
                        _ -> {[], Opts}
×
143
                    end,
144
    SOpts = misc:term_to_expr(Opts2),
291✔
145
    Timestamp = case lists:keyfind(hibernation_time, 1, Opts) of
291✔
146
                    false -> <<"1970-01-02 00:00:00">>;
×
147
                    {_, undefined} -> <<"1970-01-02 00:00:00">>;
291✔
148
                    {_, Time} -> usec_to_sql_timestamp(Time)
×
149
                end,
150
    F = fun () ->
291✔
151
                ?SQL_UPSERT_T(
291✔
152
                   "muc_room",
153
                   ["!name=%(Name)s",
154
                    "!host=%(Host)s",
155
                    "server_host=%(LServer)s",
156
                    "opts=%(SOpts)s",
157
                    "created_at=%(Timestamp)t"]),
158
                case ChangesHints of
291✔
159
                    Changes when is_list(Changes) ->
160
                        [change_room(Host, Name, Change) || Change <- Changes];
291✔
161
                    _ ->
162
                        ejabberd_sql:sql_query_t(
×
163
                          ?SQL("delete from muc_room_subscribers where "
×
164
                               "room=%(Name)s and host=%(Host)s")),
165
                        [change_room(Host, Name, {add_subscription, JID, Nick, Nodes})
×
166
                         || {JID, Nick, Nodes} <- Subs]
×
167
                end
168
        end,
169
    ejabberd_sql:sql_transaction(LServer, F).
291✔
170

171
store_changes(LServer, Host, Name, Changes) ->
172
    F = fun () ->
54✔
173
                [change_room(Host, Name, Change) || Change <- Changes]
54✔
174
        end,
175
    ejabberd_sql:sql_transaction(LServer, F).
54✔
176

177
change_room(Host, Room, {add_subscription, JID, Nick, Nodes}) ->
178
    SJID = jid:encode(JID),
27✔
179
    SNodes = misc:term_to_expr(Nodes),
27✔
180
    ?SQL_UPSERT_T(
27✔
181
       "muc_room_subscribers",
182
       ["!jid=%(SJID)s",
183
        "!host=%(Host)s",
184
        "!room=%(Room)s",
185
        "nick=%(Nick)s",
186
        "nodes=%(SNodes)s"]);
187
change_room(Host, Room, {del_subscription, JID}) ->
188
    SJID = jid:encode(JID),
27✔
189
    ejabberd_sql:sql_query_t(?SQL("delete from muc_room_subscribers where "
27✔
190
                                  "room=%(Room)s and host=%(Host)s and jid=%(SJID)s"));
191
change_room(Host, Room, Change) ->
192
    ?ERROR_MSG("Unsupported change on room ~ts@~ts: ~p", [Room, Host, Change]).
×
193

194
restore_room(LServer, Host, Name) ->
195
    case catch ejabberd_sql:sql_query(
138✔
196
                 LServer,
197
                 ?SQL("select @(opts)s from muc_room where name=%(Name)s"
186✔
198
                      " and host=%(Host)s")) of
199
        {selected, [{Opts}]} ->
200
            OptsD = ejabberd_sql:decode_term(Opts),
×
201
            case catch ejabberd_sql:sql_query(
×
202
                LServer,
203
                ?SQL("select @(jid)s, @(nick)s, @(nodes)s from muc_room_subscribers where room=%(Name)s"
×
204
                     " and host=%(Host)s")) of
205
                {selected, []} ->
206
                    OptsR = mod_muc:opts_to_binary(OptsD),
×
207
                    case lists:keymember(subscribers, 1, OptsD) of
×
208
                        true ->
209
                            store_room(LServer, Host, Name, OptsR, undefined);
×
210
                        _ ->
211
                            ok
×
212
                    end,
213
                    OptsR;
×
214
                {selected, Subs} ->
215
                    SubData = lists:map(
×
216
                             fun({Jid, Nick, Nodes}) ->
217
                                 {jid:decode(Jid), Nick, ejabberd_sql:decode_term(Nodes)}
×
218
                             end, Subs),
219
                    Opts2 = lists:keystore(subscribers, 1, OptsD, {subscribers, SubData}),
×
220
                    mod_muc:opts_to_binary(Opts2);
×
221
                _ ->
222
                    error
×
223
            end;
224
        _ ->
225
            error
138✔
226
    end.
227

228
forget_room(LServer, Host, Name) ->
229
    F = fun () ->
264✔
230
                ejabberd_sql:sql_query_t(
264✔
231
                  ?SQL("delete from muc_room where name=%(Name)s"
354✔
232
                       " and host=%(Host)s")),
233
                ejabberd_sql:sql_query_t(
264✔
234
                    ?SQL("delete from muc_room_subscribers where room=%(Name)s"
354✔
235
                       " and host=%(Host)s"))
236
        end,
237
    ejabberd_sql:sql_transaction(LServer, F).
264✔
238

239
can_use_nick(LServer, ServiceOrRoom, JID, Nick) ->
240
    SJID = jid:encode(jid:tolower(jid:remove_resource(JID))),
267✔
241
    SqlQuery = case (jid:decode(ServiceOrRoom))#jid.lserver of
267✔
242
                   ServiceOrRoom ->
243
                       ?SQL("select @(jid)s from muc_registered "
×
244
                            "where nick=%(Nick)s"
245
                            " and host=%(ServiceOrRoom)s");
246
                   Service ->
247
                       ?SQL("select @(jid)s from muc_registered "
267✔
248
                            "where nick=%(Nick)s"
249
                            " and (host=%(ServiceOrRoom)s or host=%(Service)s)")
250
               end,
251
    case catch ejabberd_sql:sql_query(LServer, SqlQuery) of
267✔
252
        {selected, [{SJID1}]} -> SJID == SJID1;
×
253
        _ -> true
267✔
254
    end.
255

256
get_rooms_without_subscribers(LServer, Host) ->
257
    case catch ejabberd_sql:sql_query(
×
258
        LServer,
259
        ?SQL("select @(name)s, @(opts)s from muc_room"
×
260
             " where host=%(Host)s")) of
261
        {selected, RoomOpts} ->
262
            lists:map(
×
263
                fun({Room, Opts}) ->
264
                    OptsD = ejabberd_sql:decode_term(Opts),
×
265
                    #muc_room{name_host = {Room, Host},
×
266
                              opts = mod_muc:opts_to_binary(OptsD)}
267
                end, RoomOpts);
268
        _Err ->
269
            []
×
270
    end.
271

272
get_hibernated_rooms_older_than(LServer, Host, Timestamp) ->
273
    TimestampS = usec_to_sql_timestamp(Timestamp),
×
274
    case catch ejabberd_sql:sql_query(
×
275
        LServer,
276
        ?SQL("select @(name)s, @(opts)s from muc_room"
×
277
             " where host=%(Host)s and created_at < %(TimestampS)t and created_at > '1970-01-02 00:00:00'")) of
278
        {selected, RoomOpts} ->
279
            lists:map(
×
280
                fun({Room, Opts}) ->
281
                    OptsD = ejabberd_sql:decode_term(Opts),
×
282
                    #muc_room{name_host = {Room, Host},
×
283
                              opts = mod_muc:opts_to_binary(OptsD)}
284
                end, RoomOpts);
285
        _Err ->
286
            []
×
287
    end.
288

289
get_rooms(LServer, Host) ->
290
    case catch ejabberd_sql:sql_query(
3✔
291
                 LServer,
292
                 ?SQL("select @(name)s, @(opts)s from muc_room"
6✔
293
                      " where host=%(Host)s")) of
294
        {selected, RoomOpts} ->
295
            case catch ejabberd_sql:sql_query(
3✔
296
                LServer,
297
                ?SQL("select @(room)s, @(jid)s, @(nick)s, @(nodes)s from muc_room_subscribers"
6✔
298
                     " where host=%(Host)s")) of
299
                {selected, Subs} ->
300
                    SubsD = lists:foldl(
3✔
301
                        fun({Room, Jid, Nick, Nodes}, Dict) ->
302
                                Sub = {jid:decode(Jid),
×
303
                                       Nick, ejabberd_sql:decode_term(Nodes)},
304
                                maps:update_with(
×
305
                                  Room,
306
                                  fun(SubAcc) ->
307
                                          [Sub | SubAcc]
×
308
                                  end,
309
                                  [Sub],
310
                                  Dict)
311
                        end, maps:new(), Subs),
312
            lists:map(
3✔
313
              fun({Room, Opts}) ->
314
                            OptsD = ejabberd_sql:decode_term(Opts),
×
315
                            OptsD2 = case {maps:find(Room, SubsD), lists:keymember(subscribers, 1, OptsD)} of
×
316
                                         {_, true} ->
317
                                             store_room(LServer, Host, Room, mod_muc:opts_to_binary(OptsD), undefined),
×
318
                                             OptsD;
×
319
                                         {{ok, SubsI}, false} ->
320
                                             lists:keystore(subscribers, 1, OptsD, {subscribers, SubsI});
×
321
                                         _ ->
322
                                             OptsD
×
323
                            end,
324
                      #muc_room{name_host = {Room, Host},
×
325
                                      opts = mod_muc:opts_to_binary(OptsD2)}
326
              end, RoomOpts);
327
        _Err ->
328
                    []
×
329
            end;
330
        _Err ->
331
            []
×
332
    end.
333

334
get_nick(LServer, Host, From) ->
335
    SJID = jid:encode(jid:tolower(jid:remove_resource(From))),
24✔
336
    case catch ejabberd_sql:sql_query(
24✔
337
                 LServer,
338
                 ?SQL("select @(nick)s from muc_registered where"
34✔
339
                      " jid=%(SJID)s and host=%(Host)s")) of
340
        {selected, [{Nick}]} -> Nick;
15✔
341
        _ -> error
9✔
342
    end.
343

344
set_nick(LServer, ServiceOrRoom, From, Nick) ->
345
    JID = jid:encode(jid:tolower(jid:remove_resource(From))),
18✔
346
    F = fun () ->
18✔
347
                case Nick of
18✔
348
                    <<"">> ->
349
                        ejabberd_sql:sql_query_t(
6✔
350
                          ?SQL("delete from muc_registered where"
10✔
351
                               " jid=%(JID)s and host=%(ServiceOrRoom)s")),
352
                        ok;
6✔
353
                    _ ->
354
                        Service = (jid:decode(ServiceOrRoom))#jid.lserver,
12✔
355
                        SqlQuery = case (ServiceOrRoom == Service) of
12✔
356
                                       true ->
357
                                           ?SQL("select @(jid)s, @(host)s from muc_registered "
12✔
358
                                                "where nick=%(Nick)s"
359
                                                " and host=%(ServiceOrRoom)s");
360
                                       false ->
361
                                           ?SQL("select @(jid)s, @(host)s from muc_registered "
×
362
                                                "where nick=%(Nick)s"
363
                                                " and (host=%(ServiceOrRoom)s or host=%(Service)s)")
364
                                   end,
365
                        Allow = case ejabberd_sql:sql_query_t(SqlQuery) of
12✔
366
                                    {selected, []}
367
                                      when (ServiceOrRoom == Service) ->
368
                                        %% Registering in the service...
369
                                        %% check if nick is registered for some room in this service
370
                                        {selected, NickRegistrations} =
9✔
371
                                            ejabberd_sql:sql_query_t(
372
                                              ?SQL("select @(jid)s, @(host)s from muc_registered "
14✔
373
                                                   "where nick=%(Nick)s")),
374
                                        not lists:any(fun({_NRJid, NRServiceOrRoom}) ->
9✔
375
                                                              Service == (jid:decode(NRServiceOrRoom))#jid.lserver end,
×
376
                                                      NickRegistrations);
377
                                    {selected, []} ->
378
                                        %% Nick not registered in any service or room
379
                                        true;
×
380
                                    {selected, [{_J, Host}]}
381
                                      when (Host == Service) and (ServiceOrRoom /= Service) ->
382
                                        %% Registering in a room, but the nick is already registered in the service
383
                                        false;
×
384
                                    {selected, [{J, _Host}]} ->
385
                                        %% Registering in room (or service) a nick that is
386
                                        %% already registered in this room (or service)
387
                                        %% Only the owner of this registration can use the nick
388
                                        J == JID
3✔
389
                                end,
390
                        if Allow ->
12✔
391
                                ?SQL_UPSERT_T(
9✔
392
                                  "muc_registered",
393
                                  ["!jid=%(JID)s",
394
                                   "!host=%(ServiceOrRoom)s",
395
                                   "server_host=%(LServer)s",
396
                                   "nick=%(Nick)s"]),
397
                                ok;
9✔
398
                           true ->
399
                                false
3✔
400
                        end
401
                end
402
        end,
403
    ejabberd_sql:sql_transaction(LServer, F).
18✔
404

405
set_affiliation(_ServerHost, _Room, _Host, _JID, _Affiliation, _Reason) ->
406
    {error, not_implemented}.
27✔
407

408
set_affiliations(_ServerHost, _Room, _Host, _Affiliations) ->
409
    {error, not_implemented}.
129✔
410

411
get_affiliation(_ServerHost, _Room, _Host, _LUser, _LServer) ->
412
    {error, not_implemented}.
1,209✔
413

414
get_affiliations(_ServerHost, _Room, _Host) ->
415
    {error, not_implemented}.
126✔
416

417
search_affiliation(_ServerHost, _Room, _Host, _Affiliation) ->
418
    {error, not_implemented}.
33✔
419

420
register_online_room(ServerHost, Room, Host, Pid) ->
421
    PidS = misc:encode_pid(Pid),
138✔
422
    NodeS = erlang:atom_to_binary(node(Pid), latin1),
138✔
423
    case ?SQL_UPSERT(ServerHost,
138✔
424
                     "muc_online_room",
425
                     ["!name=%(Room)s",
426
                      "!host=%(Host)s",
427
                      "server_host=%(ServerHost)s",
428
                      "node=%(NodeS)s",
429
                      "pid=%(PidS)s"]) of
430
        ok ->
431
            ok;
138✔
432
        Err ->
433
            Err
×
434
    end.
435

436
unregister_online_room(ServerHost, Room, Host, Pid) ->
437
    %% TODO: report errors
438
    PidS = misc:encode_pid(Pid),
138✔
439
    NodeS = erlang:atom_to_binary(node(Pid), latin1),
138✔
440
    ejabberd_sql:sql_query(
138✔
441
      ServerHost,
442
      ?SQL("delete from muc_online_room where name=%(Room)s and "
186✔
443
           "host=%(Host)s and node=%(NodeS)s and pid=%(PidS)s")).
444

445
find_online_room(ServerHost, Room, Host) ->
446
    case ejabberd_sql:sql_query(
1,564✔
447
           ServerHost,
448
           ?SQL("select @(pid)s, @(node)s from muc_online_room where "
2,088✔
449
                "name=%(Room)s and host=%(Host)s")) of
450
        {selected, [{PidS, NodeS}]} ->
451
            try {ok, misc:decode_pid(PidS, NodeS)}
1,280✔
452
            catch _:{bad_node, _} -> error
×
453
            end;
454
        {selected, []} ->
455
            error;
284✔
456
        _Err ->
457
            error
×
458
    end.
459

460
find_online_room_by_pid(ServerHost, Pid) ->
461
    PidS = misc:encode_pid(Pid),
138✔
462
    NodeS = erlang:atom_to_binary(node(Pid), latin1),
138✔
463
    case ejabberd_sql:sql_query(
138✔
464
        ServerHost,
465
        ?SQL("select @(name)s, @(host)s from muc_online_room where "
186✔
466
             "node=%(NodeS)s and pid=%(PidS)s")) of
467
        {selected, [{Room, Host}]} ->
468
            {ok, Room, Host};
138✔
469
        {selected, []} ->
470
            error;
×
471
        _Err ->
472
            error
×
473
    end.
474

475
count_online_rooms(ServerHost, Host) ->
476
    case ejabberd_sql:sql_query(
12✔
477
           ServerHost,
478
           ?SQL("select @(count(*))d from muc_online_room "
18✔
479
                "where host=%(Host)s")) of
480
        {selected, [{Num}]} ->
481
            Num;
12✔
482
        _Err ->
483
            0
×
484
    end.
485

486
get_online_rooms(ServerHost, Host, _RSM) ->
487
    case ejabberd_sql:sql_query(
21✔
488
           ServerHost,
489
           ?SQL("select @(name)s, @(pid)s, @(node)s from muc_online_room "
30✔
490
                "where host=%(Host)s")) of
491
        {selected, Rows} ->
492
            lists:flatmap(
21✔
493
              fun({Room, PidS, NodeS}) ->
494
                      try [{Room, Host, misc:decode_pid(PidS, NodeS)}]
24✔
495
                      catch _:{bad_node, _} -> []
×
496
                      end
497
              end, Rows);
498
        _Err ->
499
            []
×
500
    end.
501

502
rsm_supported() ->
503
    false.
6✔
504

505
register_online_user(ServerHost, {U, S, R}, Room, Host) ->
506
    NodeS = erlang:atom_to_binary(node(), latin1),
222✔
507
    case ?SQL_UPSERT(ServerHost, "muc_online_users",
222✔
508
                     ["!username=%(U)s",
509
                      "!server=%(S)s",
510
                      "!resource=%(R)s",
511
                      "!name=%(Room)s",
512
                      "!host=%(Host)s",
513
                      "server_host=%(ServerHost)s",
514
                      "node=%(NodeS)s"]) of
515
        ok ->
516
            ok;
222✔
517
        Err ->
518
            Err
×
519
    end.
520

521
unregister_online_user(ServerHost, {U, S, R}, Room, Host) ->
522
    %% TODO: report errors
523
    ejabberd_sql:sql_query(
222✔
524
      ServerHost,
525
      ?SQL("delete from muc_online_users where username=%(U)s and "
298✔
526
           "server=%(S)s and resource=%(R)s and name=%(Room)s and "
527
           "host=%(Host)s")).
528

529
count_online_rooms_by_user(ServerHost, U, S) ->
530
    case ejabberd_sql:sql_query(
261✔
531
           ServerHost,
532
           ?SQL("select @(count(*))d from muc_online_users where "
350✔
533
                "username=%(U)s and server=%(S)s")) of
534
        {selected, [{Num}]} ->
535
            Num;
261✔
536
        _Err ->
537
            0
×
538
    end.
539

540
get_online_rooms_by_user(ServerHost, U, S) ->
541
    case ejabberd_sql:sql_query(
×
542
           ServerHost,
543
           ?SQL("select @(name)s, @(host)s from muc_online_users where "
×
544
                "username=%(U)s and server=%(S)s")) of
545
        {selected, Rows} ->
546
            Rows;
×
547
        _Err ->
548
            []
×
549
    end.
550

551
export(_Server) ->
552
    [{muc_room,
×
553
      fun(Host, #muc_room{name_host = {Name, RoomHost}, opts = Opts}) ->
554
              case str:suffix(Host, RoomHost) of
×
555
                  true ->
556
                      SOpts = misc:term_to_expr(Opts),
×
557
                      [?SQL("delete from muc_room where name=%(Name)s"
×
558
                            " and host=%(RoomHost)s;"),
559
                       ?SQL_INSERT(
×
560
                          "muc_room",
561
                          ["name=%(Name)s",
562
                           "host=%(RoomHost)s",
563
                           "server_host=%(Host)s",
564
                           "opts=%(SOpts)s"])];
565
                  false ->
566
                      []
×
567
              end
568
      end},
569
     {muc_registered,
570
      fun(Host, #muc_registered{us_host = {{U, S}, RoomHost},
571
                                nick = Nick}) ->
572
              case str:suffix(Host, RoomHost) of
×
573
                  true ->
574
                      SJID = jid:encode(jid:make(U, S)),
×
575
                      [?SQL("delete from muc_registered where"
×
576
                            " jid=%(SJID)s and host=%(RoomHost)s;"),
577
                       ?SQL_INSERT(
×
578
                          "muc_registered",
579
                          ["jid=%(SJID)s",
580
                           "host=%(RoomHost)s",
581
                           "server_host=%(Host)s",
582
                           "nick=%(Nick)s"])];
583
                  false ->
584
                      []
×
585
              end
586
      end}].
587

588
import(_, _, _) ->
589
    ok.
×
590

591
get_subscribed_rooms(LServer, Host, Jid) ->
592
    JidS = jid:encode(Jid),
3✔
593
    case ejabberd_sql:sql_query(
3✔
594
           LServer,
595
           ?SQL("select @(room)s, @(nick)s, @(nodes)s from muc_room_subscribers "
6✔
596
                "where jid=%(JidS)s and host=%(Host)s")) of
597
        {selected, Subs} ->
598
            {ok, [{jid:make(Room, Host), Nick, ejabberd_sql:decode_term(Nodes)}
3✔
599
                  || {Room, Nick, Nodes} <- Subs]};
3✔
600
        _Error ->
601
            {error, db_failure}
×
602
    end.
603

604
remove_user(LUser, LServer) ->
605
    SJID = jid:encode(jid:make(LUser, LServer)),
6✔
606
    ejabberd_sql:sql_query(
6✔
607
      LServer,
608
      ?SQL("delete from muc_room_subscribers where jid=%(SJID)s")),
10✔
609
    ok.
6✔
610

611
%%%===================================================================
612
%%% Internal functions
613
%%%===================================================================
614
clean_tables(ServerHost) ->
615
    NodeS = erlang:atom_to_binary(node(), latin1),
6✔
616
    ?DEBUG("Cleaning SQL muc_online_room table...", []),
6✔
617
    case ejabberd_sql:sql_query(
6✔
618
           ServerHost,
619
           ?SQL("delete from muc_online_room where node=%(NodeS)s")) of
10✔
620
        {updated, _} ->
621
            ok;
6✔
622
        Err1 ->
623
            ?ERROR_MSG("Failed to clean 'muc_online_room' table: ~p", [Err1]),
×
624
            Err1
×
625
    end,
626
    ?DEBUG("Cleaning SQL muc_online_users table...", []),
6✔
627
    case ejabberd_sql:sql_query(
6✔
628
           ServerHost,
629
           ?SQL("delete from muc_online_users where node=%(NodeS)s")) of
10✔
630
        {updated, _} ->
631
            ok;
6✔
632
        Err2 ->
633
            ?ERROR_MSG("Failed to clean 'muc_online_users' table: ~p", [Err2]),
×
634
            Err2
×
635
    end.
636

637
usec_to_sql_timestamp(Timestamp) ->
638
    TS = misc:usec_to_now(Timestamp),
×
639
    case calendar:now_to_universal_time(TS) of
×
640
        {{Year, Month, Day}, {Hour, Minute, Second}} ->
641
            list_to_binary(io_lib:format("~4..0B-~2..0B-~2..0B "
×
642
                                         "~2..0B:~2..0B:~2..0B",
643
                                         [Year, Month, Day, Hour, Minute, Second]))
644
    end.
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc