⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mod_pubsub.erl

📁 ejabberd-0.7.5 分布式Jabber服务器
💻 ERL
📖 第 1 页 / 共 2 页
字号:
%%%----------------------------------------------------------------------%%% File    : mod_pubsub.erl%%% Author  : Alexey Shchepin <alexey@sevcom.net>%%% Purpose : Pub/sub support (JEP-0060)%%% Created :  4 Jul 2003 by Alexey Shchepin <alexey@sevcom.net>%%% Id      : $Id: mod_pubsub.erl,v 1.11 2004/09/17 19:52:58 aleksey Exp $%%%-----------------------------------------------------------------------module(mod_pubsub).-author('alexey@sevcom.net').-vsn('$Revision: 1.11 $ ').-behaviour(gen_mod).-export([start/1,	 init/3,	 loop/2,	 stop/0,	 system_continue/3,	 system_terminate/4,	 system_code_change/4]).-include("ejabberd.hrl").-include("jlib.hrl").-define(DICT, dict).-define(MAXITEMS, 10).-record(pubsub_node, {node, parent, info}).-record(nodeinfo, {items = [],		   options = [],		   entities = ?DICT:new()		  }).-record(entity, {affiliation = none,		 subscription = none}).-record(item, {id, publisher, payload}).start(Opts) ->    mnesia:create_table(pubsub_node,			[{disc_only_copies, [node()]},			 {attributes, record_info(fields, pubsub_node)}]),    mnesia:add_table_index(pubsub_node, parent),    Host = gen_mod:get_opt(host, Opts, "pubsub." ++ ?MYNAME),    ServedHosts = gen_mod:get_opt(served_hosts, Opts, [?MYNAME]),    register(ejabberd_mod_pubsub,	     proc_lib:spawn_link(?MODULE, init, [Host, ServedHosts, self()])).-define(MYJID, #jid{user = "", server = Host, resource = "",		    luser = "", lserver = Host, lresource = ""}).init(Host, ServedHosts, Parent) ->    ejabberd_router:register_route(Host),    create_new_node(Host, ["pubsub"], ?MYJID),    create_new_node(Host, ["pubsub", "nodes"], ?MYJID),    create_new_node(Host, ["home"], ?MYJID),    lists:foreach(fun(H) ->			  create_new_node(Host, ["home", H], ?MYJID)		  end, ServedHosts),    loop(Host, Parent).loop(Host, Parent) ->    receive	{route, From, To, Packet} ->	    case catch do_route(Host, From, To, Packet) of		{'EXIT', Reason} ->		    ?ERROR_MSG("~p", [Reason]);		_ ->		    ok	    end,	    loop(Host, Parent);	{room_destroyed, Room} ->	    ets:delete(muc_online_room, Room),	    loop(Host, Parent);	stop ->	    ejabberd_router:unregister_global_route(Host),	    ok;	reload ->	    ?MODULE:loop(Host, Parent);        {system, From, Request} ->            sys:handle_system_msg(Request, From, Parent, ?MODULE, [], Host);	_ ->	    loop(Host, Parent)    end.do_route(Host, From, To, Packet) ->    {xmlelement, Name, Attrs, Els} = Packet,    case To of	#jid{luser = "", lresource = ""} ->	    case Name of		"iq" ->		    case jlib:iq_query_info(Packet) of			#iq{type = get, xmlns = ?NS_DISCO_INFO = XMLNS,			    sub_el = SubEl} = IQ ->			    {xmlelement, _, QAttrs, _} = SubEl,			    Node = xml:get_attr_s("node", QAttrs),			    Res = IQ#iq{type = result,					sub_el = [{xmlelement, "query",						   QAttrs,						   iq_disco_info(Node)}]},			    ejabberd_router:route(To,						  From,						  jlib:iq_to_xml(Res));			#iq{type = get, xmlns = ?NS_DISCO_ITEMS = XMLNS,			    sub_el = SubEl} = IQ ->			    {xmlelement, _, QAttrs, _} = SubEl,			    Node = xml:get_attr_s("node", QAttrs),			    Res =				case iq_disco_items(Host, From, Node) of				    {result, IQRes} ->					jlib:iq_to_xml(					  IQ#iq{type = result,						sub_el = [{xmlelement, "query",							   QAttrs,							   IQRes}]});				    {error, Error} ->					jlib:make_error_reply(					  Packet, Error)				end,			    ejabberd_router:route(To, From, Res);			%#iq{type = get, xmlns = ?NS_REGISTER = XMLNS,			%    lang = Lang, sub_el = SubEl} = IQ ->			%    Res = IQ#iq{type = result,			%		 sub_el = [{xmlelement, "query",			%			    [{"xmlns", XMLNS}],			%			    iq_get_register_info(			%			      From, Lang)}]},			%    ejabberd_router:route(To,			%			  From,			%			  jlib:iq_to_xml(Res));			%#iq{type = set, xmlns = ?NS_REGISTER = XMLNS,			%    sub_el = SubEl} = IQ ->			%    case process_iq_register_set(From, SubEl) of			%	{result, IQRes} ->			%	    Res = IQ#iq{type = result,			%			sub_el = [{xmlelement, "query",			%				   [{"xmlns", XMLNS}],			%				   IQRes}]},			%	    ejabberd_router:route(			%	      To, From, jlib:iq_to_xml(Res));			%	{error, Error} ->			%	    Err = jlib:make_error_reply(			%		    Packet, Error),			%	    ejabberd_router:route(			%	      To, From, Err)			%    end;			#iq{type = Type, xmlns = ?NS_PUBSUB = XMLNS,			    sub_el = SubEl} = IQ ->			    Res =				case iq_pubsub(Host, From, Type, SubEl) of				    {result, IQRes} ->					jlib:iq_to_xml(					  IQ#iq{type = result,						sub_el = IQRes});				    {error, Error} ->					jlib:make_error_reply(					  Packet, Error)				end,			    ejabberd_router:route(To, From, Res);			#iq{type = get, xmlns = ?NS_VCARD = XMLNS,			    lang = Lang, sub_el = SubEl} = IQ ->			    Res = IQ#iq{type = result,					sub_el = [{xmlelement, "vCard",						   [{"xmlns", XMLNS}],						   iq_get_vcard(Lang)}]},			    ejabberd_router:route(To,						  From,						  jlib:iq_to_xml(Res));			#iq{} ->			    Err = jlib:make_error_reply(				    Packet,				    ?ERR_FEATURE_NOT_IMPLEMENTED),			    ejabberd_router:route(To, From, Err);			_ ->			    ok		    end;		_ ->		    ok	    end;	_ ->	    case xml:get_attr_s("type", Attrs) of		"error" ->		    ok;		"result" ->		    ok;		_ ->		    Err = jlib:make_error_reply(			    Packet, ?ERR_ITEM_NOT_FOUND),		    ejabberd_router:route(To, From, Err)	    end    end.stop() ->    ejabberd_mod_pubsub ! stop,    ok.node_to_string(Node) ->    string:strip(lists:flatten(lists:map(fun(S) -> [S, "/"] end, Node)),		 right, $/).iq_disco_info(SNode) ->    Node = string:tokens(SNode, "/"),    case Node of	[] ->	    [{xmlelement, "identity",	      [{"category", "pubsub"},	       {"type", "generic"},	       {"name", "ejabberd/mod_pubsub"}], []},	     %{xmlelement, "feature", [{"var", ?NS_REGISTER}], []},	     {xmlelement, "feature", [{"var", ?NS_PUBSUB}], []},	     {xmlelement, "feature", [{"var", ?NS_PUBSUB_EVENT}], []},	     {xmlelement, "feature", [{"var", ?NS_PUBSUB_OWNER}], []},	     {xmlelement, "feature", [{"var", ?NS_VCARD}], []}];	_ ->	    % TODO	    []    end.iq_disco_items(Host, From, SNode) ->    Node = string:tokens(SNode, "/"),    F = fun() ->		case mnesia:read({pubsub_node, Node}) of		    [#pubsub_node{info = Info}] ->			SubNodes = mnesia:index_read(pubsub_node,						     Node,						     #pubsub_node.parent),			SubItems =			    lists:map(fun(#pubsub_node{node = N}) ->					      SN = node_to_string(N),					      {xmlelement, "item",					       [{"jid", Host},						{"node", SN},						{"name", lists:last(N)}], []}				      end, SubNodes),			SN = node_to_string(Node),			Items =			    lists:map(fun(#item{id = Name}) ->					      {xmlelement, "item",					       [{"jid", Host},						{"node", SN ++ "!" ++ Name},						{"name", Name}], []}				      end, Info#nodeinfo.items),			SubItems ++ Items;		    [] ->			case Node of			    [] ->				SubNodes = mnesia:index_read(					     pubsub_node,					     Node,					     #pubsub_node.parent),				lists:map(				  fun(#pubsub_node{node = N}) ->					  SN = node_to_string(N),					  {xmlelement, "item",					   [{"jid", Host},					    {"node", SN},					    {"name", lists:last(N)}],					   []}				  end, SubNodes) ;			    _ ->				{error, ?ERR_ITEM_NOT_FOUND}			end		end	end,    case mnesia:transaction(F) of	{atomic, {error, _} = Error} ->	    Error;	{atomic, Res} ->	    {result, Res};	_ ->	    {error, ?ERR_INTERNAL_SERVER_ERROR}    end.% TODO%-define(XFIELD(Type, Label, Var, Val),%	{xmlelement, "field", [{"type", Type},%			       {"label", translate:translate(Lang, Label)},%			       {"var", Var}],%	 [{xmlelement, "value", [], [{xmlcdata, Val}]}]}).%%iq_get_register_info(From, Lang) ->%    {LUser, LServer, _} = jlib:jid_tolower(From),%    LUS = {LUser, LServer},%    Nick = case catch mnesia:dirty_read(muc_registered, LUS) of%	       {'EXIT', Reason} ->%		   "";%	       [] ->%		   "";%	       [#muc_registered{nick = N}] ->%		   N%	   end,%    [{xmlelement, "instructions", [],%      [{xmlcdata, translate:translate(%		    Lang, "You need a x:data capable client to register.")}]},%     {xmlelement, "x",%      [{"xmlns", ?NS_XDATA}],%      [{xmlelement, "title", [],%	[{xmlcdata,%	  translate:translate(%	    Lang, "Nick Registration")}]},%       {xmlelement, "instructions", [],%	[{xmlcdata,%	  translate:translate(%	    Lang, "Enter nick you want to register.")}]},%       ?XFIELD("text-single", "Nick", "nick", Nick)]}].%%iq_set_register_info(From, XData) ->%    {LUser, LServer, _} = jlib:jid_tolower(From),%    LUS = {LUser, LServer},%    case lists:keysearch("nick", 1, XData) of%	false ->%	    {error, ?ERR_BAD_REQUEST};%	{value, {_, [Nick]}} ->%	    F = fun() ->%			case Nick of%			    "" ->%				mnesia:delete({muc_registered, LUS}),%				ok;%			    _ ->%				Allow = case mnesia:index_read(%					       muc_registered,%					       Nick,%					       #muc_registered.nick) of%					    [] ->%						true;%					    [#muc_registered{user = U}] ->%						U == LUS%					end,%				if%				    Allow ->%					mnesia:write(%					  #muc_registered{user = LUS,%							  nick = Nick}),%					ok;%				    true ->%					false%				end%			end%		end,%	    case mnesia:transaction(F) of%		{atomic, ok} ->%		    {result, []};%		{atomic, false} ->%		    {error, ?ERR_NOT_ALLOWED};%		_ ->%		    {error, ?ERR_INTERNAL_SERVER_ERROR}%	    end%    end.%%process_iq_register_set(From, SubEl) ->%    {xmlelement, Name, Attrs, Els} = SubEl,%    case xml:remove_cdata(Els) of%	[{xmlelement, "x", Attrs1, Els1} = XEl] ->%	    case {xml:get_tag_attr_s("xmlns", XEl),%		  xml:get_tag_attr_s("type", XEl)} of%		{?NS_XDATA, "cancel"} ->%		    {result, []};%		{?NS_XDATA, "submit"} ->%		    XData = jlib:parse_xdata_submit(XEl),%		    case XData of%			invalid ->%			    {error, ?ERR_BAD_REQUEST};%			_ ->%			    iq_set_register_info(From, XData)%		    end;%		_ ->%		    {error, ?ERR_BAD_REQUEST}%	    end;%	_ ->%	    {error, ?ERR_BAD_REQUEST}%    end.iq_get_vcard(Lang) ->    [{xmlelement, "FN", [],      [{xmlcdata, "ejabberd/mod_pubsub"}]},     {xmlelement, "URL", [],      [{xmlcdata,	"http://ejabberd.jabberstudio.org/"}]},     {xmlelement, "DESC", [],      [{xmlcdata, translate:translate(		    Lang,		    "ejabberd pub/sub module\n"		    "Copyright (c) 2003-2004 Alexey Shchepin")}]}].iq_pubsub(Host, From, Type, SubEl) ->    {xmlelement, _, _, SubEls} = SubEl,    case xml:remove_cdata(SubEls) of	[{xmlelement, Name, Attrs, Els}] ->	    SNode = xml:get_attr_s("node", Attrs),	    Node = string:tokens(SNode, "/"),	    case {Type, Name} of		{set, "create"} ->		    create_new_node(Host, Node, From);		{set, "publish"} ->		    case xml:remove_cdata(Els) of			[{xmlelement, "item", ItemAttrs, Payload}] ->			    ItemID = xml:get_attr_s("id", ItemAttrs),			    publish_item(Host, From, Node, ItemID, Payload);			_ ->			    {error, ?ERR_BAD_REQUEST}		    end;		{set, "retract"} ->		    case xml:remove_cdata(Els) of			[{xmlelement, "item", ItemAttrs, _}] ->			    ItemID = xml:get_attr_s("id", ItemAttrs),			    delete_item(Host, From, Node, ItemID);			_ ->			    {error, ?ERR_BAD_REQUEST}		    end;		{set, "subscribe"} ->		    JID = xml:get_attr_s("jid", Attrs),		    subscribe_node(Host, From, JID, Node);		{set, "unsubscribe"} ->		    JID = xml:get_attr_s("jid", Attrs),		    unsubscribe_node(Host, From, JID, Node);		{get, "items"} ->		    MaxItems = xml:get_attr_s("max_items", Attrs),		    get_items(Host, From, Node, MaxItems);		{set, "delete"} ->		    delete_node(Host, From, Node);		{set, "purge"} ->		    purge_node(Host, From, Node);		{get, "entities"} ->		    get_entities(From, Node);		{set, "entities"} ->		    set_entities(From, Node, xml:remove_cdata(Els));		%{get, "configure"} ->		%    get_node_config(From, Node);		_ ->		    {error, ?ERR_FEATURE_NOT_IMPLEMENTED}	    end;	_ ->	    {error, ?ERR_BAD_REQUEST}    end.-define(XFIELD(Type, Label, Var, Val),	{xmlelement, "field", [{"type", Type},			       {"label", translate:translate(Lang, Label)},			       {"var", Var}],	 [{xmlelement, "value", [], [{xmlcdata, Val}]}]}).%% Create new pubsub nodes%% This function is used during init to create the first bootstrap nodescreate_new_node(Host, Node, Owner) ->    case Node of	[] ->	    {LOU, LOS, _} = jlib:jid_tolower(Owner),	    HomeNode = ["home", LOS, LOU],	    create_new_node(Host, HomeNode, Owner),	    NewNode = ["home", LOS, LOU, randoms:get_string()],	    create_new_node(Host, NewNode, Owner);	_ ->	    LOwner = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),	    Parent = lists:sublist(Node, length(Node) - 1),	    F = fun() ->			ParentExists = (Parent == []) orelse			    case mnesia:read({pubsub_node, Parent}) of				[_] ->				    true;				[] ->				    false			    end,			case ParentExists of			    false ->				{error, ?ERR_CONFLICT};			    _ ->				case mnesia:read({pubsub_node, Node}) of				    [_] ->					{error, ?ERR_CONFLICT};				    [] ->					Entities =					    ?DICT:store(					       LOwner,					       #entity{affiliation = owner,						       subscription = none},					       ?DICT:new()),					mnesia:write(					  #pubsub_node{node = Node,						       parent = Parent,						       info = #nodeinfo{							 entities = Entities}}),					ok				end			end		end,	    case check_create_permission(Host, Node, Owner) of		true ->		    case mnesia:transaction(F) of			{atomic, ok} ->			    Lang = "",			    broadcast_publish_item(			      Host, ["pubsub", "nodes"], node_to_string(Node),			      [{xmlelement, "x",				[{"xmlns", ?NS_XDATA},				 {"type", "result"}],				[?XFIELD("hidden", "", "FORM_TYPE",					 ?NS_PUBSUB_NMI),				 ?XFIELD("jid-single", "Node Creator",					 "creator",					 jlib:jid_to_string(LOwner))]}]),			    {result,			     [{xmlelement, "pubsub",				[{"xmlns", ?NS_PUBSUB}],				[{xmlelement, "create",				  [{"node", node_to_string(Node)}], []}]}]};			{atomic, {error, _} = Error} ->			    Error;			_ ->			    {error, ?ERR_INTERNAL_SERVER_ERROR}		    end;		_ ->		    {error, ?ERR_NOT_ALLOWED}	    end    end.publish_item(Host, JID, Node, ItemID, Payload) ->    Publisher = jlib:jid_tolower(jlib:jid_remove_resource(JID)),    F = fun() ->		case mnesia:read({pubsub_node, Node}) of		    [#pubsub_node{info = Info} = N] ->			Affiliation = get_affiliation(Info, Publisher),			if			    (Affiliation == owner) or			    (Affiliation == publisher) ->				NewInfo =				    insert_item(Info, ItemID,						Publisher, Payload),				mnesia:write(				  N#pubsub_node{info = NewInfo}),				{result, []};			    true ->				{error, ?ERR_NOT_ALLOWED}			end;		    [] ->			{error, ?ERR_ITEM_NOT_FOUND}		end	end,    case mnesia:transaction(F) of	{atomic, {error, _} = Error} ->	    Error;	{atomic, {result, Res}} ->	    broadcast_publish_item(Host, Node, ItemID, Payload),	    {result, Res};	_ ->	    {error, ?ERR_INTERNAL_SERVER_ERROR}    end.delete_item(Host, JID, Node, ItemID) ->    Publisher = jlib:jid_tolower(jlib:jid_remove_resource(JID)),    F = fun() ->		case mnesia:read({pubsub_node, Node}) of		    [#pubsub_node{info = Info} = N] ->			case check_item_publisher(Info, ItemID, Publisher)			    orelse			    (get_affiliation(Info, Publisher) == owner) of			    true ->				NewInfo =				    remove_item(Info, ItemID),				mnesia:write(				  N#pubsub_node{info = NewInfo}),				{result, []};			    _ ->				{error, ?ERR_NOT_ALLOWED}			end;		    [] ->			{error, ?ERR_ITEM_NOT_FOUND}		end	end,    case mnesia:transaction(F) of	{atomic, {error, _} = Error} ->

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -