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

« back to all changes in this revision

Viewing changes to src/mod_pubsub/node_hometree.erl

  • Committer: Bazaar Package Importer
  • Author(s): Konstantin Khomoutov
  • Date: 2010-12-14 17:45:08 UTC
  • mfrom: (1.1.17 upstream)
  • Revision ID: james.westby@ubuntu.com-20101214174508-6vgu3uw3ki6x8vj2
Tags: 2.1.6-1
* New upstream release.
* Remove obsolete patches.
* Update mod_admin_extra to revision 1106.
* Conflict with ejabberd-mod-shared-roster-ldap which is now included.

Show diffs side-by-side

added added

removed removed

Lines of Context:
84
84
%% API definition
85
85
%% ================
86
86
 
87
 
%% @spec (Host, ServerHost, Opts) -> any()
88
 
%%       Host = mod_pubsub:host()
89
 
%%       ServerHost = mod_pubsub:host()
90
 
%%       Opts = list()
 
87
%% @spec (Host, ServerHost, Options) -> ok
 
88
%%       Host       = string()
 
89
%%       ServerHost = string()
 
90
%%       Options    = [{atom(), term()}]
91
91
%% @doc <p>Called during pubsub modules initialisation. Any pubsub plugin must
92
92
%% implement this function. It can return anything.</p>
93
93
%% <p>This function is mainly used to trigger the setup task necessary for the
94
94
%% plugin. It can be used for example by the developer to create the specific
95
95
%% module database schema if it does not exists yet.</p>
96
 
init(_Host, _ServerHost, _Opts) ->
 
96
init(_Host, _ServerHost, _Options) ->
97
97
    pubsub_subscription:init(),
98
98
    mnesia:create_table(pubsub_state,
99
99
                        [{disc_copies, [node()]},
109
109
    end,
110
110
    ok.
111
111
 
112
 
%% @spec (Host, ServerHost) -> any()
113
 
%%       Host = mod_pubsub:host()
114
 
%%       ServerHost = host()
 
112
%% @spec (Host, ServerHost) -> ok
 
113
%%       Host       = string()
 
114
%%       ServerHost = string()
115
115
%% @doc <p>Called during pubsub modules termination. Any pubsub plugin must
116
116
%% implement this function. It can return anything.</p>
117
117
terminate(_Host, _ServerHost) ->
118
118
    ok.
119
119
 
120
 
%% @spec () -> [Option]
121
 
%%       Option = mod_pubsub:nodeOption()
 
120
%% @spec () -> Options
 
121
%%       Options = [mod_pubsub:nodeOption()]
122
122
%% @doc Returns the default pubsub node options.
123
123
%% <p>Example of function return value:</p>
124
124
%%      ```
152
152
     {deliver_notifications, true},
153
153
     {presence_based_delivery, false}].
154
154
 
155
 
%% @spec () -> []
 
155
%% @spec () -> Features
 
156
%%       Features = [string()]
156
157
%% @doc Returns the node features
157
158
features() ->
158
159
    ["create-nodes",
178
179
     "subscription-options"
179
180
    ].
180
181
 
181
 
%% @spec (Host, ServerHost, Node, ParentNode, Owner, Access) -> bool()
182
 
%%       Host = mod_pubsub:host()
183
 
%%       ServerHost = mod_pubsub:host()
184
 
%%       Node = mod_pubsub:pubsubNode()
185
 
%%       ParentNode = mod_pubsub:pubsubNode()
186
 
%%       Owner = mod_pubsub:jid()
187
 
%%       Access = all | atom()
 
182
%% @spec (Host, ServerHost, NodeId, ParentNodeId, Owner, Access) -> {result, Allowed}
 
183
%%       Host         = mod_pubsub:hostPubsub()
 
184
%%       ServerHost   = string()
 
185
%%       NodeId       = mod_pubsub:nodeId()
 
186
%%       ParentNodeId = mod_pubsub:nodeId()
 
187
%%       Owner        = mod_pubsub:jid()
 
188
%%       Access       = all | atom()
 
189
%%   Allowed      = boolean()
188
190
%% @doc Checks if the current user has the permission to create the requested node
189
191
%% <p>In {@link node_default}, the permission is decided by the place in the
190
192
%% hierarchy where the user is creating the node. The access parameter is also
195
197
%% <p>PubSub plugins can redefine the PubSub node creation rights as they
196
198
%% which. They can simply delegate this check to the {@link node_default}
197
199
%% module by implementing this function like this:
198
 
%% ```check_create_user_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
199
 
%%         node_default:check_create_user_permission(Host, ServerHost, Node, ParentNode, Owner, Access).'''</p>
200
 
create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) ->
 
200
%% ```check_create_user_permission(Host, ServerHost, NodeId, ParentNodeId, Owner, Access) ->
 
201
%%         node_default:check_create_user_permission(Host, ServerHost, NodeId, ParentNodeId, Owner, Access).'''</p>
 
202
create_node_permission(Host, ServerHost, NodeId, _ParentNodeId, Owner, Access) ->
201
203
    LOwner = jlib:jid_tolower(Owner),
202
204
    {User, Server, _Resource} = LOwner,
203
205
    Allowed = case LOwner of
206
208
        _ ->
207
209
            case acl:match_rule(ServerHost, Access, LOwner) of
208
210
                allow ->
209
 
                    case node_to_path(Node) of
 
211
                    case node_to_path(NodeId) of
210
212
                        ["home", Server, User | _] -> true;
211
213
                        _ -> false
212
214
                    end;
216
218
    end,
217
219
    {result, Allowed}.
218
220
 
219
 
%% @spec (NodeId, Owner) ->
220
 
%%                {result, Result} | exit
221
 
%%       NodeId = mod_pubsub:pubsubNodeId()
222
 
%%       Owner = mod_pubsub:jid()
 
221
%% @spec (NodeIdx, Owner) -> {result, {default, broadcast}} 
 
222
%%       NodeIdx = mod_pubsub:nodeIdx()
 
223
%%       Owner   = mod_pubsub:jid()
223
224
%% @doc <p></p>
224
 
create_node(NodeId, Owner) ->
 
225
create_node(NodeIdx, Owner) ->
225
226
    OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
226
 
    set_state(#pubsub_state{stateid = {OwnerKey, NodeId}, affiliation = owner}),
 
227
    set_state(#pubsub_state{stateid = {OwnerKey, NodeIdx}, affiliation = owner}),
227
228
    {result, {default, broadcast}}.
228
229
 
229
 
%% @spec (Removed) -> ok
230
 
%%       Removed = [mod_pubsub:pubsubNode()]
 
230
%% @spec (Nodes) -> {result, {default, broadcast, Reply}}
 
231
%%       Nodes = [mod_pubsub:pubsubNode()]
 
232
%%       Reply = [{mod_pubsub:pubsubNode(),
 
233
%%            [{mod_pubsub:ljid(), [{mod_pubsub:subscription(), mod_pubsub:subId()}]}]}]
231
234
%% @doc <p>purge items of deleted nodes after effective deletion.</p>
232
 
delete_node(Removed) ->
 
235
delete_node(Nodes) ->
233
236
    Tr = fun(#pubsub_state{stateid = {J, _}, subscriptions = Ss}) ->
234
237
                 lists:map(fun(S) ->
235
238
                                   {J, S}
244
247
                    del_state(NodeId, LJID)
245
248
            end, States),
246
249
            {PubsubNode, lists:flatmap(Tr, States)}
247
 
        end, Removed),
 
250
        end, Nodes),
248
251
    {result, {default, broadcast, Reply}}.
249
252
 
250
 
%% @spec (NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options) ->
251
 
%%               {error, Reason} | {result, Result}
 
253
%% @spec (NodeIdx, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options) -> {error, Reason} | {result, Result}
 
254
%%       NodeIdx              = mod_pubsub:nodeIdx()
 
255
%%       Sender               = mod_pubsub:jid()
 
256
%%       Subscriber           = mod_pubsub:jid()
 
257
%%       AccessModel          = mod_pubsub:accessModel()
 
258
%%       SendLast             = atom()
 
259
%%       PresenceSubscription = boolean()
 
260
%%       RosterGroup          = boolean()
 
261
%%       Options              = [mod_pubsub:nodeOption()]
 
262
%%       Reason               = mod_pubsub:stanzaError()
 
263
%%       Result               = {result, {default, subscribed, mod_pubsub:subId()}}
 
264
%%                        | {result, {default, subscribed, mod_pubsub:subId(), send_last}}
 
265
%%                        | {result, {default, pending,    mod_pubsub:subId()}}
 
266
%%
252
267
%% @doc <p>Accepts or rejects subcription requests on a PubSub node.</p>
253
268
%% <p>The mechanism works as follow:
254
269
%% <ul>
280
295
%%   to completly disable persistance.</li></ul>
281
296
%% </p>
282
297
%% <p>In the default plugin module, the record is unchanged.</p>
283
 
subscribe_node(NodeId, Sender, Subscriber, AccessModel,
 
298
subscribe_node(NodeIdx, Sender, Subscriber, AccessModel,
284
299
               SendLast, PresenceSubscription, RosterGroup, Options) ->
285
300
    SubKey = jlib:jid_tolower(Subscriber),
286
301
    GenKey = jlib:jid_remove_resource(SubKey),
287
302
    Authorized = (jlib:jid_tolower(jlib:jid_remove_resource(Sender)) == GenKey),
288
 
    GenState = get_state(NodeId, GenKey),
 
303
    GenState = get_state(NodeIdx, GenKey),
289
304
    SubState = case SubKey of
290
305
        GenKey -> GenState;
291
 
        _ -> get_state(NodeId, SubKey)
 
306
        _ -> get_state(NodeIdx, SubKey)
292
307
        end,
293
308
    Affiliation = GenState#pubsub_state.affiliation,
294
309
    Subscriptions = SubState#pubsub_state.subscriptions,
322
337
        %%      % Requesting entity is anonymous
323
338
        %%      {error, ?ERR_FORBIDDEN};
324
339
        true ->
325
 
            case pubsub_subscription:add_subscription(Subscriber, NodeId, Options) of
 
340
            case pubsub_subscription:add_subscription(Subscriber, NodeIdx, Options) of
326
341
                SubId when is_list(SubId) ->
327
342
                    NewSub = case AccessModel of
328
343
                                 authorize -> pending;
342
357
            end
343
358
    end.
344
359
 
345
 
%% @spec (NodeId, Sender, Subscriber, SubId) ->
346
 
%%                      {error, Reason} | {result, []}
347
 
%%       NodeId = mod_pubsub:pubsubNodeId()
348
 
%%       Sender = mod_pubsub:jid()
 
360
%% @spec (NodeIdx, Sender, Subscriber, SubId) ->        {error, Reason} | {result, default}
 
361
%%       NodeIdx    = mod_pubsub:nodeIdx()
 
362
%%       Sender     = mod_pubsub:jid()
349
363
%%       Subscriber = mod_pubsub:jid()
350
 
%%       SubId = mod_pubsub:subid()
351
 
%%       Reason = mod_pubsub:stanzaError()
 
364
%%       SubId      = mod_pubsub:subId()
 
365
%%       Reason     = mod_pubsub:stanzaError()
352
366
%% @doc <p>Unsubscribe the <tt>Subscriber</tt> from the <tt>Node</tt>.</p>
353
 
unsubscribe_node(NodeId, Sender, Subscriber, SubId) ->
 
367
unsubscribe_node(NodeIdx, Sender, Subscriber, SubId) ->
354
368
    SubKey = jlib:jid_tolower(Subscriber),
355
369
    GenKey = jlib:jid_remove_resource(SubKey),
356
370
    Authorized = (jlib:jid_tolower(jlib:jid_remove_resource(Sender)) == GenKey),
357
 
    GenState = get_state(NodeId, GenKey),
 
371
    GenState = get_state(NodeIdx, GenKey),
358
372
    SubState = case SubKey of
359
373
        GenKey -> GenState;
360
 
        _ -> get_state(NodeId, SubKey)
 
374
        _ -> get_state(NodeIdx, SubKey)
361
375
        end,
362
376
    Subscriptions = lists:filter(fun({_Sub, _SubId}) -> true;
363
377
                                     (_SubId)    -> false
390
404
                                end, SubState#pubsub_state.subscriptions),
391
405
            case Sub of
392
406
                {value, S} ->
393
 
                    delete_subscriptions(SubKey, NodeId, [S], SubState),
 
407
                    delete_subscriptions(SubKey, NodeIdx, [S], SubState),
394
408
                    {result, default};
395
409
                false ->
396
410
                    {error, ?ERR_EXTENDED(?ERR_UNEXPECTED_REQUEST_CANCEL, "not-subscribed")}
397
411
            end;
398
412
        %% Asking to remove all subscriptions to the given node
399
413
        SubId == all ->
400
 
            delete_subscriptions(SubKey, NodeId, Subscriptions, SubState),
 
414
            delete_subscriptions(SubKey, NodeIdx, Subscriptions, SubState),
401
415
            {result, default};
402
416
        %% No subid supplied, but there's only one matching subscription
403
417
        length(Subscriptions) == 1 ->
404
 
            delete_subscriptions(SubKey, NodeId, Subscriptions, SubState),
 
418
            delete_subscriptions(SubKey, NodeIdx, Subscriptions, SubState),
405
419
            {result, default};
406
420
        %% No subid and more than one possible subscription match.
407
421
        true ->
408
422
            {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")}
409
423
    end.
410
424
 
411
 
delete_subscriptions(SubKey, NodeId, Subscriptions, SubState) ->
 
425
delete_subscriptions(SubKey, NodeIdx, Subscriptions, SubState) ->
412
426
    NewSubs = lists:foldl(fun({Subscription, SubId}, Acc) ->
413
 
            pubsub_subscription:delete_subscription(SubKey, NodeId, SubId),
 
427
            pubsub_subscription:delete_subscription(SubKey, NodeIdx, SubId),
414
428
            Acc -- [{Subscription, SubId}]
415
429
        end, SubState#pubsub_state.subscriptions, Subscriptions),
416
430
    case {SubState#pubsub_state.affiliation, NewSubs} of
417
431
        {none, []} ->
418
432
            % Just a regular subscriber, and this is final item, so
419
433
            % delete the state.
420
 
            del_state(NodeId, SubKey);
 
434
            del_state(NodeIdx, SubKey);
421
435
        _ ->
422
436
            set_state(SubState#pubsub_state{subscriptions = NewSubs})
423
437
    end.
424
438
 
425
 
%% @spec (NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
426
 
%%               {true, PubsubItem} | {result, Reply}
427
 
%%       NodeId = mod_pubsub:pubsubNodeId()
428
 
%%       Publisher = mod_pubsub:jid()
 
439
%% @spec (NodeIdx, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
 
440
%%               {result, {default, broadcast, ItemIds}} | {error, Reason}
 
441
%%       NodeIdx      = mod_pubsub:nodeIdx()
 
442
%%       Publisher    = mod_pubsub:jid()
429
443
%%       PublishModel = atom()
430
 
%%       MaxItems = integer()
431
 
%%       ItemId = string()
432
 
%%       Payload = term()
 
444
%%       MaxItems     = integer()
 
445
%%       ItemId       = mod_pubsub:itemId()
 
446
%%       Payload      = mod_pubsub:payload()
 
447
%%       ItemIds      = [mod_pubsub:itemId()] | []
 
448
%%       Reason       = mod_pubsub:stanzaError()
433
449
%% @doc <p>Publishes the item passed as parameter.</p>
434
450
%% <p>The mechanism works as follow:
435
451
%% <ul>
460
476
%%   to completly disable persistance.</li></ul>
461
477
%% </p>
462
478
%% <p>In the default plugin module, the record is unchanged.</p>
463
 
publish_item(NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
 
479
publish_item(NodeIdx, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
464
480
    SubKey = jlib:jid_tolower(Publisher),
465
481
    GenKey = jlib:jid_remove_resource(SubKey),
466
 
    GenState = get_state(NodeId, GenKey),
 
482
    GenState = get_state(NodeIdx, GenKey),
467
483
    SubState = case SubKey of
468
484
        GenKey -> GenState;
469
 
        _ -> get_state(NodeId, SubKey)
 
485
        _ -> get_state(NodeIdx, SubKey)
470
486
        end,
471
487
    Affiliation = GenState#pubsub_state.affiliation,
472
488
    Subscribed = case PublishModel of
485
501
            if MaxItems > 0 ->
486
502
                Now = now(),
487
503
                PubId = {Now, SubKey},
488
 
                Item = case get_item(NodeId, ItemId) of
 
504
                Item = case get_item(NodeIdx, ItemId) of
489
505
                       {result, OldItem} ->
490
506
                           OldItem#pubsub_item{modification = PubId,
491
507
                                               payload = Payload};
492
508
                       _ ->
493
 
                           #pubsub_item{itemid = {ItemId, NodeId},
 
509
                           #pubsub_item{itemid = {ItemId, NodeIdx},
494
510
                                        creation = {Now, GenKey},
495
511
                                        modification = PubId,
496
512
                                        payload = Payload}
497
513
                   end,
498
514
                Items = [ItemId | GenState#pubsub_state.items--[ItemId]],
499
 
                {result, {NI, OI}} = remove_extra_items(NodeId, MaxItems, Items),
 
515
                {result, {NI, OI}} = remove_extra_items(NodeIdx, MaxItems, Items),
500
516
                set_item(Item),
501
517
                set_state(GenState#pubsub_state{items = NI}),
502
518
                {result, {default, broadcast, OI}};
505
521
            end
506
522
    end.
507
523
 
508
 
%% @spec (NodeId, MaxItems, ItemIds) -> {NewItemIds,OldItemIds}
509
 
%%       NodeId = mod_pubsub:pubsubNodeId()
510
 
%%       MaxItems = integer() | unlimited
511
 
%%       ItemIds = [ItemId::string()]
512
 
%%       NewItemIds = [ItemId::string()]
 
524
%% @spec (NodeIdx, MaxItems, ItemIds) -> {result, {NewItemIds,OldItemIds}}
 
525
%%       NodeIdx    = mod_pubsub:nodeIdx()
 
526
%%       MaxItems   = integer() | unlimited
 
527
%%       ItemIds    = [mod_pubsub:itemId()]
 
528
%%       NewItemIds = [mod_pubsub:itemId()]
 
529
%%       OldItemIds = [mod_pubsub:itemId()] | []
513
530
%% @doc <p>This function is used to remove extra items, most notably when the
514
531
%% maximum number of items has been reached.</p>
515
532
%% <p>This function is used internally by the core PubSub module, as no
518
535
%% rules can be used.</p>
519
536
%% <p>If another PubSub plugin wants to delegate the item removal (and if the
520
537
%% plugin is using the default pubsub storage), it can implements this function like this:
521
 
%% ```remove_extra_items(NodeId, MaxItems, ItemIds) ->
522
 
%%         node_default:remove_extra_items(NodeId, MaxItems, ItemIds).'''</p>
523
 
remove_extra_items(_NodeId, unlimited, ItemIds) ->
 
538
%% ```remove_extra_items(NodeIdx, MaxItems, ItemIds) ->
 
539
%%         node_default:remove_extra_items(NodeIdx, MaxItems, ItemIds).'''</p>
 
540
remove_extra_items(_NodeIdx, unlimited, ItemIds) ->
524
541
    {result, {ItemIds, []}};
525
 
remove_extra_items(NodeId, MaxItems, ItemIds) ->
 
542
remove_extra_items(NodeIdx, MaxItems, ItemIds) ->
526
543
    NewItems = lists:sublist(ItemIds, MaxItems),
527
544
    OldItems = lists:nthtail(length(NewItems), ItemIds),
528
545
    %% Remove extra items:
529
 
    del_items(NodeId, OldItems),
 
546
    del_items(NodeIdx, OldItems),
530
547
    %% Return the new items list:
531
548
    {result, {NewItems, OldItems}}.
532
549
 
533
 
%% @spec (NodeId, Publisher, PublishModel, ItemId) ->
534
 
%%                {error, Reason::stanzaError()} |
535
 
%%                {result, []}
536
 
%%       NodeId = mod_pubsub:pubsubNodeId()
537
 
%%       Publisher = mod_pubsub:jid()
 
550
%% @spec (NodeIdx, Publisher, PublishModel, ItemId) ->
 
551
%%     {result, {default, broadcast}} | {error, Reason}
 
552
%%       NodeIdx      = mod_pubsub:nodeIdx()
 
553
%%       Publisher    = mod_pubsub:jid()
538
554
%%       PublishModel = atom()
539
 
%%       ItemId = string()
 
555
%%       ItemId       = mod_pubsub:itemId()
 
556
%%   Reason       = mod_pubsub:stanzaError()
540
557
%% @doc <p>Triggers item deletion.</p>
541
558
%% <p>Default plugin: The user performing the deletion must be the node owner
542
559
%% or a publisher, or PublishModel being open.</p>
543
 
delete_item(NodeId, Publisher, PublishModel, ItemId) ->
 
560
delete_item(NodeIdx, Publisher, PublishModel, ItemId) ->
544
561
    SubKey = jlib:jid_tolower(Publisher),
545
562
    GenKey = jlib:jid_remove_resource(SubKey),
546
 
    GenState = get_state(NodeId, GenKey),
 
563
    GenState = get_state(NodeIdx, GenKey),
547
564
    #pubsub_state{affiliation = Affiliation, items = Items} = GenState,
548
565
    Allowed = (Affiliation == publisher) orelse (Affiliation == owner)
549
566
        orelse (PublishModel == open)
550
 
        orelse case get_item(NodeId, ItemId) of
 
567
        orelse case get_item(NodeIdx, ItemId) of
551
568
                   {result, #pubsub_item{creation = {_, GenKey}}} -> true;
552
569
                   _ -> false
553
570
               end,
558
575
        true ->
559
576
            case lists:member(ItemId, Items) of
560
577
                true ->
561
 
                    del_item(NodeId, ItemId),
 
578
                    del_item(NodeIdx, ItemId),
562
579
                    set_state(GenState#pubsub_state{items = lists:delete(ItemId, Items)}),
563
580
                    {result, {default, broadcast}};
564
581
                false ->
565
582
                    case Affiliation of
566
583
                        owner ->
567
584
                            %% Owner can delete other publishers items as well
568
 
                            {result, States} = get_states(NodeId),
 
585
                            {result, States} = get_states(NodeIdx),
569
586
                            lists:foldl(
570
587
                                fun(#pubsub_state{items = PI, affiliation = publisher} = S, Res) ->
571
588
                                    case lists:member(ItemId, PI) of
572
589
                                        true ->
573
 
                                            del_item(NodeId, ItemId),
 
590
                                            del_item(NodeIdx, ItemId),
574
591
                                            set_state(S#pubsub_state{items = lists:delete(ItemId, PI)}),
575
592
                                            {result, {default, broadcast}};
576
593
                                        false ->
586
603
            end
587
604
    end.
588
605
 
589
 
%% @spec (NodeId, Owner) ->
590
 
%%                {error, Reason::stanzaError()} |
591
 
%%                {result, {default, broadcast}}
592
 
%%       NodeId = mod_pubsub:pubsubNodeId()
593
 
%%       Owner = mod_pubsub:jid()
594
 
purge_node(NodeId, Owner) ->
 
606
%% @spec (NodeIdx, Owner) -> {error, Reason} | {result, {default, broadcast}}
 
607
%%       NodeIdx = mod_pubsub:nodeIdx()
 
608
%%       Owner   = mod_pubsub:jid()
 
609
%%   Reason  = mod_pubsub:stanzaError()
 
610
purge_node(NodeIdx, Owner) ->
595
611
    SubKey = jlib:jid_tolower(Owner),
596
612
    GenKey = jlib:jid_remove_resource(SubKey),
597
 
    GenState = get_state(NodeId, GenKey),
 
613
    GenState = get_state(NodeIdx, GenKey),
598
614
    case GenState of
599
615
        #pubsub_state{affiliation = owner} ->
600
 
            {result, States} = get_states(NodeId),
 
616
            {result, States} = get_states(NodeIdx),
601
617
            lists:foreach(
602
618
                fun(#pubsub_state{items = []}) ->
603
619
                    ok;
604
620
                   (#pubsub_state{items = Items} = S) ->
605
 
                    del_items(NodeId, Items),
 
621
                    del_items(NodeIdx, Items),
606
622
                    set_state(S#pubsub_state{items = []})
607
623
            end, States),
608
624
            {result, {default, broadcast}};
611
627
            {error, ?ERR_FORBIDDEN}
612
628
    end.
613
629
 
614
 
%% @spec (Host, JID) -> [{Node,Affiliation}]
615
 
%%       Host = host()
616
 
%%       JID = mod_pubsub:jid()
 
630
%% @spec (Host, Owner) -> {result, Reply}
 
631
%%       Host  = mod_pubsub:hostPubsub()
 
632
%%       Owner = mod_pubsub:jid()
 
633
%%       Reply = [] | [{mod_pubsub:pubsubNode(), mod_pubsub:affiliation()}]
617
634
%% @doc <p>Return the current affiliations for the given user</p>
618
635
%% <p>The default module reads affiliations in the main Mnesia
619
636
%% <tt>pubsub_state</tt> table. If a plugin stores its data in the same
661
678
            set_state(GenState#pubsub_state{affiliation = Affiliation})
662
679
    end.
663
680
 
664
 
%% @spec (Host, Owner) -> [{Node,Subscription}]
665
 
%%       Host = host()
666
 
%%       Owner = mod_pubsub:jid()
 
681
%% @spec (Host, Owner) ->
 
682
%%      {'result', []
 
683
%%               | [{Node, Subscription, SubId, Entity}]
 
684
%%               | [{Node, Subscription, Entity}]}
 
685
%%       Host         = mod_pubsub:hostPubsub()
 
686
%%       Owner        = mod_pubsub:jid()
 
687
%%       Node         = mod_pubsub:pubsubNode()
 
688
%%       Subscription = mod_pubsub:subscription()
 
689
%%       SubId        = mod_pubsub:subId()
 
690
%%       Entity       = mod_pubsub:ljid()
667
691
%% @doc <p>Return the current subscriptions for the given user</p>
668
692
%% <p>The default module reads subscriptions in the main Mnesia
669
693
%% <tt>pubsub_state</tt> table. If a plugin stores its data in the same
774
798
            set_state(SubState#pubsub_state{subscriptions = NewSubs})
775
799
    end.
776
800
 
777
 
%% @spec (Host, Owner) -> {result, [Node]} | {error, Reason}
778
 
%%       Host = host()
779
 
%%       Owner = jid()
780
 
%%       Node = pubsubNode()
 
801
%% TODO : doc
 
802
%% @spec (Host, Owner) -> {result, Reply} | {error, Reason} 
 
803
%%       Host  = mod_pubsub:hostPubsub()
 
804
%%   Owner = mod_pubsub:jid()
 
805
%%   Reply = [] | [mod_pubsub:nodeId()]
781
806
%% @doc <p>Returns a list of Owner's nodes on Host with pending
782
807
%% subscriptions.</p>
783
808
get_pending_nodes(Host, Owner) ->
821
846
            false
822
847
    end.
823
848
 
824
 
%% @spec (NodeId) -> [States] | []
825
 
%%       NodeId = mod_pubsub:pubsubNodeId()
 
849
%% @spec (NodeIdx) -> {result, States}
 
850
%%       NodeIdx = mod_pubsub:nodeIdx()
 
851
%%       States  = [] | [mod_pubsub:pubsubState()]
826
852
%% @doc Returns the list of stored states for a given node.
827
853
%% <p>For the default PubSub module, states are stored in Mnesia database.</p>
828
854
%% <p>We can consider that the pubsub_state table have been created by the main
831
857
%% relational database).</p>
832
858
%% <p>If a PubSub plugin wants to delegate the states storage to the default node,
833
859
%% they can implement this function like this:
834
 
%% ```get_states(NodeId) ->
835
 
%%         node_default:get_states(NodeId).'''</p>
836
 
get_states(NodeId) ->
 
860
%% ```get_states(NodeIdx) ->
 
861
%%         node_default:get_states(NodeIdx).'''</p>
 
862
get_states(NodeIdx) ->
837
863
    States = case catch mnesia:match_object(
838
 
               #pubsub_state{stateid = {'_', NodeId}, _ = '_'}) of
 
864
               #pubsub_state{stateid = {'_', NodeIdx}, _ = '_'}) of
839
865
        List when is_list(List) -> List;
840
866
        _ -> []
841
867
    end,
842
868
    {result, States}.
843
869
 
844
 
%% @spec (NodeId, JID) -> [State] | []
845
 
%%       NodeId = mod_pubsub:pubsubNodeId()
846
 
%%       JID = mod_pubsub:jid()
847
 
%%       State = mod_pubsub:pubsubItems()
 
870
%% @spec (NodeIdx, JID) -> State
 
871
%%       NodeIdx = mod_pubsub:nodeIdx()
 
872
%%       JID     = mod_pubsub:jid()
 
873
%%       State   = mod_pubsub:pubsubState()
848
874
%% @doc <p>Returns a state (one state list), given its reference.</p>
849
 
get_state(NodeId, JID) ->
850
 
    StateId = {JID, NodeId},
 
875
get_state(NodeIdx, JID) ->
 
876
    StateId = {JID, NodeIdx},
851
877
    case catch mnesia:read({pubsub_state, StateId}) of
852
878
        [State] when is_record(State, pubsub_state) -> State;
853
879
        _ -> #pubsub_state{stateid=StateId}
854
880
    end.
855
881
 
856
 
%% @spec (State) -> ok | {error, Reason::stanzaError()}
857
 
%%       State = mod_pubsub:pubsubStates()
 
882
%% @spec (State) -> ok | {error, Reason}
 
883
%%       State  = mod_pubsub:pubsubState()
 
884
%%       Reason = mod_pubsub:stanzaError()
858
885
%% @doc <p>Write a state into database.</p>
859
886
set_state(State) when is_record(State, pubsub_state) ->
860
887
    mnesia:write(State);
861
888
set_state(_) ->
862
889
    {error, ?ERR_INTERNAL_SERVER_ERROR}.
863
890
 
864
 
%% @spec (NodeId, JID) -> ok | {error, Reason::stanzaError()}
865
 
%%       NodeId = mod_pubsub:pubsubNodeId()
866
 
%%       JID = mod_pubsub:jid()
 
891
%% @spec (NodeIdx, JID) -> ok | {error, Reason}
 
892
%%       NodeIdx = mod_pubsub:nodeIdx()
 
893
%%       JID     = mod_pubsub:jid()
 
894
%%       Reason  = mod_pubsub:stanzaError()
867
895
%% @doc <p>Delete a state from database.</p>
868
 
del_state(NodeId, JID) ->
869
 
    mnesia:delete({pubsub_state, {JID, NodeId}}).
 
896
del_state(NodeIdx, JID) ->
 
897
    mnesia:delete({pubsub_state, {JID, NodeIdx}}).
870
898
 
871
 
%% @spec (NodeId, From) -> [Items] | []
872
 
%%       NodeId = mod_pubsub:pubsubNodeId()
873
 
%%       Items = mod_pubsub:pubsubItems()
 
899
%% @spec (NodeIdx, From) -> {result, Items}
 
900
%%       NodeIdx = mod_pubsub:nodeIdx()
 
901
%%       From    = mod_pubsub:jid()
 
902
%%       Items   = [] | [mod_pubsub:pubsubItem()]
874
903
%% @doc Returns the list of stored items for a given node.
875
904
%% <p>For the default PubSub module, items are stored in Mnesia database.</p>
876
905
%% <p>We can consider that the pubsub_item table have been created by the main
879
908
%% relational database), or they can even decide not to persist any items.</p>
880
909
%% <p>If a PubSub plugin wants to delegate the item storage to the default node,
881
910
%% they can implement this function like this:
882
 
%% ```get_items(NodeId, From) ->
883
 
%%         node_default:get_items(NodeId, From).'''</p>
884
 
get_items(NodeId, _From) ->
885
 
    Items = mnesia:match_object(#pubsub_item{itemid = {'_', NodeId}, _ = '_'}),
 
911
%% ```get_items(NodeIdx, From) ->
 
912
%%         node_default:get_items(NodeIdx, From).'''</p>
 
913
get_items(NodeIdx, _From) ->
 
914
    Items = mnesia:match_object(#pubsub_item{itemid = {'_', NodeIdx}, _ = '_'}),
886
915
    {result, lists:reverse(lists:keysort(#pubsub_item.modification, Items))}.
887
 
get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
 
916
 
 
917
get_items(NodeIdx, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
888
918
    SubKey = jlib:jid_tolower(JID),
889
919
    GenKey = jlib:jid_remove_resource(SubKey),
890
 
    GenState = get_state(NodeId, GenKey),
891
 
    SubState = get_state(NodeId, SubKey),
 
920
    GenState = get_state(NodeIdx, GenKey),
 
921
    SubState = get_state(NodeIdx, SubKey),
892
922
    Affiliation = GenState#pubsub_state.affiliation,
893
923
    Subscriptions = SubState#pubsub_state.subscriptions,
894
924
    Whitelisted = can_fetch_item(Affiliation, Subscriptions),
918
948
        %%      % Payment is required for a subscription
919
949
        %%      {error, ?ERR_PAYMENT_REQUIRED};
920
950
        true ->
921
 
            get_items(NodeId, JID)
 
951
            get_items(NodeIdx, JID)
922
952
    end.
923
953
 
924
 
%% @spec (NodeId, ItemId) -> [Item] | []
925
 
%%       NodeId = mod_pubsub:pubsubNodeId()
926
 
%%       ItemId = string()
927
 
%%       Item = mod_pubsub:pubsubItems()
 
954
%% @spec (NodeIdx, ItemId) -> {result, Item} | {error, 'item-not-found'}
 
955
%%       NodeIdx = mod_pubsub:nodeIdx()
 
956
%%       ItemId  = mod_pubsub:itemId()
 
957
%%       Item    = mod_pubsub:pubsubItem()
928
958
%% @doc <p>Returns an item (one item list), given its reference.</p>
929
 
get_item(NodeId, ItemId) ->
930
 
    case mnesia:read({pubsub_item, {ItemId, NodeId}}) of
 
959
get_item(NodeIdx, ItemId) ->
 
960
    case mnesia:read({pubsub_item, {ItemId, NodeIdx}}) of
931
961
        [Item] when is_record(Item, pubsub_item) ->
932
962
            {result, Item};
933
963
        _ ->
934
964
            {error, ?ERR_ITEM_NOT_FOUND}
935
965
    end.
936
 
get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
 
966
 
 
967
%% @spec (NodeIdx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> {result, Item} | {error, Reason}
 
968
%%       NodeIdx              = mod_pubsub:nodeIdx()
 
969
%%       ItemId               = mod_pubsub:itemId()
 
970
%%       JID                  = mod_pubsub:jid()
 
971
%%       AccessModel          = mod_pubsub:accessModel()
 
972
%%       PresenceSubscription = boolean()
 
973
%%       RosterGroup          = boolean()
 
974
%%       SubId                = mod_pubsub:subId()
 
975
%%       Item                 = mod_pubsub:pubsubItem()
 
976
%%       Reason               = mod_pubsub:stanzaError() | 'item-not-found'
 
977
 
 
978
get_item(NodeIdx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
937
979
    SubKey = jlib:jid_tolower(JID),
938
980
    GenKey = jlib:jid_remove_resource(SubKey),
939
 
    GenState = get_state(NodeId, GenKey),
 
981
    GenState = get_state(NodeIdx, GenKey),
940
982
    Affiliation = GenState#pubsub_state.affiliation,
941
983
    Subscriptions = GenState#pubsub_state.subscriptions,
942
984
    Whitelisted = can_fetch_item(Affiliation, Subscriptions),
966
1008
        %%      % Payment is required for a subscription
967
1009
        %%      {error, ?ERR_PAYMENT_REQUIRED};
968
1010
        true ->
969
 
            get_item(NodeId, ItemId)
 
1011
            get_item(NodeIdx, ItemId)
970
1012
    end.
971
1013
 
972
 
%% @spec (Item) -> ok | {error, Reason::stanzaError()}
973
 
%%       Item = mod_pubsub:pubsubItems()
 
1014
%% @spec (Item) -> ok | {error, Reason}
 
1015
%%       Item   = mod_pubsub:pubsubItem()
 
1016
%%       Reason = mod_pubsub:stanzaError()
974
1017
%% @doc <p>Write an item into database.</p>
975
1018
set_item(Item) when is_record(Item, pubsub_item) ->
976
1019
    mnesia:write(Item);
977
1020
set_item(_) ->
978
1021
    {error, ?ERR_INTERNAL_SERVER_ERROR}.
979
1022
 
980
 
%% @spec (NodeId, ItemId) -> ok | {error, Reason::stanzaError()}
981
 
%%       NodeId = mod_pubsub:pubsubNodeId()
982
 
%%       ItemId = string()
 
1023
%% @spec (NodeIdx, ItemId) -> ok | {error, Reason}
 
1024
%%       NodeIdx = mod_pubsub:nodeIdx()
 
1025
%%       ItemId  = mod_pubsub:itemId()
 
1026
%%       Reason  = mod_pubsub:stanzaError()
983
1027
%% @doc <p>Delete an item from database.</p>
984
 
del_item(NodeId, ItemId) ->
985
 
    mnesia:delete({pubsub_item, {ItemId, NodeId}}).
986
 
del_items(NodeId, ItemIds) ->
 
1028
del_item(NodeIdx, ItemId) ->
 
1029
    mnesia:delete({pubsub_item, {ItemId, NodeIdx}}).
 
1030
 
 
1031
del_items(NodeIdx, ItemIds) ->
987
1032
    lists:foreach(fun(ItemId) ->
988
 
        del_item(NodeId, ItemId)
 
1033
        del_item(NodeIdx, ItemId)
989
1034
    end, ItemIds).
990
1035
 
991
1036
%% @doc <p>Return the name of the node if known: Default is to return