mirror of
https://github.com/processone/ejabberd.git
synced 2024-07-02 23:06:21 +02:00
Merge branch '2.1.x' of git+ssh://git@gitorious.process-one.net/ejabberd/mainline.git into 2.2.x
Conflicts: src/configure src/ejabberd.app src/ejabberd_receiver.erl src/tls/tls_drv.c src/web/ejabberd_http.erl
This commit is contained in:
commit
52df4fa024
|
@ -2,7 +2,7 @@
|
|||
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Ejabberd 2.1.10 Developers Guide
|
||||
<TITLE>Ejabberd 2.1.x 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.10 Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
|
||||
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.x 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,7 +2,7 @@
|
|||
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Ejabberd 2.1.10 Feature Sheet
|
||||
<TITLE>Ejabberd 2.1.x 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.10 Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
|
||||
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.x 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,7 +6,7 @@
|
|||
|
||||
|
||||
|
||||
ejabberd 2.1.10
|
||||
ejabberd 2.1.x
|
||||
|
||||
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.10 </B></FONT></TD></TR>
|
||||
<TABLE CELLSPACING=6 CELLPADDING=0><TR><TD ALIGN=right NOWRAP> <FONT SIZE=6><B>ejabberd 2.1.x </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>
|
||||
|
|
|
@ -829,7 +829,7 @@ The available modules, their purpose and the options allowed by each one are:
|
|||
Options: \texttt{certfile}
|
||||
\titem{\texttt{ejabberd\_http}}
|
||||
Handles incoming HTTP connections.\\
|
||||
Options: \texttt{captcha}, \texttt{certfile}, \texttt{http\_bind}, \texttt{http\_poll},
|
||||
Options: \texttt{captcha}, \texttt{certfile}, \texttt{default\_host}, \texttt{http\_bind}, \texttt{http\_poll},
|
||||
\texttt{request\_handlers}, \texttt{tls}, \texttt{trusted\_proxies}, \texttt{web\_admin}\\
|
||||
\end{description}
|
||||
|
||||
|
@ -850,6 +850,11 @@ This is a detailed description of each option allowed by the listening modules:
|
|||
Simple web page that allows a user to fill a CAPTCHA challenge (see section \ref{captcha}).
|
||||
\titem{\{certfile, Path\}} Full path to a file containing the default SSL certificate.
|
||||
To define a certificate file specific for a given domain, use the global option \term{domain\_certfile}.
|
||||
\titem{\{default\_host, undefined|HostName\}}
|
||||
If the HTTP request received by ejabberd contains the HTTP header \term{Host}
|
||||
with an ambiguous virtual host that doesn't match any one defined in ejabberd (see \ref{hostnames}),
|
||||
then this configured HostName is set as the request Host.
|
||||
The default value of this option is: \term{undefined}.
|
||||
\titem{\{hosts, [Hostname, ...], [HostOption, ...]\}} \ind{options!hosts}
|
||||
The external Jabber component that connects to this \term{ejabberd\_service}
|
||||
can serve one or more hostnames.
|
||||
|
@ -1667,7 +1672,7 @@ The configurable options are:
|
|||
\begin{description}
|
||||
\titem{\{captcha\_cmd, Path\}}
|
||||
Full path to a script that generates the image.
|
||||
The default value is an empty string: \term{""}
|
||||
The default value disables the feature: \term{undefined}
|
||||
\titem{\{captcha\_host, ProtocolHostPort\}}
|
||||
ProtocolHostPort is a string with the host, and optionally the Protocol and Port number.
|
||||
It must identify where ejabberd listens for CAPTCHA requests.
|
||||
|
@ -5882,6 +5887,7 @@ Thanks to all people who contributed to this guide:
|
|||
\item Badlop (\ahrefurl{xmpp:badlop@jabberes.org})
|
||||
\item Evgeniy Khramtsov (\ahrefurl{xmpp:xram@jabber.ru})
|
||||
\item Florian Zumbiehl (\ahrefurl{xmpp:florz@florz.de})
|
||||
\item Ludovic Bocquet (\ahrefurl{xmpp:lbocquet@jabber.org})
|
||||
\item Marcin Owsiany (\ahrefurl{xmpp:marcin.owsiany@gmail.com})
|
||||
\item Michael Grigutsch (\ahrefurl{xmpp:migri@jabber.i-pobox.net})
|
||||
\item Mickael Remond (\ahrefurl{xmpp:mremond@process-one.net})
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
% ejabberd version (automatically generated).
|
||||
\newcommand{\version}{2.1.10}
|
||||
\newcommand{\version}{2.1.x}
|
||||
|
|
|
@ -89,19 +89,19 @@ change_shaper(Pid, Shaper) ->
|
|||
gen_server:cast(Pid, {change_shaper, Shaper}).
|
||||
|
||||
reset_stream(Pid) ->
|
||||
gen_server:call(Pid, reset_stream).
|
||||
do_call(Pid, reset_stream).
|
||||
|
||||
starttls(Pid, TLSOpts) ->
|
||||
starttls(Pid, TLSOpts, undefined).
|
||||
|
||||
starttls(Pid, TLSOpts, Data) ->
|
||||
gen_server:call(Pid, {starttls, TLSOpts, Data}).
|
||||
do_call(Pid, {starttls, TLSOpts, Data}).
|
||||
|
||||
compress(Pid, Data) ->
|
||||
gen_server:call(Pid, {compress, Data}).
|
||||
do_call(Pid, {compress, Data}).
|
||||
|
||||
become_controller(Pid, C2SPid) ->
|
||||
gen_server:call(Pid, {become_controller, C2SPid}).
|
||||
do_call(Pid, {become_controller, C2SPid}).
|
||||
|
||||
change_controller(Pid, C2SPid) ->
|
||||
case catch gen_server:call(Pid, {change_controller, C2SPid}) of
|
||||
|
@ -448,3 +448,11 @@ cancel_timer(TRef) when is_reference(TRef) ->
|
|||
end;
|
||||
cancel_timer(_) ->
|
||||
ok.
|
||||
|
||||
do_call(Pid, Msg) ->
|
||||
case catch gen_server:call(Pid, Msg) of
|
||||
{'EXIT', Why} ->
|
||||
{error, Why};
|
||||
Res ->
|
||||
Res
|
||||
end.
|
||||
|
|
|
@ -101,6 +101,8 @@
|
|||
[{"code", Code}, {"type", Type}],
|
||||
[{xmlelement, Condition, [{"xmlns", ?NS_STANZAS}], []}]}).
|
||||
|
||||
-define(ERR_BAD_FORMAT,
|
||||
?STANZA_ERROR("406", "modify", "bad-format")).
|
||||
-define(ERR_BAD_REQUEST,
|
||||
?STANZA_ERROR("400", "modify", "bad-request")).
|
||||
-define(ERR_CONFLICT,
|
||||
|
@ -155,6 +157,8 @@
|
|||
{xmlelement, "text", [{"xmlns", ?NS_STANZAS}],
|
||||
[{xmlcdata, translate:translate(Lang, Text)}]}]}).
|
||||
|
||||
-define(ERRT_BAD_FORMAT(Lang, Text),
|
||||
?STANZA_ERRORT("406", "modify", "bad-format", Lang, Text)).
|
||||
-define(ERRT_BAD_REQUEST(Lang, Text),
|
||||
?STANZA_ERRORT("400", "modify", "bad-request", Lang, Text)).
|
||||
-define(ERRT_CONFLICT(Lang, Text),
|
||||
|
|
|
@ -39,6 +39,11 @@
|
|||
|
||||
-record(private_storage, {usns, xml}).
|
||||
|
||||
-define(Xmlel_Query(Attrs, Children),
|
||||
(
|
||||
{xmlelement, "query", Attrs, Children}
|
||||
)).
|
||||
|
||||
start(Host, Opts) ->
|
||||
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
|
||||
mnesia:create_table(private_storage,
|
||||
|
@ -56,73 +61,97 @@ stop(Host) ->
|
|||
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE).
|
||||
|
||||
|
||||
process_sm_iq(From, _To, #iq{type = Type, sub_el = SubEl} = IQ) ->
|
||||
#jid{luser = LUser, lserver = LServer} = From,
|
||||
case lists:member(LServer, ?MYHOSTS) of
|
||||
true ->
|
||||
{xmlelement, Name, Attrs, Els} = SubEl,
|
||||
case Type of
|
||||
set ->
|
||||
F = fun() ->
|
||||
lists:foreach(
|
||||
fun(El) ->
|
||||
set_data(LUser, LServer, El)
|
||||
end, Els)
|
||||
end,
|
||||
mnesia:transaction(F),
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, Name, Attrs, []}]};
|
||||
get ->
|
||||
case catch get_data(LUser, LServer, Els) of
|
||||
{'EXIT', _Reason} ->
|
||||
IQ#iq{type = error,
|
||||
sub_el = [SubEl,
|
||||
?ERR_INTERNAL_SERVER_ERROR]};
|
||||
Res ->
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, Name, Attrs, Res}]}
|
||||
end
|
||||
end;
|
||||
false ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
|
||||
process_sm_iq(#jid{luser = LUser, lserver = LServer},
|
||||
#jid{luser = LUser, lserver = LServer}, IQ)
|
||||
when IQ#iq.type == 'set' ->
|
||||
case IQ#iq.sub_el of
|
||||
{xmlelement, "query", _, Xmlels} ->
|
||||
case filter_xmlels(Xmlels) of
|
||||
[] ->
|
||||
IQ#iq{
|
||||
type = error,
|
||||
sub_el = [IQ#iq.sub_el, ?ERR_NOT_ACCEPTABLE]
|
||||
};
|
||||
Data ->
|
||||
mnesia:transaction(fun() ->
|
||||
lists:foreach(fun
|
||||
(Datum) ->
|
||||
set_data(LUser, LServer, Datum)
|
||||
end, Data)
|
||||
end),
|
||||
IQ#iq{type = result, sub_el = []}
|
||||
end;
|
||||
_ ->
|
||||
IQ#iq{type = error, sub_el = [IQ#iq.sub_el, ?ERR_NOT_ACCEPTABLE]}
|
||||
end;
|
||||
%%
|
||||
process_sm_iq(#jid{luser = LUser, lserver = LServer},
|
||||
#jid{luser = LUser, lserver = LServer}, IQ)
|
||||
when IQ#iq.type == 'get' ->
|
||||
case IQ#iq.sub_el of
|
||||
{xmlelement, "query", Attrs, Xmlels} ->
|
||||
case filter_xmlels(Xmlels) of
|
||||
[] ->
|
||||
IQ#iq{
|
||||
type = error,
|
||||
sub_el = [IQ#iq.sub_el, ?ERR_BAD_FORMAT]
|
||||
};
|
||||
Data ->
|
||||
case catch get_data(LUser, LServer, Data) of
|
||||
{'EXIT', _Reason} ->
|
||||
IQ#iq{
|
||||
type = error,
|
||||
sub_el = [IQ#iq.sub_el, ?ERR_INTERNAL_SERVER_ERROR]
|
||||
};
|
||||
Storage_Xmlels ->
|
||||
IQ#iq{
|
||||
type = result,
|
||||
sub_el = [?Xmlel_Query(Attrs, Storage_Xmlels)]
|
||||
}
|
||||
end
|
||||
end;
|
||||
_ ->
|
||||
IQ#iq{type = error, sub_el = [IQ#iq.sub_el, ?ERR_BAD_FORMAT]}
|
||||
end;
|
||||
%%
|
||||
process_sm_iq(_From, _To, IQ) ->
|
||||
IQ#iq{type = error, sub_el = [IQ#iq.sub_el, ?ERR_FORBIDDEN]}.
|
||||
|
||||
|
||||
filter_xmlels(Xmlels) ->
|
||||
filter_xmlels(Xmlels, []).
|
||||
|
||||
filter_xmlels([], Data) ->
|
||||
lists:reverse(Data);
|
||||
filter_xmlels([{xmlelement, _, Attrs, _} = Xmlel | Xmlels], Data) ->
|
||||
case xml:get_attr_s("xmlns", Attrs) of
|
||||
"" -> [];
|
||||
XmlNS -> filter_xmlels(Xmlels, [{XmlNS, Xmlel} | Data])
|
||||
end;
|
||||
filter_xmlels([_ | Xmlels], Data) ->
|
||||
filter_xmlels(Xmlels, Data).
|
||||
|
||||
|
||||
set_data(LUser, LServer, {XmlNS, Xmlel}) ->
|
||||
mnesia:write(#private_storage{
|
||||
usns = {LUser, LServer, XmlNS},
|
||||
xml = Xmlel
|
||||
}).
|
||||
|
||||
|
||||
get_data(LUser, LServer, Data) ->
|
||||
get_data(LUser, LServer, Data, []).
|
||||
|
||||
get_data(_LUser, _LServer, [], Storage_Xmlels) ->
|
||||
lists:reverse(Storage_Xmlels);
|
||||
get_data(LUser, LServer, [{XmlNS, Xmlel} | Data], Storage_Xmlels) ->
|
||||
case mnesia:dirty_read(private_storage, {LUser, LServer, XmlNS}) of
|
||||
[#private_storage{xml = Storage_Xmlel}] ->
|
||||
get_data(LUser, LServer, Data, [Storage_Xmlel | Storage_Xmlels]);
|
||||
_ ->
|
||||
get_data(LUser, LServer, Data, [Xmlel | Storage_Xmlels])
|
||||
end.
|
||||
|
||||
set_data(LUser, LServer, El) ->
|
||||
case El of
|
||||
{xmlelement, _Name, Attrs, _Els} ->
|
||||
XMLNS = xml:get_attr_s("xmlns", Attrs),
|
||||
case XMLNS of
|
||||
"" ->
|
||||
ignore;
|
||||
_ ->
|
||||
mnesia:write(
|
||||
#private_storage{usns = {LUser, LServer, XMLNS},
|
||||
xml = El})
|
||||
end;
|
||||
_ ->
|
||||
ignore
|
||||
end.
|
||||
|
||||
get_data(LUser, LServer, Els) ->
|
||||
get_data(LUser, LServer, Els, []).
|
||||
|
||||
get_data(_LUser, _LServer, [], Res) ->
|
||||
lists:reverse(Res);
|
||||
get_data(LUser, LServer, [El | Els], Res) ->
|
||||
case El of
|
||||
{xmlelement, _Name, Attrs, _} ->
|
||||
XMLNS = xml:get_attr_s("xmlns", Attrs),
|
||||
case mnesia:dirty_read(private_storage, {LUser, LServer, XMLNS}) of
|
||||
[R] ->
|
||||
get_data(LUser, LServer, Els,
|
||||
[R#private_storage.xml | Res]);
|
||||
[] ->
|
||||
get_data(LUser, LServer, Els,
|
||||
[El | Res])
|
||||
end;
|
||||
_ ->
|
||||
get_data(LUser, LServer, Els, Res)
|
||||
end.
|
||||
|
||||
remove_user(User, Server) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
|
|
|
@ -631,7 +631,7 @@ add_user_to_group(Host, US, Group) ->
|
|||
GroupOpts ++ MoreGroupOpts);
|
||||
nomatch ->
|
||||
%% Push this new user to members of groups where this group is displayed
|
||||
push_user_to_displayed(LUser, LServer, Group, both),
|
||||
push_user_to_displayed(LUser, LServer, Group, Host, both),
|
||||
%% Push members of groups that are displayed to this group
|
||||
push_displayed_to_user(LUser, LServer, Group, Host, both),
|
||||
R = #sr_user{us = US, group_host = {Group, Host}},
|
||||
|
@ -668,7 +668,7 @@ remove_user_from_group(Host, US, Group) ->
|
|||
end,
|
||||
Result = mnesia:transaction(F),
|
||||
%% Push removal of the old user to members of groups where the group that this user was members was displayed
|
||||
push_user_to_displayed(LUser, LServer, Group, remove),
|
||||
push_user_to_displayed(LUser, LServer, Group, Host, remove),
|
||||
%% Push removal of members of groups that where displayed to the group which this user has left
|
||||
push_displayed_to_user(LUser, LServer, Group, Host, remove),
|
||||
Result
|
||||
|
@ -689,7 +689,7 @@ register_user(User, Server) ->
|
|||
%% Get list of groups where this user is member
|
||||
Groups = get_user_groups({User, Server}),
|
||||
%% Push this user to members of groups where is displayed a group which this user is member
|
||||
[push_user_to_displayed(User, Server, Group, both) || Group <- Groups].
|
||||
[push_user_to_displayed(User, Server, Group, Server, both) || Group <- Groups].
|
||||
|
||||
remove_user(User, Server) ->
|
||||
push_user_to_members(User, Server, remove).
|
||||
|
@ -711,19 +711,19 @@ push_user_to_members(User, Server, Subscription) ->
|
|||
end, get_group_users(LServer, Group, GroupOpts))
|
||||
end, lists:usort(SpecialGroups++UserGroups)).
|
||||
|
||||
push_user_to_displayed(LUser, LServer, Group, Subscription) ->
|
||||
GroupsOpts = groups_with_opts(LServer),
|
||||
push_user_to_displayed(LUser, LServer, Group, Host, Subscription) ->
|
||||
GroupsOpts = groups_with_opts(Host),
|
||||
GroupOpts = proplists:get_value(Group, GroupsOpts, []),
|
||||
GroupName = proplists:get_value(name, GroupOpts, Group),
|
||||
DisplayedToGroupsOpts = displayed_to_groups(Group, LServer),
|
||||
[push_user_to_group(LUser, LServer, GroupD, GroupName, Subscription) || {GroupD, _Opts} <- DisplayedToGroupsOpts].
|
||||
DisplayedToGroupsOpts = displayed_to_groups(Group, Host),
|
||||
[push_user_to_group(LUser, LServer, GroupD, Host, GroupName, Subscription) || {GroupD, _Opts} <- DisplayedToGroupsOpts].
|
||||
|
||||
push_user_to_group(LUser, LServer, Group, GroupName, Subscription) ->
|
||||
push_user_to_group(LUser, LServer, Group, Host, GroupName, Subscription) ->
|
||||
lists:foreach(
|
||||
fun({U, S}) when (U == LUser) and (S == LServer) -> ok;
|
||||
fun({U, S}) when (U == LUser) and (S == LServer) -> ok;
|
||||
({U, S}) ->
|
||||
push_roster_item(U, S, LUser, LServer, GroupName, Subscription)
|
||||
end, get_group_users(LServer, Group)).
|
||||
end, get_group_users(Host, Group)).
|
||||
|
||||
%% Get list of groups to which this group is displayed
|
||||
displayed_to_groups(GroupName, LServer) ->
|
||||
|
@ -819,7 +819,7 @@ user_available(New) ->
|
|||
fun(OG) ->
|
||||
?DEBUG("user_available: pushing ~p @ ~p grp ~p",
|
||||
[LUser, LServer, OG ]),
|
||||
push_user_to_displayed(LUser, LServer, OG, both)
|
||||
push_user_to_displayed(LUser, LServer, OG, LServer, both)
|
||||
end, OnlineGroups);
|
||||
_ ->
|
||||
ok
|
||||
|
@ -840,7 +840,7 @@ unset_presence(LUser, LServer, Resource, Status) ->
|
|||
fun(OG) ->
|
||||
%% Push removal of the old user to members of groups
|
||||
%% where the group that this uwas members was displayed
|
||||
push_user_to_displayed(LUser, LServer, OG, remove),
|
||||
push_user_to_displayed(LUser, LServer, OG, LServer, remove),
|
||||
%% Push removal of members of groups that where
|
||||
%% displayed to the group which thiuser has left
|
||||
push_displayed_to_user(LUser, LServer, OG, LServer,remove)
|
||||
|
|
|
@ -219,17 +219,17 @@ set_vcard(User, LServer, VCARD) ->
|
|||
end,
|
||||
|
||||
LUser = jlib:nodeprep(User),
|
||||
LFN = string:to_lower(FN),
|
||||
LFamily = string:to_lower(Family),
|
||||
LGiven = string:to_lower(Given),
|
||||
LMiddle = string:to_lower(Middle),
|
||||
LNickname = string:to_lower(Nickname),
|
||||
LBDay = string:to_lower(BDay),
|
||||
LCTRY = string:to_lower(CTRY),
|
||||
LLocality = string:to_lower(Locality),
|
||||
LEMail = string:to_lower(EMail),
|
||||
LOrgName = string:to_lower(OrgName),
|
||||
LOrgUnit = string:to_lower(OrgUnit),
|
||||
LFN = string2lower(FN),
|
||||
LFamily = string2lower(Family),
|
||||
LGiven = string2lower(Given),
|
||||
LMiddle = string2lower(Middle),
|
||||
LNickname = string2lower(Nickname),
|
||||
LBDay = string2lower(BDay),
|
||||
LCTRY = string2lower(CTRY),
|
||||
LLocality = string2lower(Locality),
|
||||
LEMail = string2lower(EMail),
|
||||
LOrgName = string2lower(OrgName),
|
||||
LOrgUnit = string2lower(OrgUnit),
|
||||
|
||||
US = {LUser, LServer},
|
||||
|
||||
|
@ -271,6 +271,12 @@ set_vcard(User, LServer, VCARD) ->
|
|||
ejabberd_hooks:run(vcard_set, LServer, [LUser, LServer, VCARD])
|
||||
end.
|
||||
|
||||
string2lower(String) ->
|
||||
case stringprep:tolower(String) of
|
||||
Lower when is_list(Lower) -> Lower;
|
||||
error -> string:to_lower(String)
|
||||
end.
|
||||
|
||||
-define(TLFIELD(Type, Label, Var),
|
||||
{xmlelement, "field", [{"type", Type},
|
||||
{"label", translate:translate(Lang, Label)},
|
||||
|
@ -541,7 +547,7 @@ filter_fields([], Match, _LServer) ->
|
|||
Match;
|
||||
filter_fields([{SVar, [Val]} | Ds], Match, LServer)
|
||||
when is_list(Val) and (Val /= "") ->
|
||||
LVal = string:to_lower(Val),
|
||||
LVal = string2lower(Val),
|
||||
NewMatch = case SVar of
|
||||
"user" ->
|
||||
case gen_mod:get_module_opt(LServer, ?MODULE,
|
||||
|
@ -618,17 +624,17 @@ set_vcard_t(R, _) ->
|
|||
OrgUnit = xml:get_path_s(VCARD, [{elem, "ORG"}, {elem, "ORGUNIT"}, cdata]),
|
||||
|
||||
{LUser, _LServer} = US,
|
||||
LFN = string:to_lower(FN),
|
||||
LFamily = string:to_lower(Family),
|
||||
LGiven = string:to_lower(Given),
|
||||
LMiddle = string:to_lower(Middle),
|
||||
LNickname = string:to_lower(Nickname),
|
||||
LBDay = string:to_lower(BDay),
|
||||
LCTRY = string:to_lower(CTRY),
|
||||
LLocality = string:to_lower(Locality),
|
||||
LEMail = string:to_lower(EMail),
|
||||
LOrgName = string:to_lower(OrgName),
|
||||
LOrgUnit = string:to_lower(OrgUnit),
|
||||
LFN = string2lower(FN),
|
||||
LFamily = string2lower(Family),
|
||||
LGiven = string2lower(Given),
|
||||
LMiddle = string2lower(Middle),
|
||||
LNickname = string2lower(Nickname),
|
||||
LBDay = string2lower(BDay),
|
||||
LCTRY = string2lower(CTRY),
|
||||
LLocality = string2lower(Locality),
|
||||
LEMail = string2lower(EMail),
|
||||
LOrgName = string2lower(OrgName),
|
||||
LOrgUnit = string2lower(OrgUnit),
|
||||
|
||||
if
|
||||
(LUser == error) or
|
||||
|
|
|
@ -186,17 +186,17 @@ set_vcard(User, LServer, VCARD) ->
|
|||
end,
|
||||
|
||||
LUser = jlib:nodeprep(User),
|
||||
LFN = string:to_lower(FN),
|
||||
LFamily = string:to_lower(Family),
|
||||
LGiven = string:to_lower(Given),
|
||||
LMiddle = string:to_lower(Middle),
|
||||
LNickname = string:to_lower(Nickname),
|
||||
LBDay = string:to_lower(BDay),
|
||||
LCTRY = string:to_lower(CTRY),
|
||||
LLocality = string:to_lower(Locality),
|
||||
LEMail = string:to_lower(EMail),
|
||||
LOrgName = string:to_lower(OrgName),
|
||||
LOrgUnit = string:to_lower(OrgUnit),
|
||||
LFN = string2lower(FN),
|
||||
LFamily = string2lower(Family),
|
||||
LGiven = string2lower(Given),
|
||||
LMiddle = string2lower(Middle),
|
||||
LNickname = string2lower(Nickname),
|
||||
LBDay = string2lower(BDay),
|
||||
LCTRY = string2lower(CTRY),
|
||||
LLocality = string2lower(Locality),
|
||||
LEMail = string2lower(EMail),
|
||||
LOrgName = string2lower(OrgName),
|
||||
LOrgUnit = string2lower(OrgUnit),
|
||||
|
||||
if
|
||||
(LUser == error) or
|
||||
|
@ -252,6 +252,12 @@ set_vcard(User, LServer, VCARD) ->
|
|||
ejabberd_hooks:run(vcard_set, LServer, [LUser, LServer, VCARD])
|
||||
end.
|
||||
|
||||
string2lower(String) ->
|
||||
case stringprep:tolower(String) of
|
||||
Lower when is_list(Lower) -> Lower;
|
||||
error -> string:to_lower(String)
|
||||
end.
|
||||
|
||||
-define(TLFIELD(Type, Label, Var),
|
||||
{xmlelement, "field", [{"type", Type},
|
||||
{"label", translate:translate(Lang, Label)},
|
||||
|
@ -531,7 +537,7 @@ filter_fields([], Match, _LServer) ->
|
|||
end;
|
||||
filter_fields([{SVar, [Val]} | Ds], Match, LServer)
|
||||
when is_list(Val) and (Val /= "") ->
|
||||
LVal = string:to_lower(Val),
|
||||
LVal = string2lower(Val),
|
||||
NewMatch = case SVar of
|
||||
"user" -> make_val(Match, "lusername", LVal);
|
||||
"fn" -> make_val(Match, "lfn", LVal);
|
||||
|
|
|
@ -575,7 +575,7 @@ escape($\n) -> "\\n";
|
|||
escape($\t) -> "\\t";
|
||||
escape($\b) -> "\\b";
|
||||
escape($\r) -> "\\r";
|
||||
escape($') -> "\\'";
|
||||
escape($') -> "''";
|
||||
escape($") -> "\\\"";
|
||||
escape($\\) -> "\\\\";
|
||||
escape(C) -> C.
|
||||
|
|
|
@ -433,30 +433,37 @@ static ErlDrvSSizeT tls_drv_control(ErlDrvData handle,
|
|||
die_unless(SSL_get_error(d->ssl, res) == SSL_ERROR_WANT_READ,
|
||||
"SSL_do_handshake failed");
|
||||
}
|
||||
rlen = 1;
|
||||
b = driver_alloc_binary(rlen + BUF_SIZE);
|
||||
b->orig_bytes[0] = 0;
|
||||
if (SSL_is_init_finished(d->ssl)) {
|
||||
size = BUF_SIZE + 1;
|
||||
rlen = 1;
|
||||
b = driver_alloc_binary(size);
|
||||
b->orig_bytes[0] = 0;
|
||||
|
||||
while ((res = SSL_read(d->ssl,
|
||||
b->orig_bytes + rlen, BUF_SIZE)) > 0)
|
||||
{
|
||||
//printf("%d bytes of decrypted data read from state machine\r\n",res);
|
||||
rlen += res;
|
||||
b = driver_realloc_binary(b, rlen + BUF_SIZE);
|
||||
}
|
||||
while ((res = SSL_read(d->ssl,
|
||||
b->orig_bytes + rlen, BUF_SIZE)) > 0)
|
||||
{
|
||||
//printf("%d bytes of decrypted data read from state machine\r\n",res);
|
||||
rlen += res;
|
||||
size += BUF_SIZE;
|
||||
b = driver_realloc_binary(b, size);
|
||||
}
|
||||
|
||||
if (res < 0)
|
||||
{
|
||||
int err = SSL_get_error(d->ssl, res);
|
||||
if (res < 0)
|
||||
{
|
||||
int err = SSL_get_error(d->ssl, res);
|
||||
|
||||
if (err != SSL_ERROR_WANT_READ)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
b = driver_realloc_binary(b, rlen);
|
||||
*rbuf = (char *)b;
|
||||
return rlen;
|
||||
if (err == SSL_ERROR_WANT_READ)
|
||||
{
|
||||
//printf("SSL_read wants more data\r\n");
|
||||
//return 0;
|
||||
}
|
||||
// TODO
|
||||
}
|
||||
b = driver_realloc_binary(b, rlen);
|
||||
*rbuf = (char *)b;
|
||||
return rlen;
|
||||
}
|
||||
break;
|
||||
case GET_PEER_CERTIFICATE:
|
||||
cert = SSL_get_peer_certificate(d->ssl);
|
||||
if (cert == NULL)
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
request_tp,
|
||||
request_headers = [],
|
||||
end_of_request = false,
|
||||
default_host,
|
||||
trail = "",
|
||||
websocket_handlers = []
|
||||
}).
|
||||
|
@ -145,9 +146,11 @@ init({SockMod, Socket}, Opts) ->
|
|||
false -> []
|
||||
end,
|
||||
?DEBUG("WS: ~p~n", [WebSocketHandlers]),
|
||||
DefaultHost = gen_mod:get_opt(default_host, Opts, undefined),
|
||||
?INFO_MSG("started: ~p", [{SockMod1, Socket1}]),
|
||||
State = #state{sockmod = SockMod1,
|
||||
socket = Socket1,
|
||||
default_host = DefaultHost,
|
||||
request_handlers = RequestHandlers,
|
||||
websocket_handlers = WebSocketHandlers},
|
||||
receive_headers(State).
|
||||
|
@ -278,8 +281,9 @@ process_header(State, Data) ->
|
|||
[State#state.socket,
|
||||
State#state.request_method,
|
||||
element(2, State#state.request_path)]),
|
||||
{Host, Port, TP} = get_transfer_protocol(SockMod,
|
||||
{HostProvided, Port, TP} = get_transfer_protocol(SockMod,
|
||||
State#state.request_host),
|
||||
Host = get_host_really_served(State#state.default_host, HostProvided),
|
||||
State2 = State#state{request_host = Host,
|
||||
request_port = Port,
|
||||
request_tp = TP},
|
||||
|
@ -316,6 +320,15 @@ add_header(Name, Value, State) ->
|
|||
{value, {Param, V}} -> V;
|
||||
false -> undefined
|
||||
end).
|
||||
|
||||
get_host_really_served(undefined, Provided) ->
|
||||
Provided;
|
||||
get_host_really_served(Default, Provided) ->
|
||||
case lists:member(Provided, ?MYHOSTS) of
|
||||
true -> Provided;
|
||||
false -> Default
|
||||
end.
|
||||
|
||||
%% @spec (SockMod, HostPort) -> {Host::string(), Port::integer(), TP}
|
||||
%% where
|
||||
%% SockMod = gen_tcp | tls
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
%%%----------------------------------------------------------------------
|
||||
%%% File : ejabberd_http_bind.erl
|
||||
%%% Author : Stefan Strigler <steve@zeank.in-berlin.de>
|
||||
%%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as
|
||||
%%% Purpose : Implements XMPP over BOSH (XEP-0206) (formerly known as
|
||||
%%% HTTP Binding)
|
||||
%%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de>
|
||||
%%% Modified: may 2009 by Mickael Remond, Alexey Schepin
|
||||
|
|
Loading…
Reference in New Issue
Block a user