1 |
|
%%%---------------------------------------------------------------------- |
2 |
|
%%% Based on file mod_muc. |
3 |
|
%%% |
4 |
|
%%% Original header and copyright notice: |
5 |
|
%%% |
6 |
|
%%% Author : Alexey Shchepin <alexey@process-one.net> |
7 |
|
%%% Purpose : MUC support (XEP-0045) |
8 |
|
%%% |
9 |
|
%%% |
10 |
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne |
11 |
|
%%% |
12 |
|
%%% This program is free software; you can redistribute it and/or |
13 |
|
%%% modify it under the terms of the GNU General Public License as |
14 |
|
%%% published by the Free Software Foundation; either version 2 of the |
15 |
|
%%% License, or (at your option) any later version. |
16 |
|
%%% |
17 |
|
%%% This program is distributed in the hope that it will be useful, |
18 |
|
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 |
|
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
20 |
|
%%% General Public License for more details. |
21 |
|
%%% |
22 |
|
%%% You should have received a copy of the GNU General Public License |
23 |
|
%%% along with this program; if not, write to the Free Software |
24 |
|
%%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
25 |
|
%%% |
26 |
|
%%%---------------------------------------------------------------------- |
27 |
|
|
28 |
|
-module(mod_muc_mnesia). |
29 |
|
-behaviour(mod_muc_backend). |
30 |
|
-export([init/2, |
31 |
|
store_room/4, |
32 |
|
restore_room/3, |
33 |
|
forget_room/3, |
34 |
|
get_rooms/2, |
35 |
|
can_use_nick/4, |
36 |
|
get_nick/3, |
37 |
|
set_nick/4, |
38 |
|
unset_nick/3]). |
39 |
|
|
40 |
|
-include("mongoose.hrl"). |
41 |
|
-include("jlib.hrl"). |
42 |
|
-include("mod_muc.hrl"). |
43 |
|
|
44 |
|
-record(muc_registered, { |
45 |
|
us_host :: {US :: jid:simple_bare_jid(), MucHost :: jid:lserver()} | '$1', |
46 |
|
nick :: mod_muc:nick() |
47 |
|
}). |
48 |
|
|
49 |
|
init(_HostType, _Opts) -> |
50 |
8 |
mongoose_mnesia:create_table(muc_room, |
51 |
|
[{disc_copies, [node()]}, |
52 |
|
{attributes, record_info(fields, muc_room)}]), |
53 |
8 |
mongoose_mnesia:create_table(muc_registered, |
54 |
|
[{disc_copies, [node()]}, |
55 |
|
{attributes, record_info(fields, muc_registered)}]), |
56 |
8 |
mnesia:add_table_index(muc_registered, nick), |
57 |
8 |
ok. |
58 |
|
|
59 |
|
-spec store_room(mongooseim:host_type(), jid:server(), mod_muc:room(), list()) |
60 |
|
-> ok | {error, term()}. |
61 |
|
store_room(HostType, MucHost, RoomName, Opts) -> |
62 |
69 |
F = fun() -> |
63 |
69 |
mnesia:write(#muc_room{name_host = {RoomName, MucHost}, |
64 |
|
opts = Opts}) |
65 |
|
end, |
66 |
69 |
Result = mnesia:transaction(F), |
67 |
69 |
case Result of |
68 |
|
{atomic, _} -> |
69 |
69 |
ok; |
70 |
|
_ -> |
71 |
:-( |
?LOG_ERROR(#{what => muc_store_room_failed, |
72 |
|
sub_host => MucHost, host_type => HostType, |
73 |
:-( |
room => RoomName, reason => Result}), |
74 |
:-( |
{error, Result} |
75 |
|
end. |
76 |
|
|
77 |
|
restore_room(HostType, MucHost, RoomName) -> |
78 |
2 |
try mnesia:dirty_read(muc_room, {RoomName, MucHost}) of |
79 |
|
[#muc_room{opts = Opts}] -> |
80 |
2 |
{ok, Opts}; |
81 |
|
[] -> |
82 |
:-( |
{error, room_not_found}; |
83 |
|
Other -> |
84 |
:-( |
{error, Other} |
85 |
|
catch Class:Reason:Stacktrace -> |
86 |
:-( |
?LOG_ERROR(#{what => muc_restore_room_failed, room => RoomName, |
87 |
|
sub_host => MucHost, host_type => HostType, |
88 |
:-( |
class => Class, reason => Reason, stacktrace => Stacktrace}), |
89 |
:-( |
{error, {Class, Reason}} |
90 |
|
end. |
91 |
|
|
92 |
|
-spec forget_room(mongooseim:host_type(), jid:server(), mod_muc:room()) -> |
93 |
|
ok | {error, term()}. |
94 |
|
forget_room(HostType, MucHost, RoomName) -> |
95 |
53 |
F = fun() -> |
96 |
53 |
mnesia:delete({muc_room, {RoomName, MucHost}}) |
97 |
|
end, |
98 |
53 |
Result = mnesia:transaction(F), |
99 |
53 |
case Result of |
100 |
|
{atomic, _} -> |
101 |
53 |
ok; |
102 |
|
_ -> |
103 |
:-( |
?LOG_ERROR(#{what => muc_forget_room_failed, |
104 |
|
sub_host => MucHost, host_type => HostType, |
105 |
:-( |
room => RoomName, reason => Result}), |
106 |
:-( |
{error, Result} |
107 |
|
end. |
108 |
|
|
109 |
|
get_rooms(HostType, MucHost) -> |
110 |
:-( |
Query = [{#muc_room{name_host = {'_', MucHost}, _ = '_'}, |
111 |
|
[], |
112 |
|
['$_']}], |
113 |
:-( |
try |
114 |
:-( |
{ok, mnesia:dirty_select(muc_room, Query)} |
115 |
|
catch Class:Reason:Stacktrace -> |
116 |
:-( |
?LOG_ERROR(#{what => muc_get_rooms_failed, |
117 |
|
sub_host => MucHost, host_type => HostType, |
118 |
:-( |
class => Class, reason => Reason, stacktrace => Stacktrace}), |
119 |
:-( |
{error, {Class, Reason}} |
120 |
|
end. |
121 |
|
|
122 |
|
-spec can_use_nick(mongooseim:host_type(), jid:server(), |
123 |
|
jid:jid(), mod_muc:nick()) -> boolean(). |
124 |
|
can_use_nick(_HostType, MucHost, JID, Nick) -> |
125 |
106 |
LUS = jid:to_lus(JID), |
126 |
106 |
can_use_nick_internal(MucHost, Nick, LUS). |
127 |
|
|
128 |
|
can_use_nick_internal(MucHost, Nick, LUS) -> |
129 |
106 |
Query = [{#muc_registered{us_host = '$1', nick = Nick, _ = '_'}, |
130 |
|
[{'==', {element, 2, '$1'}, MucHost}], |
131 |
|
['$_']}], |
132 |
106 |
try mnesia:dirty_select(muc_registered, Query) of |
133 |
|
[] -> |
134 |
106 |
true; |
135 |
|
[#muc_registered{us_host = {U, _Host}}] -> |
136 |
:-( |
U == LUS |
137 |
|
catch Class:Reason:Stacktrace -> |
138 |
:-( |
?LOG_ERROR(#{what => muc_can_use_nick_failed, sub_host => MucHost, |
139 |
:-( |
class => Class, reason => Reason, stacktrace => Stacktrace}), |
140 |
:-( |
false |
141 |
|
end. |
142 |
|
|
143 |
|
get_nick(_HostType, MucHost, From) -> |
144 |
:-( |
LUS = jid:to_lus(From), |
145 |
:-( |
try mnesia:dirty_read(muc_registered, {LUS, MucHost}) of |
146 |
|
[] -> |
147 |
:-( |
{error, not_registered}; |
148 |
|
[#muc_registered{nick = Nick}] -> |
149 |
:-( |
{ok, Nick} |
150 |
|
catch Class:Reason:Stacktrace -> |
151 |
:-( |
?LOG_ERROR(#{what => muc_get_nick_failed, |
152 |
|
sub_host => MucHost, from_jid => jid:to_binary(From), |
153 |
:-( |
class => Class, reason => Reason, stacktrace => Stacktrace}), |
154 |
:-( |
{error, {Class, Reason}} |
155 |
|
end. |
156 |
|
|
157 |
|
set_nick(HostType, MucHost, From, Nick) |
158 |
|
when is_binary(Nick), Nick =/= <<>> -> |
159 |
:-( |
LUS = jid:to_lus(From), |
160 |
:-( |
F = fun () -> |
161 |
:-( |
case can_use_nick_internal(MucHost, Nick, LUS) of |
162 |
|
true -> |
163 |
:-( |
Object = #muc_registered{us_host = {LUS, MucHost}, nick = Nick}, |
164 |
:-( |
mnesia:write(Object), |
165 |
:-( |
ok; |
166 |
|
false -> |
167 |
:-( |
{error, conflict} |
168 |
|
end |
169 |
|
end, |
170 |
:-( |
case mnesia:transaction(F) of |
171 |
|
{atomic, Result} -> |
172 |
:-( |
Result; |
173 |
|
ErrorResult -> |
174 |
:-( |
?LOG_ERROR(#{what => muc_set_nick_failed, reason => ErrorResult, |
175 |
|
server => HostType, sub_host => MucHost, |
176 |
:-( |
from_jid => jid:to_binary(From), nick => Nick}), |
177 |
:-( |
{error, ErrorResult} |
178 |
|
end. |
179 |
|
|
180 |
|
unset_nick(HostType, MucHost, From) -> |
181 |
:-( |
LUS = jid:to_lus(From), |
182 |
:-( |
F = fun () -> |
183 |
:-( |
mnesia:delete({muc_registered, {LUS, MucHost}}) |
184 |
|
end, |
185 |
:-( |
case mnesia:transaction(F) of |
186 |
|
{atomic, _} -> |
187 |
:-( |
ok; |
188 |
|
ErrorResult -> |
189 |
:-( |
?LOG_ERROR(#{what => muc_unset_nick_failed, reason => ErrorResult, |
190 |
|
server => HostType, sub_host => MucHost, |
191 |
:-( |
from_jid => jid:to_binary(From)}), |
192 |
:-( |
{error, ErrorResult} |
193 |
|
end. |