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 |
|
init(_HostType, _Opts) -> |
45 |
12 |
mnesia:create_table(muc_room, |
46 |
|
[{disc_copies, [node()]}, |
47 |
|
{attributes, record_info(fields, muc_room)}]), |
48 |
12 |
mnesia:create_table(muc_registered, |
49 |
|
[{disc_copies, [node()]}, |
50 |
|
{attributes, record_info(fields, muc_registered)}]), |
51 |
12 |
mnesia:add_table_copy(muc_room, node(), disc_copies), |
52 |
12 |
mnesia:add_table_copy(muc_registered, node(), disc_copies), |
53 |
12 |
mnesia:add_table_index(muc_registered, nick), |
54 |
12 |
ok. |
55 |
|
|
56 |
|
-spec store_room(mongooseim:host_type(), jid:server(), mod_muc:room(), list()) |
57 |
|
-> ok | {error, term()}. |
58 |
|
store_room(HostType, MucHost, RoomName, Opts) -> |
59 |
125 |
F = fun() -> |
60 |
125 |
mnesia:write(#muc_room{name_host = {RoomName, MucHost}, |
61 |
|
opts = Opts}) |
62 |
|
end, |
63 |
125 |
Result = mnesia:transaction(F), |
64 |
125 |
case Result of |
65 |
|
{atomic, _} -> |
66 |
125 |
ok; |
67 |
|
_ -> |
68 |
:-( |
?LOG_ERROR(#{what => muc_store_room_failed, |
69 |
|
sub_host => MucHost, host_type => HostType, |
70 |
:-( |
room => RoomName, reason => Result}), |
71 |
:-( |
{error, Result} |
72 |
|
end. |
73 |
|
|
74 |
|
restore_room(HostType, MucHost, RoomName) -> |
75 |
49 |
try mnesia:dirty_read(muc_room, {RoomName, MucHost}) of |
76 |
|
[#muc_room{opts = Opts}] -> |
77 |
7 |
{ok, Opts}; |
78 |
|
[] -> |
79 |
42 |
{error, room_not_found}; |
80 |
|
Other -> |
81 |
:-( |
{error, Other} |
82 |
|
catch Class:Reason:Stacktrace -> |
83 |
:-( |
?LOG_ERROR(#{what => muc_restore_room_failed, room => RoomName, |
84 |
|
sub_host => MucHost, host_type => HostType, |
85 |
:-( |
class => Class, reason => Reason, stacktrace => Stacktrace}), |
86 |
:-( |
{error, {Class, Reason}} |
87 |
|
end. |
88 |
|
|
89 |
|
-spec forget_room(mongooseim:host_type(), jid:server(), mod_muc:room()) -> |
90 |
|
ok | {error, term()}. |
91 |
|
forget_room(HostType, MucHost, RoomName) -> |
92 |
63 |
F = fun() -> |
93 |
63 |
mnesia:delete({muc_room, {RoomName, MucHost}}) |
94 |
|
end, |
95 |
63 |
Result = mnesia:transaction(F), |
96 |
63 |
case Result of |
97 |
|
{atomic, _} -> |
98 |
63 |
ok; |
99 |
|
_ -> |
100 |
:-( |
?LOG_ERROR(#{what => muc_forget_room_failed, |
101 |
|
sub_host => MucHost, host_type => HostType, |
102 |
:-( |
room => RoomName, reason => Result}), |
103 |
:-( |
{error, Result} |
104 |
|
end. |
105 |
|
|
106 |
|
get_rooms(HostType, MucHost) -> |
107 |
24 |
Query = [{#muc_room{name_host = {'_', MucHost}, _ = '_'}, |
108 |
|
[], |
109 |
|
['$_']}], |
110 |
24 |
try |
111 |
24 |
{ok, mnesia:dirty_select(muc_room, Query)} |
112 |
|
catch Class:Reason:Stacktrace -> |
113 |
:-( |
?LOG_ERROR(#{what => muc_get_rooms_failed, |
114 |
|
sub_host => MucHost, host_type => HostType, |
115 |
:-( |
class => Class, reason => Reason, stacktrace => Stacktrace}), |
116 |
:-( |
{error, {Class, Reason}} |
117 |
|
end. |
118 |
|
|
119 |
|
-spec can_use_nick(mongooseim:host_type(), jid:server(), |
120 |
|
ejabberd:jid(), mod_muc:nick()) -> boolean(). |
121 |
|
can_use_nick(_HostType, MucHost, JID, Nick) -> |
122 |
209 |
LUS = jid:to_lus(JID), |
123 |
209 |
can_use_nick_internal(MucHost, Nick, LUS). |
124 |
|
|
125 |
|
can_use_nick_internal(MucHost, Nick, LUS) -> |
126 |
223 |
Query = [{#muc_registered{us_host = '$1', nick = Nick, _ = '_'}, |
127 |
|
[{'==', {element, 2, '$1'}, MucHost}], |
128 |
|
['$_']}], |
129 |
223 |
try mnesia:dirty_select(muc_registered, Query) of |
130 |
|
[] -> |
131 |
221 |
true; |
132 |
|
[#muc_registered{us_host = {U, _Host}}] -> |
133 |
2 |
U == LUS |
134 |
|
catch Class:Reason:Stacktrace -> |
135 |
:-( |
?LOG_ERROR(#{what => muc_can_use_nick_failed, sub_host => MucHost, |
136 |
:-( |
class => Class, reason => Reason, stacktrace => Stacktrace}), |
137 |
:-( |
false |
138 |
|
end. |
139 |
|
|
140 |
|
get_nick(_HostType, MucHost, From) -> |
141 |
22 |
LUS = jid:to_lus(From), |
142 |
22 |
try mnesia:dirty_read(muc_registered, {LUS, MucHost}) of |
143 |
|
[] -> |
144 |
8 |
{error, not_registered}; |
145 |
|
[#muc_registered{nick = Nick}] -> |
146 |
14 |
{ok, Nick} |
147 |
|
catch Class:Reason:Stacktrace -> |
148 |
:-( |
?LOG_ERROR(#{what => muc_get_nick_failed, |
149 |
|
sub_host => MucHost, from_jid => jid:to_binary(From), |
150 |
:-( |
class => Class, reason => Reason, stacktrace => Stacktrace}), |
151 |
:-( |
{error, {Class, Reason}} |
152 |
|
end. |
153 |
|
|
154 |
|
set_nick(HostType, MucHost, From, Nick) |
155 |
|
when is_binary(Nick), Nick =/= <<>> -> |
156 |
14 |
LUS = jid:to_lus(From), |
157 |
14 |
F = fun () -> |
158 |
14 |
case can_use_nick_internal(MucHost, Nick, LUS) of |
159 |
|
true -> |
160 |
14 |
Object = #muc_registered{us_host = {LUS, MucHost}, nick = Nick}, |
161 |
14 |
mnesia:write(Object), |
162 |
14 |
ok; |
163 |
|
false -> |
164 |
:-( |
{error, conflict} |
165 |
|
end |
166 |
|
end, |
167 |
14 |
case mnesia:transaction(F) of |
168 |
|
{atomic, Result} -> |
169 |
14 |
Result; |
170 |
|
ErrorResult -> |
171 |
:-( |
?LOG_ERROR(#{what => muc_set_nick_failed, reason => ErrorResult, |
172 |
|
server => HostType, sub_host => MucHost, |
173 |
:-( |
from_jid => jid:to_binary(From), nick => Nick}), |
174 |
:-( |
{error, ErrorResult} |
175 |
|
end. |
176 |
|
|
177 |
|
unset_nick(HostType, MucHost, From) -> |
178 |
6 |
LUS = jid:to_lus(From), |
179 |
6 |
F = fun () -> |
180 |
6 |
mnesia:delete({muc_registered, {LUS, MucHost}}) |
181 |
|
end, |
182 |
6 |
case mnesia:transaction(F) of |
183 |
|
{atomic, _} -> |
184 |
6 |
ok; |
185 |
|
ErrorResult -> |
186 |
:-( |
?LOG_ERROR(#{what => muc_unset_nick_failed, reason => ErrorResult, |
187 |
|
server => HostType, sub_host => MucHost, |
188 |
:-( |
from_jid => jid:to_binary(From)}), |
189 |
:-( |
{error, ErrorResult} |
190 |
|
end. |