~ubuntu-branches/ubuntu/trusty/ejabberd/trusty-proposed

« back to all changes in this revision

Viewing changes to src/mod_pubsub/pubsub_subscription.erl

  • Committer: Bazaar Package Importer
  • Author(s): Gerfried Fuchs, Konstantin Khomoutov, Gerfried Fuchs
  • Date: 2009-12-04 18:22:49 UTC
  • mfrom: (1.1.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20091204182249-6jfmdz8878h7oaos
Tags: 2.1.0-1
[ Konstantin Khomoutov ]
* New upstream release (Closes: #519858).
  This also adds support for LDAPS upstream (Closes: #526145).
* Do not depend on cdbs anymore, port debian/rules to dh+quilt,
  remove build dependency on patchutils, use erlang-depends.
* Bump debhelper version to 7, standards base to 3.8.3
* Depend on erlang R13B.
* Recommend imagemagick (for captcha support).
* Remove deprecated patches (ssl.patch patch, dynamic_compile_loglevel.patch,
  ldaps.patch, update.patch, proxy.patch, caps.patch, convert.patch,
  s2s.patch).
* Replace mod_ctlextra with mod_admin_extra.
* Use upstream inetrc file.
* Bring debian/ejabberd.cfg and ejabberdctl in sync with upstream.
* Update ejabberdctl manual page.
* Provide NEWS file.
* Rework README.Debian:
  * Group all information into sections.
  * Describe issues with epam binary (Closes: #502791).
  * Discuss how to use DBMS backends (Closes: #540915, #507144).
  * Discuss upgrading from 2.0.x series.
* Implement PID file management (Closes: #519858).
* Make logrotate process all files matching "*.log".
* Improve init script:
  * Make init script LSB-compliant.
  * Implement "live" target which allows to run ejabberd in foreground.
* Make captcha.sh use bash explicitly.
* Rework node-generation for ejabberdctl to fix ejabberd's atom table
  overflows while preserving the possibility to run several versions
  of ejabberdctl concurrently as before.
* Add webadmin patch restoring compatibility with Erlang/OTP <= R12B-4.
* Integrate upstream patch for EJAB-1106.
* Add upstream patch for EJAB-1098.
* Add upstream patch for EJAB-1045.
* Add Konstantin Khomoutov to uploaders.
* Add Japanese debconf translation (thanks to Hideki Yamane)
  (Closes: #558071).

[ Gerfried Fuchs ]
* Build-Depend on po-debconf so po2debconf can be called.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
%%% ====================================================================
 
2
%%% ``The contents of this file are subject to the Erlang Public License,
 
3
%%% Version 1.1, (the "License"); you may not use this file except in
 
4
%%% compliance with the License. You should have received a copy of the
 
5
%%% Erlang Public License along with this software. If not, it can be
 
6
%%% retrieved via the world wide web at http://www.erlang.org/.
 
7
%%%
 
8
%%% Software distributed under the License is distributed on an "AS IS"
 
9
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 
10
%%% the License for the specific language governing rights and limitations
 
11
%%% under the License.
 
12
%%%
 
13
%%% The Initial Developer of the Original Code is ProcessOne.
 
14
%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne
 
15
%%% All Rights Reserved.''
 
16
%%% This software is copyright 2006-2009, ProcessOne.
 
17
%%%
 
18
%%% @author Brian Cully <bjc@kublai.com>
 
19
%%% @version {@vsn}, {@date} {@time}
 
20
%%% @end
 
21
%%% ====================================================================
 
22
 
 
23
-module(pubsub_subscription).
 
24
-author("bjc@kublai.com").
 
25
 
 
26
%% API
 
27
-export([init/0,
 
28
         subscribe_node/3,
 
29
         unsubscribe_node/3,
 
30
         get_subscription/3,
 
31
         set_subscription/4,
 
32
         get_options_xform/2,
 
33
         parse_options_xform/1]).
 
34
 
 
35
% Internal function also exported for use in transactional bloc from pubsub plugins
 
36
-export([add_subscription/3,
 
37
         delete_subscription/3,
 
38
         read_subscription/3,
 
39
         write_subscription/4]).
 
40
 
 
41
-include("pubsub.hrl").
 
42
-include("jlib.hrl").
 
43
 
 
44
-define(PUBSUB_DELIVER,     "pubsub#deliver").
 
45
-define(PUBSUB_DIGEST,       "pubsub#digest").
 
46
-define(PUBSUB_DIGEST_FREQUENCY,   "pubsub#digest_frequency").
 
47
-define(PUBSUB_EXPIRE,       "pubsub#expire").
 
48
-define(PUBSUB_INCLUDE_BODY,       "pubsub#include_body").
 
49
-define(PUBSUB_SHOW_VALUES,     "pubsub#show-values").
 
50
-define(PUBSUB_SUBSCRIPTION_TYPE,  "pubsub#subscription_type").
 
51
-define(PUBSUB_SUBSCRIPTION_DEPTH, "pubsub#subscription_depth").
 
52
 
 
53
-define(DELIVER_LABEL,
 
54
        "Whether an entity wants to receive or disable notifications").
 
55
-define(DIGEST_LABEL,
 
56
        "Whether an entity wants to receive digests (aggregations) of notifications or all notifications individually").
 
57
-define(DIGEST_FREQUENCY_LABEL,
 
58
       "The minimum number of milliseconds between sending any two notification digests").
 
59
-define(EXPIRE_LABEL,
 
60
        "The DateTime at which a leased subscription will end or has ended").
 
61
-define(INCLUDE_BODY_LABEL,
 
62
       "Whether an entity wants to receive an XMPP message body in addition to the payload format").
 
63
-define(SHOW_VALUES_LABEL,
 
64
        "The presence states for which an entity wants to receive notifications").
 
65
-define(SUBSCRIPTION_TYPE_LABEL,
 
66
        "Type of notification to receive").
 
67
-define(SUBSCRIPTION_DEPTH_LABEL,
 
68
        "Depth from subscription for which to receive notifications").
 
69
 
 
70
-define(SHOW_VALUE_AWAY_LABEL,   "XMPP Show Value of Away").
 
71
-define(SHOW_VALUE_CHAT_LABEL,   "XMPP Show Value of Chat").
 
72
-define(SHOW_VALUE_DND_LABEL,    "XMPP Show Value of DND (Do Not Disturb)").
 
73
-define(SHOW_VALUE_ONLINE_LABEL, "Mere Availability in XMPP (No Show Value)").
 
74
-define(SHOW_VALUE_XA_LABEL,     "XMPP Show Value of XA (Extended Away)").
 
75
 
 
76
-define(SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL,
 
77
        "Receive notification of new items only").
 
78
-define(SUBSCRIPTION_TYPE_VALUE_NODES_LABEL,
 
79
        "Receive notification of new nodes only").
 
80
 
 
81
-define(SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL,
 
82
        "Receive notification from direct child nodes only").
 
83
-define(SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL,
 
84
        "Receive notification from all descendent nodes").
 
85
 
 
86
%%====================================================================
 
87
%% API
 
88
%%====================================================================
 
89
init() ->
 
90
    ok = create_table().
 
91
 
 
92
subscribe_node(JID, NodeID, Options) ->
 
93
    case catch mnesia:sync_dirty(fun add_subscription/3,
 
94
                            [JID, NodeID, Options]) of
 
95
        {'EXIT', {aborted, Error}} -> Error;
 
96
        {error, Error} -> {error, Error};
 
97
        Result -> {result, Result}
 
98
    end.
 
99
 
 
100
unsubscribe_node(JID, NodeID, SubID) ->
 
101
    case catch mnesia:sync_dirty(fun delete_subscription/3,
 
102
                            [JID, NodeID, SubID]) of
 
103
        {'EXIT', {aborted, Error}} -> Error;
 
104
        {error, Error} -> {error, Error};
 
105
        Result -> {result, Result}
 
106
    end.
 
107
 
 
108
get_subscription(JID, NodeID, SubID) ->
 
109
    case catch mnesia:sync_dirty(fun read_subscription/3,
 
110
                            [JID, NodeID, SubID]) of
 
111
        {'EXIT', {aborted, Error}} -> Error;
 
112
        {error, Error} -> {error, Error};
 
113
        Result -> {result, Result}
 
114
    end.
 
115
 
 
116
set_subscription(JID, NodeID, SubID, Options) ->
 
117
    case catch mnesia:sync_dirty(fun write_subscription/4,
 
118
                            [JID, NodeID, SubID, Options]) of
 
119
        {'EXIT', {aborted, Error}} -> Error;
 
120
        {error, Error} -> {error, Error};
 
121
        Result -> {result, Result}
 
122
    end.
 
123
 
 
124
get_options_xform(Lang, Options) ->
 
125
    Keys = [deliver, show_values, subscription_type, subscription_depth],
 
126
    XFields = [get_option_xfield(Lang, Key, Options) || Key <- Keys],
 
127
 
 
128
    {result, {xmlelement, "x", [{"xmlns", ?NS_XDATA}],
 
129
              [{xmlelement, "field", [{"var", "FORM_TYPE"}, {"type", "hidden"}],
 
130
                [{xmlelement, "value", [],
 
131
                  [{xmlcdata, ?NS_PUBSUB_SUB_OPTIONS}]}]}] ++ XFields}}.
 
132
 
 
133
parse_options_xform(XFields) ->
 
134
    case xml:remove_cdata(XFields) of
 
135
        [] -> {result, []};
 
136
        [{xmlelement, "x", _Attrs, _Els} = XEl] ->
 
137
            case jlib:parse_xdata_submit(XEl) of
 
138
                XData when is_list(XData) ->
 
139
                    case set_xoption(XData, []) of
 
140
                        Opts when is_list(Opts) -> {result, Opts};
 
141
                        Other              -> Other
 
142
                    end;
 
143
                Other ->
 
144
                    Other
 
145
            end;
 
146
        Other ->
 
147
            Other
 
148
    end.
 
149
 
 
150
%%====================================================================
 
151
%% Internal functions
 
152
%%====================================================================
 
153
create_table() ->
 
154
    case mnesia:create_table(pubsub_subscription,
 
155
                             [{disc_copies, [node()]},
 
156
                              {attributes, record_info(fields, pubsub_subscription)},
 
157
                              {type, set}]) of
 
158
        {atomic, ok}               -> ok;
 
159
        {aborted, {already_exists, _}} -> ok;
 
160
        Other                     -> Other
 
161
    end.
 
162
 
 
163
add_subscription(_JID, _NodeID, Options) ->
 
164
    SubID = make_subid(),
 
165
    mnesia:write(#pubsub_subscription{subid = SubID, options = Options}),
 
166
    SubID.
 
167
 
 
168
delete_subscription(_JID, _NodeID, SubID) ->
 
169
    mnesia:delete({pubsub_subscription, SubID}).
 
170
 
 
171
read_subscription(_JID, _NodeID, SubID) ->
 
172
    case mnesia:read({pubsub_subscription, SubID}) of
 
173
    [Sub] -> Sub;
 
174
    _ -> {error, notfound}
 
175
    end.
 
176
 
 
177
write_subscription(JID, NodeID, SubID, Options) ->
 
178
    case read_subscription(JID, NodeID, SubID) of
 
179
    {error, notfound} -> {error, notfound};
 
180
    Sub -> mnesia:write(Sub#pubsub_subscription{options = Options})
 
181
    end.
 
182
 
 
183
make_subid() ->
 
184
    {T1, T2, T3} = now(),
 
185
    lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])).
 
186
 
 
187
%%
 
188
%% Subscription XForm processing.
 
189
%%
 
190
 
 
191
%% Return processed options, with types converted and so forth, using
 
192
%% Opts as defaults.
 
193
set_xoption([], Opts) ->
 
194
    Opts;
 
195
set_xoption([{Var, Value} | T], Opts) ->
 
196
    NewOpts = case var_xfield(Var) of
 
197
                  {error, _} ->
 
198
                      Opts;
 
199
                  Key ->
 
200
                      Val = val_xfield(Key, Value),
 
201
                      lists:keystore(Key, 1, Opts, {Key, Val})
 
202
              end,
 
203
    set_xoption(T, NewOpts).
 
204
 
 
205
%% Return the options list's key for an XForm var.
 
206
var_xfield(?PUBSUB_DELIVER)         -> deliver;
 
207
var_xfield(?PUBSUB_DIGEST)           -> digest;
 
208
var_xfield(?PUBSUB_DIGEST_FREQUENCY)   -> digest_frequency;
 
209
var_xfield(?PUBSUB_EXPIRE)           -> expire;
 
210
var_xfield(?PUBSUB_INCLUDE_BODY)       -> include_body;
 
211
var_xfield(?PUBSUB_SHOW_VALUES) -> show_values;
 
212
var_xfield(?PUBSUB_SUBSCRIPTION_TYPE)  -> subscription_type;
 
213
var_xfield(?PUBSUB_SUBSCRIPTION_DEPTH) -> subscription_depth;
 
214
var_xfield(_)                     -> {error, badarg}.
 
215
 
 
216
%% Convert Values for option list's Key.
 
217
val_xfield(deliver, [Val])             -> xopt_to_bool(Val);
 
218
val_xfield(digest, [Val])               -> xopt_to_bool(Val);
 
219
val_xfield(digest_frequency, [Val])      -> list_to_integer(Val);
 
220
val_xfield(expire, [Val])               -> jlib:datetime_string_to_timestamp(Val);
 
221
val_xfield(include_body, [Val])   -> xopt_to_bool(Val);
 
222
val_xfield(show_values, Vals)       -> Vals;
 
223
val_xfield(subscription_type, ["items"]) -> items;
 
224
val_xfield(subscription_type, ["nodes"]) -> nodes;
 
225
val_xfield(subscription_depth, ["all"])  -> all;
 
226
val_xfield(subscription_depth, [Depth])  ->
 
227
    case catch list_to_integer(Depth) of
 
228
        N when is_integer(N) -> N;
 
229
        _                   -> {error, ?ERR_NOT_ACCEPTABLE}
 
230
    end.
 
231
 
 
232
%% Convert XForm booleans to Erlang booleans.
 
233
xopt_to_bool("0")     -> false;
 
234
xopt_to_bool("1")     -> true;
 
235
xopt_to_bool("false") -> false;
 
236
xopt_to_bool("true")  -> true;
 
237
xopt_to_bool(_)       -> {error, ?ERR_NOT_ACCEPTABLE}.
 
238
 
 
239
%% Return a field for an XForm for Key, with data filled in, if
 
240
%% applicable, from Options.
 
241
get_option_xfield(Lang, Key, Options) ->
 
242
    Var = xfield_var(Key),
 
243
    Label = xfield_label(Key),
 
244
    {Type, OptEls} = type_and_options(xfield_type(Key), Lang),
 
245
    Vals = case lists:keysearch(Key, 1, Options) of
 
246
               {value, {_, Val}} ->
 
247
                   [tr_xfield_values(Vals) || Vals <- xfield_val(Key, Val)];
 
248
               false ->
 
249
                   []
 
250
           end,
 
251
    {xmlelement, "field",
 
252
     [{"var", Var}, {"type", Type},
 
253
      {"label", translate:translate(Lang, Label)}],
 
254
     OptEls ++ Vals}.
 
255
 
 
256
type_and_options({Type, Options}, Lang) ->
 
257
    {Type, [tr_xfield_options(O, Lang) || O <- Options]};
 
258
type_and_options(Type, _Lang) ->
 
259
    {Type, []}.
 
260
 
 
261
tr_xfield_options({Value, Label}, Lang) ->
 
262
    {xmlelement, "option",
 
263
     [{"label", translate:translate(Lang, Label)}], [{xmlelement, "value", [],
 
264
       [{xmlcdata, Value}]}]}.
 
265
 
 
266
tr_xfield_values(Value) ->
 
267
    {xmlelement, "value", [], [{xmlcdata, Value}]}.
 
268
 
 
269
%% Return the XForm variable name for a subscription option key.
 
270
xfield_var(deliver)         -> ?PUBSUB_DELIVER;
 
271
xfield_var(digest)           -> ?PUBSUB_DIGEST;
 
272
xfield_var(digest_frequency)   -> ?PUBSUB_DIGEST_FREQUENCY;
 
273
xfield_var(expire)           -> ?PUBSUB_EXPIRE;
 
274
xfield_var(include_body)       -> ?PUBSUB_INCLUDE_BODY;
 
275
xfield_var(show_values) -> ?PUBSUB_SHOW_VALUES;
 
276
xfield_var(subscription_type)  -> ?PUBSUB_SUBSCRIPTION_TYPE;
 
277
xfield_var(subscription_depth) -> ?PUBSUB_SUBSCRIPTION_DEPTH.
 
278
 
 
279
%% Return the XForm variable type for a subscription option key.
 
280
xfield_type(deliver)        -> "boolean";
 
281
xfield_type(digest)          -> "boolean";
 
282
xfield_type(digest_frequency)   -> "text-single";
 
283
xfield_type(expire)          -> "text-single";
 
284
xfield_type(include_body)       -> "boolean";
 
285
xfield_type(show_values)        ->
 
286
    {"list-multi", [{"away",   ?SHOW_VALUE_AWAY_LABEL},
 
287
                    {"chat",   ?SHOW_VALUE_CHAT_LABEL},
 
288
                    {"dnd",    ?SHOW_VALUE_DND_LABEL},
 
289
                    {"online", ?SHOW_VALUE_ONLINE_LABEL},
 
290
                    {"xa",     ?SHOW_VALUE_XA_LABEL}]};
 
291
xfield_type(subscription_type)  ->
 
292
    {"list-single", [{"items", ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL},
 
293
                     {"nodes", ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]};
 
294
xfield_type(subscription_depth) ->
 
295
    {"list-single", [{"1",   ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL},
 
296
                     {"all", ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}.
 
297
 
 
298
%% Return the XForm variable label for a subscription option key.
 
299
xfield_label(deliver) -> ?DELIVER_LABEL;
 
300
xfield_label(digest) -> ?DIGEST_LABEL;
 
301
xfield_label(digest_frequency) -> ?DIGEST_FREQUENCY_LABEL;
 
302
xfield_label(expire) -> ?EXPIRE_LABEL;
 
303
xfield_label(include_body) -> ?INCLUDE_BODY_LABEL;
 
304
xfield_label(show_values) -> ?SHOW_VALUES_LABEL;
 
305
xfield_label(subscription_type) -> ?SUBSCRIPTION_TYPE_LABEL;
 
306
xfield_label(subscription_depth) -> ?SUBSCRIPTION_DEPTH_LABEL.
 
307
 
 
308
%% Return the XForm value for a subscription option key.
 
309
xfield_val(deliver,         Val)   -> [bool_to_xopt(Val)];
 
310
xfield_val(digest,           Val)   -> [bool_to_xopt(Val)];
 
311
xfield_val(digest_frequency,   Val)   -> [integer_to_list(Val)];
 
312
xfield_val(expire,           Val)   -> [jlib:now_to_utc_string(Val)];
 
313
xfield_val(include_body,       Val)   -> [bool_to_xopt(Val)];
 
314
xfield_val(show_values, Val)   -> Val;
 
315
xfield_val(subscription_type,  items) -> ["items"];
 
316
xfield_val(subscription_type,  nodes) -> ["nodes"];
 
317
xfield_val(subscription_depth, all)   -> ["all"];
 
318
xfield_val(subscription_depth, N)     -> [integer_to_list(N)].
 
319
 
 
320
%% Convert erlang booleans to XForms.
 
321
bool_to_xopt(false) -> "false";
 
322
bool_to_xopt(true)  -> "true".