Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5feeacf875 | |||
| 90954cb248 | |||
| 8220db189f | |||
| 45db79b9a7 | |||
| 870edd13e5 | |||
| 6d811f5178 | |||
| 9ca775e199 | |||
| 0b96b745bf | |||
| e85f7566dd | |||
| bc8264b2ac | |||
| 371f1f200e | |||
| edbb30babd | |||
| cdb2ebe4bd |
+2
-2
@@ -2,7 +2,7 @@
|
||||
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Ejabberd 2.1.12 Developers Guide
|
||||
<TITLE>Ejabberd 2.1.13 Developers Guide
|
||||
</TITLE>
|
||||
|
||||
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
||||
@@ -49,7 +49,7 @@ TD P{margin:0px;}
|
||||
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic dev.tex -->
|
||||
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
|
||||
|
||||
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.12 Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
|
||||
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.13 Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
|
||||
<A HREF="mailto:alexey@sevcom.net"><TT>mailto:alexey@sevcom.net</TT></A><BR>
|
||||
<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT></A></H3></TD></TR>
|
||||
</TABLE><DIV CLASS="center">
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Ejabberd 2.1.12 Feature Sheet
|
||||
<TITLE>Ejabberd 2.1.13 Feature Sheet
|
||||
</TITLE>
|
||||
|
||||
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
||||
@@ -50,7 +50,7 @@ SPAN{width:20%; float:right; text-align:left; margin-left:auto;}
|
||||
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic features.tex -->
|
||||
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
|
||||
|
||||
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.12 Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
|
||||
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.13 Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
|
||||
<A HREF="mailto:s.devrieze@pandora.be"><TT>mailto:s.devrieze@pandora.be</TT></A><BR>
|
||||
<A HREF="xmpp:sander@devrieze.dyndns.org"><TT>xmpp:sander@devrieze.dyndns.org</TT></A></H3></TD></TR>
|
||||
</TABLE><DIV CLASS="center">
|
||||
|
||||
+6
-3
@@ -6,7 +6,7 @@
|
||||
|
||||
|
||||
|
||||
ejabberd 2.1.12
|
||||
ejabberd 2.1.13
|
||||
|
||||
Installation and Operation Guide
|
||||
|
||||
@@ -76,7 +76,7 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}
|
||||
<HR SIZE=2><BR>
|
||||
<BR>
|
||||
|
||||
<TABLE CELLSPACING=6 CELLPADDING=0><TR><TD ALIGN=right NOWRAP> <FONT SIZE=6><B>ejabberd 2.1.12 </B></FONT></TD></TR>
|
||||
<TABLE CELLSPACING=6 CELLPADDING=0><TR><TD ALIGN=right NOWRAP> <FONT SIZE=6><B>ejabberd 2.1.13 </B></FONT></TD></TR>
|
||||
<TR><TD ALIGN=right NOWRAP> </TD></TR>
|
||||
<TR><TD ALIGN=right NOWRAP> <FONT SIZE=6>Installation and Operation Guide</FONT></TD></TR>
|
||||
</TABLE><BR>
|
||||
@@ -688,7 +688,7 @@ Handles incoming s2s connections.<BR>
|
||||
Interacts with an <A HREF="http://www.ejabberd.im/tutorials-transports">external component</A>
|
||||
(as defined in the Jabber Component Protocol (<A HREF="http://xmpp.org/extensions/xep-0114.html">XEP-0114</A>).<BR>
|
||||
Options: <TT>access</TT>, <TT>hosts</TT>, <TT>max_fsm_queue</TT>,
|
||||
<TT>service_check_from</TT>, <TT>shaper</TT>
|
||||
<TT>service_check_from</TT>, <TT>shaper_rule</TT>
|
||||
</DD><DT CLASS="dt-description"><B><TT>ejabberd_stun</TT></B></DT><DD CLASS="dd-description">
|
||||
Handles STUN Binding requests as defined in
|
||||
<A HREF="http://tools.ietf.org/html/rfc5389">RFC 5389</A>.<BR>
|
||||
@@ -792,6 +792,9 @@ The default value is <TT>true</TT>, to be compliant with <A HREF="http://xmpp.or
|
||||
</DD><DT CLASS="dt-description"><B><TT>{shaper, none|ShaperName}</TT></B></DT><DD CLASS="dd-description"> This option defines a
|
||||
shaper for the port (see section <A HREF="#shapers">3.1.6</A>). The default value
|
||||
is <TT>none</TT>.
|
||||
</DD><DT CLASS="dt-description"><B><TT>{shaper_rule, none|ShaperRule}</TT></B></DT><DD CLASS="dd-description"> This option defines a
|
||||
shaper rule for the <TT>ejabberd_service</TT> (see section <A HREF="#shapers">3.1.6</A>). The recommended value
|
||||
is <TT>fast</TT>.
|
||||
</DD><DT CLASS="dt-description"><B><TT>starttls</TT></B></DT><DD CLASS="dd-description"> This option
|
||||
specifies that STARTTLS encryption is available on connections to the port.
|
||||
You should also set the <TT>certfile</TT> option.
|
||||
|
||||
+4
-1
@@ -818,7 +818,7 @@ The available modules, their purpose and the options allowed by each one are:
|
||||
Interacts with an \footahref{http://www.ejabberd.im/tutorials-transports}{external component}
|
||||
(as defined in the Jabber Component Protocol (\xepref{0114}).\\
|
||||
Options: \texttt{access}, \texttt{hosts}, \texttt{max\_fsm\_queue},
|
||||
\texttt{service\_check\_from}, \texttt{shaper}
|
||||
\texttt{service\_check\_from}, \texttt{shaper\_rule}
|
||||
\titem{\texttt{ejabberd\_stun}}
|
||||
Handles STUN Binding requests as defined in
|
||||
\footahref{http://tools.ietf.org/html/rfc5389}{RFC 5389}.\\
|
||||
@@ -934,6 +934,9 @@ This is a detailed description of each option allowed by the listening modules:
|
||||
\titem{\{shaper, none|ShaperName\}} \ind{options!shaper}This option defines a
|
||||
shaper for the port (see section~\ref{shapers}). The default value
|
||||
is \term{none}.
|
||||
\titem{\{shaper\_rule, none|ShaperRule\}} \ind{options!shaperrule}This option defines a
|
||||
shaper rule for the \term{ejabberd\_service} (see section~\ref{shapers}). The recommended value
|
||||
is \term{fast}.
|
||||
\titem{starttls} \ind{options!starttls}\ind{STARTTLS}This option
|
||||
specifies that STARTTLS encryption is available on connections to the port.
|
||||
You should also set the \option{certfile} option.
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
Release Notes
|
||||
ejabberd 2.1.12
|
||||
|
||||
ejabberd 2.1.13 includes just a few bugfixes.
|
||||
|
||||
Read more details about the changes in:
|
||||
http://redir.process-one.net/ejabberd-2.1.13
|
||||
|
||||
Download the source code and installers from:
|
||||
http://www.process-one.net/en/ejabberd/
|
||||
|
||||
|
||||
The changes are:
|
||||
|
||||
- Compilation: Detect correctly newer Darwin versions (EJAB-1594)
|
||||
- Guide: ejabberd_service expects a shaper_rule, not a shaper
|
||||
- MUC: Handle multiple < and > in mod_muc_log plaintext mode (EJAB-1640)
|
||||
- MUC: Handle ~ control sequence in text of mod_muc_log (EJAB-1639)
|
||||
- MUC: list_to_integer/2 only works in OTP R14 and newer
|
||||
- Pubsub: access_createnode acl also applies to auto created nodes
|
||||
- Web: Normalize HTTP path
|
||||
- WebAdmin: Fix bug when displaying offline messages in WebAdmin
|
||||
|
||||
|
||||
Bug reports
|
||||
|
||||
You can officially report bugs on ProcessOne support site:
|
||||
http://support.process-one.net/
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
% ejabberd version (automatically generated).
|
||||
\newcommand{\version}{2.1.12}
|
||||
\newcommand{\version}{2.1.13}
|
||||
|
||||
Vendored
+2
-2
@@ -4984,8 +4984,8 @@ test -n "$target_alias" &&
|
||||
|
||||
|
||||
case "$target_os" in
|
||||
*darwin10*)
|
||||
echo "Target OS is 'Darwin10'"
|
||||
*darwin*)
|
||||
echo "Target OS is 'Darwin'"
|
||||
ac_ext=erl
|
||||
ac_compile='$ERLC $ERLCFLAGS -b beam conftest.$ac_ext >&5'
|
||||
ac_link='$ERLC $ERLCFLAGS -b beam conftest.$ac_ext >&5 && echo "#!/bin/sh" > conftest$ac_exeext && $as_echo "\"$ERL\" -run conftest start -run init stop -noshell" >> conftest$ac_exeext && chmod +x conftest$ac_exeext'
|
||||
|
||||
+2
-2
@@ -157,8 +157,8 @@ AC_CANONICAL_SYSTEM
|
||||
|
||||
|
||||
case "$target_os" in
|
||||
*darwin10*)
|
||||
echo "Target OS is 'Darwin10'"
|
||||
*darwin*)
|
||||
echo "Target OS is 'Darwin'"
|
||||
AC_LANG(Erlang)
|
||||
AC_RUN_IFELSE(
|
||||
[AC_LANG_PROGRAM([],[dnl
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
{application, ejabberd,
|
||||
[{description, "ejabberd"},
|
||||
{vsn, "2.1.12"},
|
||||
{vsn, "2.1.13"},
|
||||
{modules, [acl,
|
||||
adhoc,
|
||||
configure,
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
-define(PROCNAME, ejabberd_mod_muc_log).
|
||||
-record(room, {jid, title, subject, subject_author, config}).
|
||||
|
||||
-define(PLAINTEXT_CO, "ZZCZZ").
|
||||
-define(PLAINTEXT_IN, "ZZIZZ").
|
||||
-define(PLAINTEXT_OUT, "ZZOZZ").
|
||||
|
||||
@@ -321,9 +322,15 @@ htmlize_nick(Nick1, html) ->
|
||||
htmlize_nick(Nick1, plaintext) ->
|
||||
htmlize(?PLAINTEXT_IN++Nick1++?PLAINTEXT_OUT, plaintext).
|
||||
|
||||
%% list_to_integer/2 was introduced in OTP R14
|
||||
-ifdef(SSL40).
|
||||
set_filemode(Fn, {FileMode, FileGroup}) ->
|
||||
ok = file:change_mode(Fn, list_to_integer(integer_to_list(FileMode), 8)),
|
||||
ok = file:change_group(Fn, FileGroup).
|
||||
-else.
|
||||
set_filemode(Fn, {_FileMode, FileGroup}) ->
|
||||
ok = file:change_group(Fn, FileGroup).
|
||||
-endif.
|
||||
|
||||
add_message_to_log(Nick1, Message, RoomJID, Opts, State) ->
|
||||
#logstate{out_dir = OutDir,
|
||||
@@ -455,7 +462,7 @@ add_message_to_log(Nick1, Message, RoomJID, Opts, State) ->
|
||||
STimeUnique = io_lib:format("~s.~w", [STime, Microsecs]),
|
||||
|
||||
%% Write message
|
||||
fw(F, io_lib:format("<a id=\"~s\" name=\"~s\" href=\"#~s\" class=\"ts\">[~s]</a> ",
|
||||
catch fw(F, io_lib:format("<a id=\"~s\" name=\"~s\" href=\"#~s\" class=\"ts\">[~s]</a> ",
|
||||
[STimeUnique, STimeUnique, STimeUnique, STime]) ++ Text, FileFormat),
|
||||
|
||||
%% Close file
|
||||
@@ -680,7 +687,8 @@ fw(F, S, O, FileFormat) ->
|
||||
html ->
|
||||
S1;
|
||||
plaintext ->
|
||||
S1x = ejabberd_regexp:greplace(S1, "<[^<^>]*>", ""),
|
||||
S1a = ejabberd_regexp:greplace(S1, "<[^<^>]*>", ""),
|
||||
S1x = ejabberd_regexp:greplace(S1a, ?PLAINTEXT_CO, "~~"),
|
||||
S1y = ejabberd_regexp:greplace(S1x, ?PLAINTEXT_IN, "<"),
|
||||
ejabberd_regexp:greplace(S1y, ?PLAINTEXT_OUT, ">")
|
||||
end,
|
||||
@@ -787,15 +795,16 @@ htmlize(S1) ->
|
||||
htmlize(S1, html).
|
||||
|
||||
htmlize(S1, plaintext) ->
|
||||
S1;
|
||||
ejabberd_regexp:greplace(S1, "~", ?PLAINTEXT_CO);
|
||||
htmlize(S1, FileFormat) ->
|
||||
htmlize(S1, false, FileFormat).
|
||||
|
||||
%% The NoFollow parameter tell if the spam prevention should be applied to the link found
|
||||
%% true means 'apply nofollow on links'.
|
||||
htmlize(S1, _NoFollow, plaintext) ->
|
||||
S1x = ejabberd_regexp:replace(S1, "<", ?PLAINTEXT_IN),
|
||||
ejabberd_regexp:replace(S1x, ">", ?PLAINTEXT_OUT);
|
||||
htmlize(S0, _NoFollow, plaintext) ->
|
||||
S1 = ejabberd_regexp:greplace(S0, "~", ?PLAINTEXT_CO),
|
||||
S1x = ejabberd_regexp:greplace(S1, "<", ?PLAINTEXT_IN),
|
||||
ejabberd_regexp:greplace(S1x, ">", ?PLAINTEXT_OUT);
|
||||
htmlize(S1, NoFollow, _FileFormat) ->
|
||||
S2_list = string:tokens(S1, "\n"),
|
||||
lists:foldl(
|
||||
|
||||
+1
-1
@@ -833,7 +833,7 @@ get_queue_length(LUser, LServer, odbc) ->
|
||||
get_messages_subset(User, Host, MsgsAll, DBType) ->
|
||||
Access = gen_mod:get_module_opt(Host, ?MODULE, access_max_user_messages,
|
||||
max_user_offline_messages),
|
||||
MaxOfflineMsgs = case get_max_user_messages(Access, User, Host) of
|
||||
MaxOfflineMsgs = case get_max_user_messages(Access, {User, Host}, Host) of
|
||||
Number when is_integer(Number) -> Number;
|
||||
_ -> 100
|
||||
end,
|
||||
|
||||
@@ -1248,7 +1248,7 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) ->
|
||||
case xml:remove_cdata(Els) of
|
||||
[{xmlelement, "item", ItemAttrs, Payload}] ->
|
||||
ItemId = xml:get_attr_s("id", ItemAttrs),
|
||||
publish_item(Host, ServerHost, Node, From, ItemId, Payload);
|
||||
publish_item(Host, ServerHost, Node, From, ItemId, Payload, Access);
|
||||
[] ->
|
||||
%% Publisher attempts to publish to persistent node with no item
|
||||
{error, extended_error(?ERR_BAD_REQUEST,
|
||||
@@ -2030,8 +2030,10 @@ unsubscribe_node(Host, Node, From, Subscriber, SubId) ->
|
||||
%%</ul>
|
||||
publish_item(Host, ServerHost, Node, Publisher, "", Payload) ->
|
||||
%% if publisher does not specify an ItemId, the service MUST generate the ItemId
|
||||
publish_item(Host, ServerHost, Node, Publisher, uniqid(), Payload);
|
||||
publish_item(Host, ServerHost, Node, Publisher, uniqid(), Payload, all);
|
||||
publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
|
||||
publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload, all).
|
||||
publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload, Access) ->
|
||||
Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) ->
|
||||
Features = features(Type),
|
||||
PublishFeature = lists:member("publish", Features),
|
||||
@@ -2122,7 +2124,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
|
||||
Type = select_type(ServerHost, Host, Node),
|
||||
case lists:member("auto-create", features(Type)) of
|
||||
true ->
|
||||
case create_node(Host, ServerHost, Node, Publisher, Type) of
|
||||
case create_node(Host, ServerHost, Node, Publisher, Type, Access, []) of
|
||||
{result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
|
||||
[{xmlelement, "create", [{"node", NewNode}], []}]}]} ->
|
||||
publish_item(Host, ServerHost, list_to_binary(NewNode),
|
||||
@@ -2621,13 +2623,15 @@ get_options_helper(JID, Lang, Node, NodeID, SubID, Type) ->
|
||||
|
||||
read_sub(Subscriber, Node, NodeID, SubID, Lang) ->
|
||||
case pubsub_subscription:get_subscription(Subscriber, NodeID, SubID) of
|
||||
{error, notfound} ->
|
||||
{error, extended_error(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
|
||||
{result, #pubsub_subscription{options = Options}} ->
|
||||
{result, XdataEl} = pubsub_subscription:get_options_xform(Lang, Options),
|
||||
OptionsEl = {xmlelement, "options", [{"jid", jlib:jid_to_string(Subscriber)},
|
||||
{"subid", SubID}|nodeAttr(Node)],
|
||||
[XdataEl]},
|
||||
{"subid", SubID}|nodeAttr(Node)],
|
||||
[XdataEl]},
|
||||
PubsubEl = {xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], [OptionsEl]},
|
||||
{result, PubsubEl};
|
||||
_ -> OptionsEl = {xmlelement, "options", [{"jid", jlib:jid_to_string(Subscriber)},
|
||||
{"subid", SubID}|nodeAttr(Node)]},
|
||||
PubsubEl = {xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], [OptionsEl]},
|
||||
{result, PubsubEl}
|
||||
end.
|
||||
@@ -2678,12 +2682,14 @@ set_options_helper(Configuration, JID, NodeID, SubID, Type) ->
|
||||
|
||||
write_sub(_Subscriber, _NodeID, _SubID, invalid) ->
|
||||
{error, extended_error(?ERR_BAD_REQUEST, "invalid-options")};
|
||||
write_sub(_Subscriber, _NodeID, _SubID, []) ->
|
||||
{result, []};
|
||||
write_sub(Subscriber, NodeID, SubID, Options) ->
|
||||
case pubsub_subscription:set_subscription(Subscriber, NodeID, SubID, Options) of
|
||||
{error, notfound} ->
|
||||
{error, extended_error(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
|
||||
{result, _} ->
|
||||
{result, []}
|
||||
{result, []};
|
||||
{error, _} ->
|
||||
{error, extended_error('not-acceptable', "invalid-subid")}
|
||||
end.
|
||||
|
||||
%% @spec (Host, Node, JID, Plugins) -> {error, Reason} | {result, Response}
|
||||
|
||||
@@ -97,9 +97,11 @@ init(_Host, _ServerHost, _Options) ->
|
||||
pubsub_subscription:init(),
|
||||
mnesia:create_table(pubsub_state,
|
||||
[{disc_copies, [node()]},
|
||||
{index, [nodeidx]},
|
||||
{attributes, record_info(fields, pubsub_state)}]),
|
||||
mnesia:create_table(pubsub_item,
|
||||
[{disc_only_copies, [node()]},
|
||||
{index, [nodeidx]},
|
||||
{attributes, record_info(fields, pubsub_item)}]),
|
||||
ItemsFields = record_info(fields, pubsub_item),
|
||||
case mnesia:table_info(pubsub_item, attributes) of
|
||||
@@ -224,7 +226,7 @@ create_node_permission(Host, ServerHost, NodeId, _ParentNodeId, Owner, Access) -
|
||||
%% @doc <p></p>
|
||||
create_node(NodeIdx, Owner) ->
|
||||
OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
|
||||
set_state(#pubsub_state{stateid = {OwnerKey, NodeIdx}, affiliation = owner}),
|
||||
set_state(#pubsub_state{stateid = {OwnerKey, NodeIdx}, nodeidx = NodeIdx, affiliation = owner}),
|
||||
{result, {default, broadcast}}.
|
||||
|
||||
%% @spec (Nodes) -> {result, {default, broadcast, Reply}}
|
||||
@@ -507,6 +509,7 @@ publish_item(NodeIdx, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
|
||||
payload = Payload};
|
||||
_ ->
|
||||
#pubsub_item{itemid = {ItemId, NodeIdx},
|
||||
nodeidx = NodeIdx,
|
||||
creation = {Now, GenKey},
|
||||
modification = PubId,
|
||||
payload = Payload}
|
||||
@@ -860,8 +863,8 @@ get_nodes_helper(NodeTree,
|
||||
%% ```get_states(NodeIdx) ->
|
||||
%% node_default:get_states(NodeIdx).'''</p>
|
||||
get_states(NodeIdx) ->
|
||||
States = case catch mnesia:match_object(
|
||||
#pubsub_state{stateid = {'_', NodeIdx}, _ = '_'}) of
|
||||
States = case catch mnesia:index_read(
|
||||
pubsub_state, NodeIdx, #pubsub_state.nodeidx) of
|
||||
List when is_list(List) -> List;
|
||||
_ -> []
|
||||
end,
|
||||
@@ -875,8 +878,8 @@ get_states(NodeIdx) ->
|
||||
get_state(NodeIdx, JID) ->
|
||||
StateId = {JID, NodeIdx},
|
||||
case catch mnesia:read({pubsub_state, StateId}) of
|
||||
[State] when is_record(State, pubsub_state) -> State;
|
||||
_ -> #pubsub_state{stateid=StateId}
|
||||
[#pubsub_state{} = State] -> State;
|
||||
_ -> #pubsub_state{stateid=StateId, nodeidx=NodeIdx}
|
||||
end.
|
||||
|
||||
%% @spec (State) -> ok | {error, Reason}
|
||||
@@ -911,7 +914,7 @@ del_state(NodeIdx, JID) ->
|
||||
%% ```get_items(NodeIdx, From) ->
|
||||
%% node_default:get_items(NodeIdx, From).'''</p>
|
||||
get_items(NodeIdx, _From) ->
|
||||
Items = mnesia:match_object(#pubsub_item{itemid = {'_', NodeIdx}, _ = '_'}),
|
||||
Items = mnesia:index_read(pubsub_item, NodeIdx, #pubsub_item.nodeidx),
|
||||
{result, lists:reverse(lists:keysort(#pubsub_item.modification, Items))}.
|
||||
|
||||
get_items(NodeIdx, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
|
||||
|
||||
@@ -136,8 +136,9 @@
|
||||
options = []
|
||||
}).
|
||||
|
||||
%% @type pubsubState() = {pubsub_state, StateId, Items, Affiliation, Subscriptions}
|
||||
%% @type pubsubState() = {pubsub_state, StateId, NodeIdx, Items, Affiliation, Subscriptions}
|
||||
%% StateId = {ljid(), nodeIdx()}
|
||||
%% NodeIdx = nodeIdx(),
|
||||
%% Items = [itemId()]
|
||||
%% Affiliation = affiliation()
|
||||
%% Subscriptions = [{subscription(), subId()}].
|
||||
@@ -146,6 +147,7 @@
|
||||
-record(pubsub_state,
|
||||
{
|
||||
stateid,
|
||||
nodeidx,
|
||||
items = [],
|
||||
affiliation = 'none',
|
||||
subscriptions = []
|
||||
@@ -161,6 +163,7 @@
|
||||
-record(pubsub_item,
|
||||
{
|
||||
itemid,
|
||||
nodeidx,
|
||||
creation = {'unknown','unknown'},
|
||||
modification = {'unknown','unknown'},
|
||||
payload = []
|
||||
|
||||
@@ -160,6 +160,8 @@ create_table() ->
|
||||
Other -> Other
|
||||
end.
|
||||
|
||||
add_subscription(_JID, _NodeID, []) ->
|
||||
make_subid();
|
||||
add_subscription(_JID, _NodeID, Options) ->
|
||||
SubID = make_subid(),
|
||||
mnesia:write(#pubsub_subscription{subid = SubID, options = Options}),
|
||||
@@ -174,11 +176,8 @@ read_subscription(_JID, _NodeID, SubID) ->
|
||||
_ -> {error, notfound}
|
||||
end.
|
||||
|
||||
write_subscription(JID, NodeID, SubID, Options) ->
|
||||
case read_subscription(JID, NodeID, SubID) of
|
||||
{error, notfound} -> {error, notfound};
|
||||
Sub -> mnesia:write(Sub#pubsub_subscription{options = Options})
|
||||
end.
|
||||
write_subscription(_JID, _NodeID, SubID, Options) ->
|
||||
mnesia:write(#pubsub_subscription{subid = SubID, options = Options}).
|
||||
|
||||
make_subid() ->
|
||||
{T1, T2, T3} = now(),
|
||||
|
||||
@@ -372,7 +372,7 @@ process_request(#state{request_method = Method,
|
||||
{'EXIT', _} ->
|
||||
make_bad_request(State);
|
||||
{NPath, Query} ->
|
||||
LPath = [path_decode(NPE) || NPE <- string:tokens(NPath, "/")],
|
||||
LPath = normalize_path([NPE || NPE <- string:tokens(path_decode(NPath), "/")]),
|
||||
LQuery = case (catch parse_urlencoded(Query)) of
|
||||
{'EXIT', _Reason} ->
|
||||
[];
|
||||
@@ -449,7 +449,7 @@ process_request(#state{request_method = Method,
|
||||
{'EXIT', _} ->
|
||||
make_bad_request(State);
|
||||
{NPath, _Query} ->
|
||||
LPath = [path_decode(NPE) || NPE <- string:tokens(NPath, "/")],
|
||||
LPath = normalize_path([NPE || NPE <- string:tokens(path_decode(NPath), "/")]),
|
||||
LQuery = case (catch parse_urlencoded(Data)) of
|
||||
{'EXIT', _Reason} ->
|
||||
[];
|
||||
@@ -1125,3 +1125,14 @@ drop_spaces(YS=[X|XS]) ->
|
||||
false ->
|
||||
YS
|
||||
end.
|
||||
|
||||
normalize_path(Path) ->
|
||||
normalize_path(Path, []).
|
||||
|
||||
normalize_path([], Norm) -> lists:reverse(Norm);
|
||||
normalize_path([".."|Path], Norm) ->
|
||||
normalize_path(Path, Norm);
|
||||
normalize_path([_Parent, ".."|Path], Norm) ->
|
||||
normalize_path(Path, Norm);
|
||||
normalize_path([Part | Path], Norm) ->
|
||||
normalize_path(Path, [Part|Norm]).
|
||||
|
||||
@@ -303,7 +303,7 @@ process(LocalPath, Request) ->
|
||||
add_to_log(FileSize, Code, Request),
|
||||
{Code, Headers, Contents}
|
||||
catch
|
||||
exit:{noproc, _} ->
|
||||
exit:{noproc, _} ->
|
||||
?ERROR_MSG("Received an HTTP request with Host ~p, but couldn't find the related "
|
||||
"ejabberd virtual host", [Request#request.host]),
|
||||
ejabberd_web:error(not_found)
|
||||
@@ -313,6 +313,7 @@ serve(LocalPath, DocRoot, DirectoryIndices, CustomHeaders, DefaultContentType, C
|
||||
FileName = filename:join(filename:split(DocRoot) ++ LocalPath),
|
||||
case file:read_file_info(FileName) of
|
||||
{error, enoent} -> ?HTTP_ERR_FILE_NOT_FOUND;
|
||||
{error, enotdir} -> ?HTTP_ERR_FILE_NOT_FOUND;
|
||||
{error, eacces} -> ?HTTP_ERR_FORBIDDEN;
|
||||
{ok, #file_info{type = directory}} -> serve_index(FileName,
|
||||
DirectoryIndices,
|
||||
|
||||
Reference in New Issue
Block a user