aboutsummaryrefslogtreecommitdiff
path: root/src/web/pshb_http.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/web/pshb_http.erl')
-rw-r--r--src/web/pshb_http.erl792
1 files changed, 437 insertions, 355 deletions
diff --git a/src/web/pshb_http.erl b/src/web/pshb_http.erl
index 02eb0a4cc..6f1a7a52c 100644
--- a/src/web/pshb_http.erl
+++ b/src/web/pshb_http.erl
@@ -25,7 +25,7 @@
%%%----------------------------------------------------------------------
%%%
%%% {5280, ejabberd_http, [
-%%% http_poll,
+%%% http_poll,
%%% web_admin,
%%% {request_handlers, [{["pshb"], pshb_http}]} % this should be added
%%% ]}
@@ -34,383 +34,465 @@
%%% curl -u cstar@localhost:encore -i -X POST http://localhost:5280/pshb/localhost/foo -d @sam.atom
%%%
+-module(pshb_http).
--module (pshb_http).
-author('ecestari@process-one.net').
--compile({no_auto_import,[error/1]}).
+-compile({no_auto_import, [{error, 1}]}).
-include("ejabberd.hrl").
+
-include("jlib.hrl").
+
-include("ejabberd_http.hrl").
-include("mod_pubsub/pubsub.hrl").
--export([process/2]).
-
-process([Domain | _Rest] = LocalPath, #request{auth = Auth} = Request)->
- UD = get_auth(Auth),
- Module = backend(Domain),
- case catch out(Module, Request, Request#request.method, LocalPath,UD) of
- {'EXIT', Error} ->
- ?ERROR_MSG("Error while processing ~p : ~n~p", [LocalPath, Error]),
- error(500);
- Result ->
- Result
- end.
-
+-export([process/2]).
+
+process([Domain | _Rest] = LocalPath,
+ #request{auth = Auth} = Request) ->
+ UD = get_auth(Auth),
+ Module = backend(Domain),
+ case catch out(Module, Request, Request#request.method,
+ LocalPath, UD)
+ of
+ {'EXIT', Error} ->
+ ?ERROR_MSG("Error while processing ~p : ~n~p",
+ [LocalPath, Error]),
+ error(500);
+ Result -> Result
+ end.
+
get_auth(Auth) ->
case Auth of
- {SJID, P} ->
- case jlib:string_to_jid(SJID) of
- error ->
- undefined;
- #jid{user = U, server = S} ->
- case ejabberd_auth:check_password(U, S, P) of
- true ->
- {U, S};
- false ->
- undefined
- end
- end;
- _ ->
- undefined
+ {SJID, P} ->
+ case jlib:string_to_jid(SJID) of
+ error -> undefined;
+ #jid{user = U, server = S} ->
+ case ejabberd_auth:check_password(U, S, P) of
+ true -> {U, S};
+ false -> undefined
+ end
+ end;
+ _ -> undefined
end.
-out(Module, Args, 'GET', [Domain,Node]=Uri, _User) ->
- case Module:tree_action(get_host(Uri), get_node, [get_host(Uri),get_collection(Uri)]) of
- {error, Error} ->
- error(Error);
- #pubsub_node{options = Options}->
+out(Module, Args, 'GET', [Domain, Node] = Uri, _User) ->
+ case Module:tree_action(get_host(Uri), get_node,
+ [get_host(Uri), get_collection(Uri)])
+ of
+ {error, Error} -> error(Error);
+ #pubsub_node{options = Options} ->
AccessModel = lists:keyfind(access_model, 1, Options),
case AccessModel of
{access_model, open} ->
- Items = lists:sort(fun(X,Y)->
- {DateX, _} = X#pubsub_item.modification,
- {DateY, _} = Y#pubsub_item.modification,
- DateX > DateY
- end, Module:get_items(
- get_host(Uri),
- get_collection(Uri))),
- case Items of
- [] -> ?DEBUG("Items : ~p ~n", [collection(get_collection(Uri),
- collection_uri(Args,Domain,Node), calendar:now_to_universal_time(erlang:now()), "", [])]),
- {200, [{"Content-Type", "application/atom+xml"}],
- collection(get_collection(Uri),
- collection_uri(Args,Domain,Node), calendar:now_to_universal_time(erlang:now()), "", [])};
- _ ->
- #pubsub_item{modification = {LastDate, _JID}} = LastItem = hd(Items),
- Etag =generate_etag(LastItem),
- IfNoneMatch=proplists:get_value('If-None-Match', Args#request.headers),
- if IfNoneMatch==Etag
- ->
- success(304);
- true ->
- XMLEntries= [item_to_entry(Args,Domain, Node,Entry)||Entry <- Items],
- {200, [{"Content-Type", "application/atom+xml"},{"Etag", Etag}],
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
- ++ xml:element_to_string(
- collection(get_collection(Uri), collection_uri(Args,Domain,Node),
- calendar:now_to_universal_time(LastDate), "", XMLEntries))}
- end
- end;
- {access_model, Access} ->
- ?INFO_MSG("Uri ~p requested. access_model is ~p. HTTP access denied unless access_model =:= open",
- [Uri, Access]),
- error(?ERR_FORBIDDEN)
- end
- end;
-
-out(Module, Args, 'POST', [_D, _Node]=Uri, {_User, _Domain} = UD) ->
- publish_item(Module, Args, Uri, uniqid(false), UD);
-
-out(Module, Args, 'PUT', [_D, _Node, Slug]=Uri, {_User, _Domain} = UD) ->
- publish_item(Module, Args, Uri, Slug, UD);
-
-out(Module, _Args, 'DELETE', [_D, Node, Id]= Uri, {User, UDomain}) ->
- Jid = jlib:make_jid({User, UDomain, ""}),
- case Module:delete_item(get_host(Uri), list_to_binary(Node), Jid, Id) of
- {error, Error} -> error(Error);
- {result, _Res} -> success(200)
- end;
-
-
-out(Module, Args, 'PUT', [_Domain, Node]= Uri, {User, UDomain}) ->
- Host = get_host(Uri),
- Jid = jlib:make_jid({User, UDomain, ""}),
- Payload = xml_stream:parse_element(Args#request.data),
- ConfigureElement = case xml:get_subtag(Payload, "configure") of
- false ->[];
- {xmlelement, _, _, SubEls}->SubEls
- end,
- case Module:set_configure(Host, list_to_binary(Node), Jid, ConfigureElement, Args#request.lang) of
- {result, []} -> success(200);
- {error, Error} -> error(Error)
- end;
-
-out(Module, Args, 'GET', [Domain]=Uri, From)->
- Host = get_host(Uri),
- ?DEBUG("Host = ~p", [Host]),
- case Module:tree_action(Host, get_subnodes, [Host, <<>>, From ]) of
- [] ->
- ?DEBUG("Error getting URI ~p : ~p",[Uri, From]),
- error(?ERR_ITEM_NOT_FOUND);
- Collections ->
- {200, [{"Content-Type", "application/atomsvc+xml"}], "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
- ++ xml:element_to_string(service(Args,Domain, Collections))}
- end;
-
-out(Module, Args, 'POST', [Domain]=Uri, {User, UDomain})->
- Host = get_host(Uri),
- Payload = xml_stream:parse_element(Args#request.data),
- {Node, Type} = case xml:get_subtag(Payload, "create") of
- false -> {<<>>,"flat"};
- E ->
- {list_to_binary(get_tag_attr_or_default("node", E,"")),
- get_tag_attr_or_default("type", E,"flat")}
- end,
- ConfigureElement = case xml:get_subtag(Payload, "configure") of
- false ->[];
- {xmlelement, _, _, SubEls}->SubEls
- end,
- Jid = jlib:make_jid({User, UDomain, ""}),
- case Module:create_node(Host, Domain, Node, Jid, Type, all, ConfigureElement) of
- {error, Error} ->
- ?ERROR_MSG("Error create node via HTTP : ~p",[Error]),
- error(Error); % will probably detail more
- {result, [Result]} ->
- {200, [{"Content-Type", "application/xml"}], "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
- ++ xml:element_to_string(Result)}
- end;
-
-out(Module,_Args, 'DELETE', [_Domain, Node] = Uri, {User, UDomain})->
- Host = get_host(Uri),
- Jid = jlib:make_jid({User, UDomain, ""}),
- BinNode = list_to_binary(Node),
- case Module:delete_node(Host, BinNode, Jid) of
- {error, Error} -> error(Error);
- {result, []} ->
- {200, [],[]}
- end;
-
-
-
-out(Module, Args, 'GET', [Domain, Node, _Item]=URI, _) ->
- Failure = fun(Error)->
- ?DEBUG("Error getting URI ~p : ~p",[URI, Error]),
- error(Error)
- end,
- Success = fun(Item)->
- Etag =generate_etag(Item),
- IfNoneMatch=proplists:get_value('If-None-Match', Args#request.headers),
- if IfNoneMatch==Etag
- ->
- success(304);
- true ->
- {200, [{"Content-Type", "application/atom+xml"},{"Etag", Etag}], "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
- ++ xml:element_to_string(item_to_entry(Args, Domain,Node, Item))}
- end
- end,
- get_item(Module, URI, Failure, Success);
-
-out(_Module,_,Method,Uri,undefined) ->
- ?DEBUG("Error, ~p not authorized for ~p : ~p",[ Method,Uri]),
- error(?ERR_FORBIDDEN).
-
-get_item(Module, Uri, Failure, Success)->
- ?DEBUG(" Module:get_item(~p, ~p,~p)", [get_host(Uri), get_collection(Uri), get_member(Uri)]),
- case Module:get_item(get_host(Uri), get_collection(Uri), get_member(Uri)) of
- {error, Reason} ->
- Failure(Reason);
- #pubsub_item{}=Item ->
- Success(Item)
- end.
-
-publish_item(Module, Args, [Domain, Node | _R] = Uri, Slug, {User, Domain})->
-
- Payload = xml_stream:parse_element(Args#request.data),
- [FilteredPayload]=xml:remove_cdata([Payload]),
-
- %FilteredPayload2 = case xml:get_subtag(FilteredPayload, "app:edited") ->
- % {xmlelement, Name, Attrs, [{cdata, }]}
- case Module:publish_item(get_host(Uri),
- Domain,
- get_collection(Uri),
- jlib:make_jid(User,Domain, ""),
- Slug,
- [FilteredPayload]) of
- {result, [_]} ->
- ?DEBUG("Publishing to ~p~n",[entry_uri(Args, Domain, Node,Slug)]),
- {201, [{"location", entry_uri(Args, Domain,Node,Slug)}], Payload};
- {error, Error} ->
- error(Error)
- end.
-
-generate_etag(#pubsub_item{modification={{_, D2, D3}, _JID}})->integer_to_list(D3+D2).
-get_host([Domain|_Rest])-> "pubsub."++Domain.
-get_collection([_Domain, Node|_Rest])->list_to_binary(Node).
-get_member([_Domain, _Node, Member])->
- Member.
+ Items = lists:sort(fun (X, Y) ->
+ {DateX, _} =
+ X#pubsub_item.modification,
+ {DateY, _} =
+ Y#pubsub_item.modification,
+ DateX > DateY
+ end,
+ Module:get_items(get_host(Uri),
+ get_collection(Uri))),
+ case Items of
+ [] ->
+ ?DEBUG("Items : ~p ~n",
+ [collection(get_collection(Uri),
+ collection_uri(Args, Domain, Node),
+ calendar:now_to_universal_time(erlang:now()),
+ <<"">>, [])]),
+ {200,
+ [{<<"Content-Type">>, <<"application/atom+xml">>}],
+ collection(get_collection(Uri),
+ collection_uri(Args, Domain, Node),
+ calendar:now_to_universal_time(erlang:now()),
+ <<"">>, [])};
+ _ ->
+ #pubsub_item{modification = {LastDate, _JID}} =
+ LastItem = hd(Items),
+ Etag = generate_etag(LastItem),
+ IfNoneMatch = proplists:get_value('If-None-Match',
+ Args#request.headers),
+ if IfNoneMatch == Etag -> success(304);
+ true ->
+ XMLEntries = [item_to_entry(Args, Domain, Node,
+ Entry)
+ || Entry <- Items],
+ {200,
+ [{<<"Content-Type">>, <<"application/atom+xml">>},
+ {<<"Etag">>, Etag}],
+ <<"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n",
+ (xml:element_to_binary(collection(get_collection(Uri),
+ collection_uri(Args,
+ Domain,
+ Node),
+ calendar:now_to_universal_time(LastDate),
+ <<"">>,
+ XMLEntries)))/binary>>}
+ end
+ end;
+ {access_model, Access} ->
+ ?INFO_MSG("Uri ~p requested. access_model is ~p. "
+ "HTTP access denied unless access_model "
+ "=:= open",
+ [Uri, Access]),
+ error(?ERR_FORBIDDEN)
+ end
+ end;
+out(Module, Args, 'POST', [_D, _Node] = Uri,
+ {_User, _Domain} = UD) ->
+ publish_item(Module, Args, Uri, uniqid(false), UD);
+out(Module, Args, 'PUT', [_D, _Node, Slug] = Uri,
+ {_User, _Domain} = UD) ->
+ publish_item(Module, Args, Uri, Slug, UD);
+out(Module, _Args, 'DELETE', [_D, Node, Id] = Uri,
+ {User, UDomain}) ->
+ Jid = jlib:make_jid({User, UDomain, <<"">>}),
+ case Module:delete_item(get_host(Uri),
+ iolist_to_binary(Node), Jid, Id)
+ of
+ {error, Error} -> error(Error);
+ {result, _Res} -> success(200)
+ end;
+out(Module, Args, 'PUT', [_Domain, Node] = Uri,
+ {User, UDomain}) ->
+ Host = get_host(Uri),
+ Jid = jlib:make_jid({User, UDomain, <<"">>}),
+ Payload = xml_stream:parse_element(Args#request.data),
+ ConfigureElement = case xml:get_subtag(Payload,
+ <<"configure">>)
+ of
+ false -> [];
+ #xmlel{children = SubEls} -> SubEls
+ end,
+ case Module:set_configure(Host, iolist_to_binary(Node),
+ Jid, ConfigureElement, Args#request.lang)
+ of
+ {result, []} -> success(200);
+ {error, Error} -> error(Error)
+ end;
+out(Module, Args, 'GET', [Domain] = Uri, From) ->
+ Host = get_host(Uri),
+ ?DEBUG("Host = ~p", [Host]),
+ case Module:tree_action(Host, get_subnodes,
+ [Host, <<>>, From])
+ of
+ [] ->
+ ?DEBUG("Error getting URI ~p : ~p", [Uri, From]),
+ error(?ERR_ITEM_NOT_FOUND);
+ Collections ->
+ {200,
+ [{<<"Content-Type">>, <<"application/atomsvc+xml">>}],
+ <<"<?xml version=\"1.0\" encoding=\"utf-8\"?>",
+ (xml:element_to_binary(service(Args, Domain,
+ Collections)))/binary>>}
+ end;
+out(Module, Args, 'POST', [Domain] = Uri,
+ {User, UDomain}) ->
+ Host = get_host(Uri),
+ Payload = xml_stream:parse_element(Args#request.data),
+ {Node, Type} = case xml:get_subtag(Payload,
+ <<"create">>)
+ of
+ false -> {<<>>, <<"flat">>};
+ E ->
+ {get_tag_attr_or_default(<<"node">>, E, <<"">>),
+ get_tag_attr_or_default(<<"type">>, E, <<"flat">>)}
+ end,
+ ConfigureElement = case xml:get_subtag(Payload,
+ <<"configure">>)
+ of
+ false -> [];
+ #xmlel{children = SubEls} -> SubEls
+ end,
+ Jid = jlib:make_jid({User, UDomain, <<"">>}),
+ case Module:create_node(Host, Domain, Node, Jid, Type,
+ all, ConfigureElement)
+ of
+ {error, Error} ->
+ ?ERROR_MSG("Error create node via HTTP : ~p", [Error]),
+ error(Error);
+ {result, [Result]} ->
+ {200, [{<<"Content-Type">>, <<"application/xml">>}],
+ <<"<?xml version=\"1.0\" encoding=\"utf-8\"?>",
+ (xml:element_to_binary(Result))/binary>>}
+ end;
+out(Module, _Args, 'DELETE', [_Domain, Node] = Uri,
+ {User, UDomain}) ->
+ Host = get_host(Uri),
+ Jid = jlib:make_jid({User, UDomain, <<"">>}),
+ case Module:delete_node(Host, Node, Jid) of
+ {error, Error} -> error(Error);
+ {result, []} -> {200, [], []}
+ end;
+out(Module, Args, 'GET', [Domain, Node, _Item] = URI,
+ _) ->
+ Failure = fun (Error) ->
+ ?DEBUG("Error getting URI ~p : ~p", [URI, Error]),
+ error(Error)
+ end,
+ Success = fun (Item) ->
+ Etag = generate_etag(Item),
+ IfNoneMatch = proplists:get_value('If-None-Match',
+ Args#request.headers),
+ if IfNoneMatch == Etag -> success(304);
+ true ->
+ {200,
+ [{<<"Content-Type">>, <<"application/atom+xml">>},
+ {<<"Etag">>, Etag}],
+ <<"<?xml version=\"1.0\" encoding=\"utf-8\"?>",
+ (xml:element_to_binary(item_to_entry(Args,
+ Domain,
+ Node,
+ Item)))/binary>>}
+ end
+ end,
+ get_item(Module, URI, Failure, Success);
+out(_Module, _, Method, Uri, undefined) ->
+ ?DEBUG("Error, ~p not authorized for ~p : ~p",
+ [Method, Uri]),
+ error(?ERR_FORBIDDEN).
+
+get_item(Module, Uri, Failure, Success) ->
+ ?DEBUG(" Module:get_item(~p, ~p,~p)",
+ [get_host(Uri), get_collection(Uri), get_member(Uri)]),
+ case Module:get_item(get_host(Uri), get_collection(Uri),
+ get_member(Uri))
+ of
+ {error, Reason} -> Failure(Reason);
+ #pubsub_item{} = Item -> Success(Item)
+ end.
+
+publish_item(Module, Args, [Domain, Node | _R] = Uri,
+ Slug, {User, Domain}) ->
+ Payload = xml_stream:parse_element(Args#request.data),
+ [FilteredPayload] = xml:remove_cdata([Payload]),
+ case Module:publish_item(get_host(Uri), Domain,
+ get_collection(Uri),
+ jlib:make_jid(User, Domain, <<"">>), Slug,
+ [FilteredPayload])
+ of
+ {result, [_]} ->
+ ?DEBUG("Publishing to ~p~n",
+ [entry_uri(Args, Domain, Node, Slug)]),
+ {201,
+ [{<<"location">>, entry_uri(Args, Domain, Node, Slug)}],
+ Payload};
+ {error, Error} -> error(Error)
+ end.
+
+generate_etag(#pubsub_item{modification =
+ {{_, D2, D3}, _JID}}) ->
+ jlib:integer_to_binary(D3 + D2).
+
+get_host([Domain | _Rest]) ->
+ <<"pubsub.", Domain/binary>>.
+
+get_collection([_Domain, Node | _Rest]) ->
+ Node.
+
+get_member([_Domain, _Node, Member]) -> Member.
collection_uri(R, Domain, Node) ->
- base_uri(R, Domain)++ "/" ++ b2l(Node).
-
-entry_uri(R,Domain, Node, Id)->
- collection_uri(R,Domain, Node)++"/"++b2l(Id).
-
-base_uri(#request{host=Host, port=Port}, Domain)->
- "http://"++Host++":"++i2l(Port)++"/pshb/" ++ Domain.
-
-item_to_entry(Args,Domain, Node,#pubsub_item{itemid={Id,_}, payload=Entry}=Item)->
- [R]=xml:remove_cdata(Entry),
- item_to_entry(Args, Domain, Node, Id, R, Item).
-
-item_to_entry(Args,Domain, Node, Id,{xmlelement, "entry", Attrs, SubEl},
- #pubsub_item{modification={ Secs, JID} }) ->
- Date = calendar:now_to_local_time(Secs),
- {_User, Domain, _}=jlib:jid_tolower(JID),
- SubEl2=[{xmlelement, "app:edited", [], [{xmlcdata, w3cdtf(Date)}]},
- {xmlelement, "updated", [],[{xmlcdata, w3cdtf(Date)}]},
- {xmlelement, "author", [],[{xmlelement, "name", [], [{xmlcdata, list_to_binary(jlib:jid_to_string(JID))}]}]},
- {xmlelement, "link",[{"rel", "edit"},
- {"href", entry_uri(Args,Domain,Node, Id)}],[] },
- {xmlelement, "id", [],[{xmlcdata, entry_uri(Args, Domain, Node, Id)}]}
- | SubEl],
- {xmlelement, "entry", [{"xmlns:app","http://www.w3.org/2007/app"}|Attrs], SubEl2};
-
+ <<(base_uri(R, Domain))/binary, "/",
+ Node/binary>>.
+
+entry_uri(R, Domain, Node, Id) ->
+ <<(collection_uri(R, Domain, Node))/binary, "/",
+ Id/binary>>.
+
+base_uri(#request{host = Host, port = Port}, Domain) ->
+ <<"http://", Host/binary, ":", (i2l(Port))/binary,
+ "/pshb/", Domain/binary>>.
+
+item_to_entry(Args, Domain, Node,
+ #pubsub_item{itemid = {Id, _}, payload = Entry} =
+ Item) ->
+ [R] = xml:remove_cdata(Entry),
+ item_to_entry(Args, Domain, Node, Id, R, Item).
+
+item_to_entry(Args, Domain, Node, Id,
+ #xmlel{name = <<"entry">>, attrs = Attrs,
+ children = SubEl},
+ #pubsub_item{modification = {Secs, JID}}) ->
+ Date = calendar:now_to_local_time(Secs),
+ {_User, Domain, _} = jlib:jid_tolower(JID),
+ SubEl2 = [#xmlel{name = <<"app:edited">>, attrs = [],
+ children = [{xmlcdata, w3cdtf(Date)}]},
+ #xmlel{name = <<"updated">>, attrs = [],
+ children = [{xmlcdata, w3cdtf(Date)}]},
+ #xmlel{name = <<"author">>, attrs = [],
+ children =
+ [#xmlel{name = <<"name">>, attrs = [],
+ children =
+ [{xmlcdata,
+ jlib:jid_to_string(JID)}]}]},
+ #xmlel{name = <<"link">>,
+ attrs =
+ [{<<"rel">>, <<"edit">>},
+ {<<"href">>, entry_uri(Args, Domain, Node, Id)}],
+ children = []},
+ #xmlel{name = <<"id">>, attrs = [],
+ children =
+ [{xmlcdata, entry_uri(Args, Domain, Node, Id)}]}
+ | SubEl],
+ #xmlel{name = <<"entry">>,
+ attrs =
+ [{<<"xmlns:app">>, <<"http://www.w3.org/2007/app">>}
+ | Attrs],
+ children = SubEl2};
% Don't do anything except adding xmlns
-item_to_entry(_Args,_Domain, Node, _Id, {xmlelement, Name, Attrs, Subels}=Element, _Item)->
- case proplists:is_defined("xmlns",Attrs) of
- true -> Element;
- false -> {xmlelement, Name, [{"xmlns", Node}|Attrs], Subels}
- end.
-
-collection(Title, Link, Updated, _Id, Entries)->
- {xmlelement, "feed", [{"xmlns", "http://www.w3.org/2005/Atom"},
- {"xmlns:app", "http://www.w3.org/2007/app"}], [
- {xmlelement, "title", [],[{xmlcdata, Title}]},
- {xmlelement, "generator", [],[{xmlcdata, <<"ejabberd">>}]},
- {xmlelement, "updated", [],[{xmlcdata, w3cdtf(Updated)}]},
- {xmlelement, "link", [{"href", Link}, {"rel", "self"}], []},
- {xmlelement, "id", [], [{xmlcdata, list_to_binary(Link)}]},
- {xmlelement, "title", [],[{xmlcdata, Title}]} |
- Entries
- ]}.
-
-service(Args, Domain,Collections)->
- {xmlelement, "service", [{"xmlns", "http://www.w3.org/2007/app"},
- {"xmlns:atom", "http://www.w3.org/2005/Atom"},
- {"xmlns:app", "http://www.w3.org/2007/app"}],[
- {xmlelement, "workspace", [],[
- {xmlelement, "atom:title", [],[{xmlcdata,"Pubsub node Feed for " ++Domain}]} |
- lists:map(fun(#pubsub_node{nodeid={_Server, Id}, type=_Type})->
- {xmlelement, "collection", [{"href", collection_uri(Args,Domain, Id)}], [
- {xmlelement, "atom:title", [], [{xmlcdata, Id}]}
- ]}
- end, Collections)
- ]}
- ]}.
-
-%% simple output functions
-error({xmlelement, "error", Attrs, _}=Error) ->
- Value = list_to_integer(xml:get_attr_s("code", Attrs)),
- {Value, [{"Content-type", "application/xml"}], xml:element_to_string(Error)};
-error(404)->
- {404, [], "Not Found"};
-error(403)->
- {403, [], "Forbidden"};
-error(500)->
- {500, [], "Internal server error"};
-error(401)->
- {401, [{"WWW-Authenticate", "basic realm=\"ejabberd\""}],"Unauthorized"};
-error(Code)->
- {Code, [], ""}.
-success(200)->
- {200, [], ""};
-success(Code)->
- {Code, [], ""}.
-
-backend(Domain)->
- Modules = gen_mod:loaded_modules(Domain),
- case lists:member(mod_pubsub_odbc, Modules) of
- true -> mod_pubsub_odbc;
- _ -> mod_pubsub
- end.
-
-
-% Code below is taken (with some modifications) from the yaws webserver, which
-% is distributed under the folowing license:
-%
-% This software (the yaws webserver) is free software.
-% Parts of this software is Copyright (c) Claes Wikstrom <klacke@hyber.org>
-% Any use or misuse of the source code is hereby freely allowed.
-%
-% 1. Redistributions of source code must retain the above copyright
-% notice as well as this list of conditions.
-%
-% 2. Redistributions in binary form must reproduce the above copyright
-% notice as well as this list of conditions.
-%%% Create W3CDTF (http://www.w3.org/TR/NOTE-datetime) formatted date
-%%% w3cdtf(GregSecs) -> "YYYY-MM-DDThh:mm:ssTZD"
-%%%
-uniqid(false)->
- {T1, T2, T3} = now(),
- lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3]));
-uniqid(Slug) ->
- Slut = string:to_lower(Slug),
- S = string:substr(Slut, 1, 9),
- {_T1, T2, T3} = now(),
- lists:flatten(io_lib:fwrite("~s-~.16B~.16B", [S, T2, T3])).
-
-w3cdtf(Date) -> %1 Date = calendar:gregorian_seconds_to_datetime(GregSecs),
- {{Y, Mo, D},{H, Mi, S}} = Date,
- [UDate|_] = calendar:local_time_to_universal_time_dst(Date),
- {DiffD,{DiffH,DiffMi,_}}=calendar:time_difference(UDate,Date),
- w3cdtf_diff(Y, Mo, D, H, Mi, S, DiffD, DiffH, DiffMi).
-
-%%% w3cdtf's helper function
-w3cdtf_diff(Y, Mo, D, H, Mi, S, _DiffD, DiffH, DiffMi) when DiffH < 12, DiffH /= 0 ->
- i2l(Y) ++ "-" ++ add_zero(Mo) ++ "-" ++ add_zero(D) ++ "T" ++
- add_zero(H) ++ ":" ++ add_zero(Mi) ++ ":" ++
- add_zero(S) ++ "+" ++ add_zero(DiffH) ++ ":" ++ add_zero(DiffMi);
-
-w3cdtf_diff(Y, Mo, D, H, Mi, S, DiffD, DiffH, DiffMi) when DiffH > 12, DiffD == 0 ->
- i2l(Y) ++ "-" ++ add_zero(Mo) ++ "-" ++ add_zero(D) ++ "T" ++
- add_zero(H) ++ ":" ++ add_zero(Mi) ++ ":" ++
- add_zero(S) ++ "+" ++ add_zero(DiffH) ++ ":" ++
- add_zero(DiffMi);
-
-w3cdtf_diff(Y, Mo, D, H, Mi, S, DiffD, DiffH, DiffMi) when DiffH > 12, DiffD /= 0, DiffMi /= 0 ->
- i2l(Y) ++ "-" ++ add_zero(Mo) ++ "-" ++ add_zero(D) ++ "T" ++
- add_zero(H) ++ ":" ++ add_zero(Mi) ++ ":" ++
- add_zero(S) ++ "-" ++ add_zero(23-DiffH) ++
- ":" ++ add_zero(60-DiffMi);
-
-w3cdtf_diff(Y, Mo, D, H, Mi, S, DiffD, DiffH, DiffMi) when DiffH > 12, DiffD /= 0, DiffMi == 0 ->
- i2l(Y) ++ "-" ++ add_zero(Mo) ++ "-" ++ add_zero(D) ++ "T" ++
- add_zero(H) ++ ":" ++ add_zero(Mi) ++ ":" ++
- add_zero(S) ++ "-" ++ add_zero(24-DiffH) ++
- ":" ++ add_zero(DiffMi);
-
-w3cdtf_diff(Y, Mo, D, H, Mi, S, _DiffD, DiffH, _DiffMi) when DiffH == 0 ->
- i2l(Y) ++ "-" ++ add_zero(Mo) ++ "-" ++ add_zero(D) ++ "T" ++
- add_zero(H) ++ ":" ++ add_zero(Mi) ++ ":" ++
- add_zero(S) ++ "Z".
+item_to_entry(_Args, _Domain, Node, _Id,
+ #xmlel{name = Name, attrs = Attrs, children = Subels} =
+ Element,
+ _Item) ->
+ case proplists:is_defined(<<"xmlns">>, Attrs) of
+ true -> Element;
+ false ->
+ #xmlel{name = Name,
+ attrs = [{<<"xmlns">>, Node} | Attrs],
+ children = Subels}
+ end.
-add_zero(I) when is_integer(I) -> add_zero(i2l(I));
-add_zero([A]) -> [$0,A];
-add_zero(L) when is_list(L) -> L.
+collection(Title, Link, Updated, _Id, Entries) ->
+ #xmlel{name = <<"feed">>,
+ attrs =
+ [{<<"xmlns">>, <<"http://www.w3.org/2005/Atom">>},
+ {<<"xmlns:app">>, <<"http://www.w3.org/2007/app">>}],
+ children =
+ [#xmlel{name = <<"title">>, attrs = [],
+ children = [{xmlcdata, Title}]},
+ #xmlel{name = <<"generator">>, attrs = [],
+ children = [{xmlcdata, <<"ejabberd">>}]},
+ #xmlel{name = <<"updated">>, attrs = [],
+ children = [{xmlcdata, w3cdtf(Updated)}]},
+ #xmlel{name = <<"link">>,
+ attrs = [{<<"href">>, Link}, {<<"rel">>, <<"self">>}],
+ children = []},
+ #xmlel{name = <<"id">>, attrs = [],
+ children = [{xmlcdata, iolist_to_binary(Link)}]},
+ #xmlel{name = <<"title">>, attrs = [],
+ children = [{xmlcdata, Title}]}
+ | Entries]}.
+
+service(Args, Domain, Collections) ->
+ #xmlel{name = <<"service">>,
+ attrs =
+ [{<<"xmlns">>, <<"http://www.w3.org/2007/app">>},
+ {<<"xmlns:atom">>, <<"http://www.w3.org/2005/Atom">>},
+ {<<"xmlns:app">>, <<"http://www.w3.org/2007/app">>}],
+ children =
+ [#xmlel{name = <<"workspace">>, attrs = [],
+ children =
+ [#xmlel{name = <<"atom:title">>, attrs = [],
+ children =
+ [{xmlcdata,
+ <<"Pubsub node Feed for ",
+ Domain/binary>>}]}
+ | lists:map(fun (#pubsub_node{nodeid =
+ {_Server, Id},
+ type = _Type}) ->
+ #xmlel{name = <<"collection">>,
+ attrs =
+ [{<<"href">>,
+ collection_uri(Args,
+ Domain,
+ Id)}],
+ children =
+ [#xmlel{name =
+ <<"atom:title">>,
+ attrs = [],
+ children =
+ [{xmlcdata,
+ Id}]}]}
+ end,
+ Collections)]}]}.
+
+error(#xmlel{name = <<"error">>, attrs = Attrs} =
+ Error) ->
+ Value =
+ jlib:binary_to_integer(xml:get_attr_s(<<"code">>,
+ Attrs)),
+ {Value, [{<<"Content-type">>, <<"application/xml">>}],
+ xml:element_to_binary(Error)};
+error(404) -> {404, [], <<"Not Found">>};
+error(403) -> {403, [], <<"Forbidden">>};
+error(500) -> {500, [], <<"Internal server error">>};
+error(401) ->
+ {401,
+ [{<<"WWW-Authenticate">>,
+ <<"basic realm=\"ejabberd\"">>}],
+ <<"Unauthorized">>};
+error(Code) -> {Code, [], <<"">>}.
+
+success(200) -> {200, [], <<"">>};
+success(Code) -> {Code, [], <<"">>}.
+
+backend(Domain) ->
+ Modules = gen_mod:loaded_modules(Domain),
+ case lists:member(mod_pubsub_odbc, Modules) of
+ true -> mod_pubsub_odbc;
+ _ -> mod_pubsub
+ end.
+uniqid(false) ->
+ {T1, T2, T3} = now(),
+ list_to_binary(io_lib:fwrite("~.16B~.16B~.16B",
+ [T1, T2, T3])).
+w3cdtf(Date) -> %1 Date = calendar:gregorian_seconds_to_datetime(GregSecs),
+ {{Y, Mo, D}, {H, Mi, S}} = Date,
+ [UDate | _] =
+ calendar:local_time_to_universal_time_dst(Date),
+ {DiffD, {DiffH, DiffMi, _}} =
+ calendar:time_difference(UDate, Date),
+ w3cdtf_diff(Y, Mo, D, H, Mi, S, DiffD, DiffH, DiffMi).
+
+w3cdtf_diff(Y, Mo, D, H, Mi, S, _DiffD, DiffH, DiffMi)
+ when DiffH < 12, DiffH /= 0 ->
+ <<(i2l(Y))/binary, "-", (add_zero(Mo))/binary, "-",
+ (add_zero(D))/binary, "T", (add_zero(H))/binary, ":",
+ (add_zero(Mi))/binary, ":", (add_zero(S))/binary, "+",
+ (add_zero(DiffH))/binary, ":",
+ (add_zero(DiffMi))/binary>>;
+w3cdtf_diff(Y, Mo, D, H, Mi, S, DiffD, DiffH, DiffMi)
+ when DiffH > 12, DiffD == 0 ->
+ <<(i2l(Y))/binary, "-", (add_zero(Mo))/binary, "-",
+ (add_zero(D))/binary, "T", (add_zero(H))/binary, ":",
+ (add_zero(Mi))/binary, ":", (add_zero(S))/binary, "+",
+ (add_zero(DiffH))/binary, ":",
+ (add_zero(DiffMi))/binary>>;
+w3cdtf_diff(Y, Mo, D, H, Mi, S, DiffD, DiffH, DiffMi)
+ when DiffH > 12, DiffD /= 0, DiffMi /= 0 ->
+ <<(i2l(Y))/binary, "-", (add_zero(Mo))/binary, "-",
+ (add_zero(D))/binary, "T", (add_zero(H))/binary, ":",
+ (add_zero(Mi))/binary, ":", (add_zero(S))/binary, "-",
+ (add_zero(23 - DiffH))/binary, ":",
+ (add_zero(60 - DiffMi))/binary>>;
+w3cdtf_diff(Y, Mo, D, H, Mi, S, DiffD, DiffH, DiffMi)
+ when DiffH > 12, DiffD /= 0, DiffMi == 0 ->
+ <<(i2l(Y))/binary, "-", (add_zero(Mo))/binary, "-",
+ (add_zero(D))/binary, "T", (add_zero(H))/binary, ":",
+ (add_zero(Mi))/binary, ":", (add_zero(S))/binary, "-",
+ (add_zero(24 - DiffH))/binary, ":",
+ (add_zero(DiffMi))/binary>>;
+w3cdtf_diff(Y, Mo, D, H, Mi, S, _DiffD, DiffH, _DiffMi)
+ when DiffH == 0 ->
+ <<(i2l(Y))/binary, "-", (add_zero(Mo))/binary, "-",
+ (add_zero(D))/binary, "T", (add_zero(H))/binary, ":",
+ (add_zero(Mi))/binary, ":", (add_zero(S))/binary, "Z">>.
-i2l(I) when is_integer(I) -> integer_to_list(I);
-i2l(L) when is_list(L) -> L.
+add_zero(I) when is_integer(I) -> add_zero(i2l(I));
+add_zero(<<A>>) -> <<$0, A>>;
+add_zero(L) when is_binary(L) -> L.
-b2l(B) when is_binary(B) -> binary_to_list(B);
-b2l(L) when is_list(L) -> L.
+i2l(I) when is_integer(I) ->
+ jlib:integer_to_binary(I).
-get_tag_attr_or_default(AttrName, Element, Default)->
- case xml:get_tag_attr_s(AttrName, Element) of
- "" -> Default;
- Val -> Val
- end.
+get_tag_attr_or_default(AttrName, Element, Default) ->
+ case xml:get_tag_attr_s(AttrName, Element) of
+ <<"">> -> Default;
+ Val -> Val
+ end.