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

processone / ejabberd / 1212

18 Nov 2025 12:37PM UTC coverage: 33.784% (+0.003%) from 33.781%
1212

push

github

badlop
mod_conversejs: Improve link to conversejs in WebAdmin (#4495)

Until now, the WebAdmin menu included a link to the first request handler
with mod_conversejs that the admin configured in ejabberd.yml
That link included the authentication credentials hashed as URI arguments
if using HTTPS. Then process/2 extracted those arguments and passed them
as autologin options to Converse.

From now, mod_conversejs automatically adds a request_handler nested in
webadmin subpath. The webadmin menu links to that converse URI; this allows
to access the HTTP auth credentials, no need to explicitly pass them.
process/2 extracts this HTTP auth and passes autologin options to Converse.
Now scram password storage is supported too.

This minimum configuration allows WebAdmin to access Converse:

listen:
  -
    port: 5443
    module: ejabberd_http
    tls: true
    request_handlers:
      /admin: ejabberd_web_admin
      /ws: ejabberd_http_ws
modules:
  mod_conversejs:
    conversejs_resources: "/home/conversejs/12.0.0/dist"

0 of 12 new or added lines in 1 file covered. (0.0%)

11290 existing lines in 174 files now uncovered.

15515 of 45924 relevant lines covered (33.78%)

1277.8 hits per line

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

56.48
/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-2025   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, get_nicks/2, 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
-export([sql_schemas/0]).
46

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

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

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

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

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

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

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

231
forget_room(LServer, Host, Name) ->
UNCOV
232
    F = fun () ->
630✔
UNCOV
233
                ejabberd_sql:sql_query_t(
630✔
UNCOV
234
                  ?SQL("delete from muc_room where name=%(Name)s"
814✔
235
                       " and host=%(Host)s")),
UNCOV
236
                ejabberd_sql:sql_query_t(
630✔
UNCOV
237
                    ?SQL("delete from muc_room_subscribers where room=%(Name)s"
814✔
238
                       " and host=%(Host)s"))
239
        end,
UNCOV
240
    ejabberd_sql:sql_transaction(LServer, F).
630✔
241

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

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

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

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

337
get_nick(LServer, Host, From) ->
UNCOV
338
    SJID = jid:encode(jid:tolower(jid:remove_resource(From))),
98✔
UNCOV
339
    case catch ejabberd_sql:sql_query(
98✔
340
                 LServer,
UNCOV
341
                 ?SQL("select @(nick)s from muc_registered where"
130✔
342
                      " jid=%(SJID)s and host=%(Host)s")) of
UNCOV
343
        {selected, [{Nick}]} -> Nick;
56✔
UNCOV
344
        _ -> error
42✔
345
    end.
346

347
get_nicks(LServer, Host) ->
348
    case catch ejabberd_sql:sql_query(LServer,
×
349
                                      ?SQL("select @(jid)s, @(nick)s from muc_registered where"
×
350
                                           " host=%(Host)s"))
351
    of
352
        {selected, Results} ->
353
            lists:map(fun({JidBin, Nick}) ->
×
354
                         {User, Server, _Resource} =
×
355
                             jid:tolower(
356
                                 jid:decode(JidBin)),
357
                         {User, Server, Nick}
×
358
                      end,
359
                      Results);
360
        _ ->
361
            error
×
362
    end.
363

364
set_nick(LServer, ServiceOrRoom, From, Nick) ->
UNCOV
365
    JID = jid:encode(jid:tolower(jid:remove_resource(From))),
56✔
UNCOV
366
    F = fun () ->
56✔
UNCOV
367
                case Nick of
56✔
368
                    <<"">> ->
UNCOV
369
                        ejabberd_sql:sql_query_t(
28✔
UNCOV
370
                          ?SQL("delete from muc_registered where"
40✔
371
                               " jid=%(JID)s and host=%(ServiceOrRoom)s")),
UNCOV
372
                        ok;
28✔
373
                    _ ->
UNCOV
374
                        Service = (jid:decode(ServiceOrRoom))#jid.lserver,
28✔
UNCOV
375
                        SqlQuery = case (ServiceOrRoom == Service) of
28✔
376
                                       true ->
UNCOV
377
                                           ?SQL("select @(jid)s, @(host)s from muc_registered "
28✔
378
                                                "where nick=%(Nick)s"
379
                                                " and host=%(ServiceOrRoom)s");
380
                                       false ->
381
                                           ?SQL("select @(jid)s, @(host)s from muc_registered "
×
382
                                                "where nick=%(Nick)s"
383
                                                " and (host=%(ServiceOrRoom)s or host=%(Service)s)")
384
                                   end,
UNCOV
385
                        Allow = case ejabberd_sql:sql_query_t(SqlQuery) of
28✔
386
                                    {selected, []}
387
                                      when (ServiceOrRoom == Service) ->
388
                                        %% Registering in the service...
389
                                        %% check if nick is registered for some room in this service
UNCOV
390
                                        {selected, NickRegistrations} =
21✔
391
                                            ejabberd_sql:sql_query_t(
UNCOV
392
                                              ?SQL("select @(jid)s, @(host)s from muc_registered "
31✔
393
                                                   "where nick=%(Nick)s")),
UNCOV
394
                                        not lists:any(fun({_NRJid, NRServiceOrRoom}) ->
21✔
395
                                                              Service == (jid:decode(NRServiceOrRoom))#jid.lserver end,
×
396
                                                      NickRegistrations);
397
                                    {selected, []} ->
398
                                        %% Nick not registered in any service or room
399
                                        true;
×
400
                                    {selected, [{_J, Host}]}
401
                                      when (Host == Service) and (ServiceOrRoom /= Service) ->
402
                                        %% Registering in a room, but the nick is already registered in the service
403
                                        false;
×
404
                                    {selected, [{J, _Host}]} ->
405
                                        %% Registering in room (or service) a nick that is
406
                                        %% already registered in this room (or service)
407
                                        %% Only the owner of this registration can use the nick
UNCOV
408
                                        J == JID
7✔
409
                                end,
UNCOV
410
                        if Allow ->
28✔
UNCOV
411
                                ?SQL_UPSERT_T(
21✔
412
                                  "muc_registered",
413
                                  ["!jid=%(JID)s",
414
                                   "!host=%(ServiceOrRoom)s",
415
                                   "server_host=%(LServer)s",
416
                                   "nick=%(Nick)s"]),
UNCOV
417
                                ok;
21✔
418
                           true ->
UNCOV
419
                                false
7✔
420
                        end
421
                end
422
        end,
UNCOV
423
    ejabberd_sql:sql_transaction(LServer, F).
56✔
424

425
set_affiliation(_ServerHost, _Room, _Host, _JID, _Affiliation, _Reason) ->
UNCOV
426
    {error, not_implemented}.
63✔
427

428
set_affiliations(_ServerHost, _Room, _Host, _Affiliations) ->
UNCOV
429
    {error, not_implemented}.
308✔
430

431
get_affiliation(_ServerHost, _Room, _Host, _LUser, _LServer) ->
UNCOV
432
    {error, not_implemented}.
2,891✔
433

434
get_affiliations(_ServerHost, _Room, _Host) ->
UNCOV
435
    {error, not_implemented}.
301✔
436

437
search_affiliation(_ServerHost, _Room, _Host, _Affiliation) ->
UNCOV
438
    {error, not_implemented}.
77✔
439

440
register_online_room(ServerHost, Room, Host, Pid) ->
UNCOV
441
    PidS = misc:encode_pid(Pid),
329✔
UNCOV
442
    NodeS = erlang:atom_to_binary(node(Pid), latin1),
329✔
UNCOV
443
    case ?SQL_UPSERT(ServerHost,
329✔
444
                     "muc_online_room",
445
                     ["!name=%(Room)s",
446
                      "!host=%(Host)s",
447
                      "server_host=%(ServerHost)s",
448
                      "node=%(NodeS)s",
449
                      "pid=%(PidS)s"]) of
450
        ok ->
UNCOV
451
            ok;
329✔
452
        Err ->
453
            Err
×
454
    end.
455

456
unregister_online_room(ServerHost, Room, Host, Pid) ->
457
    %% TODO: report errors
UNCOV
458
    PidS = misc:encode_pid(Pid),
329✔
UNCOV
459
    NodeS = erlang:atom_to_binary(node(Pid), latin1),
329✔
UNCOV
460
    ejabberd_sql:sql_query(
329✔
461
      ServerHost,
UNCOV
462
      ?SQL("delete from muc_online_room where name=%(Room)s and "
427✔
463
           "host=%(Host)s and node=%(NodeS)s and pid=%(PidS)s")).
464

465
find_online_room(ServerHost, Room, Host) ->
UNCOV
466
    case ejabberd_sql:sql_query(
3,724✔
467
           ServerHost,
UNCOV
468
           ?SQL("select @(pid)s, @(node)s from muc_online_room where "
4,792✔
469
                "name=%(Room)s and host=%(Host)s")) of
470
        {selected, [{PidS, NodeS}]} ->
UNCOV
471
            try {ok, misc:decode_pid(PidS, NodeS)}
3,052✔
472
            catch _:{bad_node, _} -> error
×
473
            end;
474
        {selected, []} ->
UNCOV
475
            error;
672✔
476
        _Err ->
477
            error
×
478
    end.
479

480
find_online_room_by_pid(ServerHost, Pid) ->
UNCOV
481
    PidS = misc:encode_pid(Pid),
329✔
UNCOV
482
    NodeS = erlang:atom_to_binary(node(Pid), latin1),
329✔
UNCOV
483
    case ejabberd_sql:sql_query(
329✔
484
        ServerHost,
UNCOV
485
        ?SQL("select @(name)s, @(host)s from muc_online_room where "
427✔
486
             "node=%(NodeS)s and pid=%(PidS)s")) of
487
        {selected, [{Room, Host}]} ->
UNCOV
488
            {ok, Room, Host};
329✔
489
        {selected, []} ->
490
            error;
×
491
        _Err ->
492
            error
×
493
    end.
494

495
count_online_rooms(ServerHost, Host) ->
UNCOV
496
    case ejabberd_sql:sql_query(
28✔
497
           ServerHost,
UNCOV
498
           ?SQL("select @(count(*))d from muc_online_room "
40✔
499
                "where host=%(Host)s")) of
500
        {selected, [{Num}]} ->
UNCOV
501
            Num;
28✔
502
        _Err ->
503
            0
×
504
    end.
505

506
get_online_rooms(ServerHost, Host, _RSM) ->
UNCOV
507
    case ejabberd_sql:sql_query(
49✔
508
           ServerHost,
UNCOV
509
           ?SQL("select @(name)s, @(pid)s, @(node)s from muc_online_room "
67✔
510
                "where host=%(Host)s")) of
511
        {selected, Rows} ->
UNCOV
512
            lists:flatmap(
49✔
513
              fun({Room, PidS, NodeS}) ->
UNCOV
514
                      try [{Room, Host, misc:decode_pid(PidS, NodeS)}]
56✔
515
                      catch _:{bad_node, _} -> []
×
516
                      end
517
              end, Rows);
518
        _Err ->
519
            []
×
520
    end.
521

522
rsm_supported() ->
UNCOV
523
    false.
42✔
524

525
register_online_user(ServerHost, {U, S, R}, Room, Host) ->
UNCOV
526
    NodeS = erlang:atom_to_binary(node(), latin1),
532✔
UNCOV
527
    case ?SQL_UPSERT(ServerHost, "muc_online_users",
532✔
528
                     ["!username=%(U)s",
529
                      "!server=%(S)s",
530
                      "!resource=%(R)s",
531
                      "!name=%(Room)s",
532
                      "!host=%(Host)s",
533
                      "server_host=%(ServerHost)s",
534
                      "node=%(NodeS)s"]) of
535
        ok ->
UNCOV
536
            ok;
532✔
537
        Err ->
538
            Err
×
539
    end.
540

541
unregister_online_user(ServerHost, {U, S, R}, Room, Host) ->
542
    %% TODO: report errors
UNCOV
543
    ejabberd_sql:sql_query(
532✔
544
      ServerHost,
UNCOV
545
      ?SQL("delete from muc_online_users where username=%(U)s and "
688✔
546
           "server=%(S)s and resource=%(R)s and name=%(Room)s and "
547
           "host=%(Host)s")).
548

549
count_online_rooms_by_user(ServerHost, U, S) ->
UNCOV
550
    case ejabberd_sql:sql_query(
623✔
551
           ServerHost,
UNCOV
552
           ?SQL("select @(count(*))d from muc_online_users where "
805✔
553
                "username=%(U)s and server=%(S)s")) of
554
        {selected, [{Num}]} ->
UNCOV
555
            Num;
623✔
556
        _Err ->
557
            0
×
558
    end.
559

560
get_online_rooms_by_user(ServerHost, U, S) ->
561
    case ejabberd_sql:sql_query(
×
562
           ServerHost,
563
           ?SQL("select @(name)s, @(host)s from muc_online_users where "
×
564
                "username=%(U)s and server=%(S)s")) of
565
        {selected, Rows} ->
566
            Rows;
×
567
        _Err ->
568
            []
×
569
    end.
570

571
export(_Server) ->
572
    [{muc_room,
×
573
      fun(Host, #muc_room{name_host = {Name, RoomHost}, opts = Opts}) ->
574
              case str:suffix(Host, RoomHost) of
×
575
                  true ->
576
                      SOpts = misc:term_to_expr(Opts),
×
577
                      [?SQL("delete from muc_room where name=%(Name)s"
×
578
                            " and host=%(RoomHost)s;"),
579
                       ?SQL_INSERT(
×
580
                          "muc_room",
581
                          ["name=%(Name)s",
582
                           "host=%(RoomHost)s",
583
                           "server_host=%(Host)s",
584
                           "opts=%(SOpts)s"])];
585
                  false ->
586
                      []
×
587
              end
588
      end},
589
     {muc_registered,
590
      fun(Host, #muc_registered{us_host = {{U, S}, RoomHost},
591
                                nick = Nick}) ->
592
              case str:suffix(Host, RoomHost) of
×
593
                  true ->
594
                      SJID = jid:encode(jid:make(U, S)),
×
595
                      [?SQL("delete from muc_registered where"
×
596
                            " jid=%(SJID)s and host=%(RoomHost)s;"),
597
                       ?SQL_INSERT(
×
598
                          "muc_registered",
599
                          ["jid=%(SJID)s",
600
                           "host=%(RoomHost)s",
601
                           "server_host=%(Host)s",
602
                           "nick=%(Nick)s"])];
603
                  false ->
604
                      []
×
605
              end
606
      end}].
607

608
import(_, _, _) ->
609
    ok.
×
610

611
get_subscribed_rooms(LServer, Host, Jid) ->
UNCOV
612
    JidS = jid:encode(Jid),
7✔
UNCOV
613
    case ejabberd_sql:sql_query(
7✔
614
           LServer,
UNCOV
615
           ?SQL("select @(room)s, @(nick)s, @(nodes)s from muc_room_subscribers "
13✔
616
                "where jid=%(JidS)s and host=%(Host)s")) of
617
        {selected, Subs} ->
UNCOV
618
            {ok, [{jid:make(Room, Host), Nick, ejabberd_sql:decode_term(Nodes)}
7✔
UNCOV
619
                  || {Room, Nick, Nodes} <- Subs]};
7✔
620
        _Error ->
621
            {error, db_failure}
×
622
    end.
623

624
remove_user(LUser, LServer) ->
UNCOV
625
    SJID = jid:encode(jid:make(LUser, LServer)),
14✔
UNCOV
626
    ejabberd_sql:sql_query(
14✔
627
      LServer,
UNCOV
628
      ?SQL("delete from muc_room_subscribers where jid=%(SJID)s")),
22✔
UNCOV
629
    ok.
14✔
630

631
%%%===================================================================
632
%%% Internal functions
633
%%%===================================================================
634
clean_tables(ServerHost) ->
UNCOV
635
    NodeS = erlang:atom_to_binary(node(), latin1),
14✔
UNCOV
636
    ?DEBUG("Cleaning SQL muc_online_room table...", []),
14✔
UNCOV
637
    case ejabberd_sql:sql_query(
14✔
638
           ServerHost,
UNCOV
639
           ?SQL("delete from muc_online_room where node=%(NodeS)s")) of
22✔
640
        {updated, _} ->
UNCOV
641
            ok;
14✔
642
        Err1 ->
643
            ?ERROR_MSG("Failed to clean 'muc_online_room' table: ~p", [Err1]),
×
644
            Err1
×
645
    end,
UNCOV
646
    ?DEBUG("Cleaning SQL muc_online_users table...", []),
14✔
UNCOV
647
    case ejabberd_sql:sql_query(
14✔
648
           ServerHost,
UNCOV
649
           ?SQL("delete from muc_online_users where node=%(NodeS)s")) of
22✔
650
        {updated, _} ->
UNCOV
651
            ok;
14✔
652
        Err2 ->
653
            ?ERROR_MSG("Failed to clean 'muc_online_users' table: ~p", [Err2]),
×
654
            Err2
×
655
    end.
656

657
usec_to_sql_timestamp(Timestamp) ->
658
    TS = misc:usec_to_now(Timestamp),
×
659
    case calendar:now_to_universal_time(TS) of
×
660
        {{Year, Month, Day}, {Hour, Minute, Second}} ->
661
            list_to_binary(io_lib:format("~4..0B-~2..0B-~2..0B "
×
662
                                         "~2..0B:~2..0B:~2..0B",
663
                                         [Year, Month, Day, Hour, Minute, Second]))
664
    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

© 2025 Coveralls, Inc