From 72e3e0e6add45753a166d9c2a995c1e23d8bf373 Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Fri, 8 Jul 2011 18:17:05 +0300 Subject: [PATCH] Ported flash clients patch from 2.1.x --- doc/guide.tex | 3 ++ src/Makefile.in | 7 +++- src/configure.ac | 9 +++++ src/ejabberd.hrl | 7 ++++ src/ejabberd_c2s.erl | 87 ++++++++++++++++++++++++++++++++++++++------ 5 files changed, 101 insertions(+), 12 deletions(-) diff --git a/doc/guide.tex b/doc/guide.tex index 5b999b15b..c72b305ad 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -393,6 +393,9 @@ Some options that you may be interested in modifying: \titem{--disable-transient-supervisors} Disable the use of Erlang/OTP supervision for transient processes. + + \titem{--enable-flash-hack} + Enable support for non-standard XML socket clients of Adobe Flash 8 and lower. \end{description} \makesubsection{install}{Install} diff --git a/src/Makefile.in b/src/Makefile.in index f11360a64..83668c0f1 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -64,6 +64,11 @@ ifeq (@pam@, pam) INSTALL_EPAM=install -m 750 $(O_USER) epam $(PBINDIR) endif +ifeq (@flash_hack@, true) + ERLC_FLAGS+=-DENABLE_FLASH_HACK + CPPFLAGS+=-DENABLE_FLASH_HACK +endif + prefix = @prefix@ exec_prefix = @exec_prefix@ @@ -158,7 +163,7 @@ mostlyclean-recursive maintainer-clean-recursive: @ERLC@ -W $(EFLAGS) $*.erl $(ERLSHLIBS): %.so: %.c - $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) \ + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(LIBS) \ $(subst ../,,$(subst .so,.c,$@)) \ $(ERLANG_LIBS) \ $(ERLANG_CFLAGS) \ diff --git a/src/configure.ac b/src/configure.ac index 5aa34de24..a902c3aab 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -62,6 +62,15 @@ AC_ARG_ENABLE(roster_gateway_workaround, esac],[roster_gateway_workaround=false]) AC_SUBST(roster_gateway_workaround) +AC_ARG_ENABLE(flash_hack, +[AC_HELP_STRING([--enable-flash-hack], [support Adobe Flash client XML (default: no)])], +[case "${enableval}" in + yes) flash_hack=true ;; + no) flash_hack=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-flash-hack) ;; +esac],[flash_hack=false]) +AC_SUBST(flash_hack) + AC_ARG_ENABLE(mssql, [AC_HELP_STRING([--enable-mssql], [use Microsoft SQL Server database (default: no, requires --enable-odbc)])], [case "${enableval}" in diff --git a/src/ejabberd.hrl b/src/ejabberd.hrl index d77769a99..8c07db530 100644 --- a/src/ejabberd.hrl +++ b/src/ejabberd.hrl @@ -32,6 +32,13 @@ -define(CONFIG_PATH, "ejabberd.cfg"). -define(LOG_PATH, "ejabberd.log"). +-ifdef(ENABLE_FLASH_HACK). +-define(FLASH_HACK, true). +-else. +-define(FLASH_HACK, false). +-endif. + + -define(EJABBERD_URI, "http://www.process-one.net/en/ejabberd/"). -define(S2STIMEOUT, 600000). diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index c84b95279..73e883173 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -114,7 +114,8 @@ ip, aux_fields = [], fsm_limit_opts, - lang}). + lang, + flash_connection = false}). %-define(DBGFSM, true). @@ -151,6 +152,14 @@ "id='~s' from='~s'~s~s>" ). +-define(FLASH_STREAM_HEADER, + "" + "" + ). +-define(NS_FLASH_STREAM, "http://www.jabber.com/streams/flash"). + -define(INVALID_NS_ERR, exmpp_stream:error('invalid-namespace')). -define(INVALID_XML_ERR, exmpp_stream:error('xml-not-well-formed')). -define(HOST_UNKNOWN_ERR, exmpp_stream:error('host-unknown')). @@ -344,7 +353,8 @@ get_subscribed(FsmRef) -> %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- -wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> +wait_for_stream({xmlstreamstart, #xmlel{ns = NS, name = Name} = Opening}, + StateData) -> DefaultLang = case ?MYLANG of undefined -> "en"; @@ -353,11 +363,19 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> end, Header = exmpp_stream:opening_reply(Opening, StateData#state.streamid, DefaultLang), - case NS of - ?NS_XMPP -> + case {NS, exmpp_xml:is_ns_declared_here(Opening, ?NS_FLASH_STREAM), + ?FLASH_HACK, + StateData#state.flash_connection} of + {_, true, true, false} -> + %% Flash client connecting - attention! + %% Some of them don't provide an xmlns:stream attribute - + %% compensate for that. + wait_for_stream({xmlstreamstart, Opening#xmlel{ns = ?NS_XMPP}}, + StateData#state{flash_connection = true}); + {?NS_XMPP, _, _, _} -> ServerB = exmpp_stringprep:nameprep( exmpp_stream:get_receiving_entity(Opening)), - Server = binary_to_list(ServerB), + Server = binary_to_list(ServerB), case ?IS_MY_HOST(Server) of true -> Lang = case exmpp_stream:get_lang(Opening) of @@ -518,11 +536,17 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> send_trailer(StateData), {stop, normal, StateData} end; - _ -> - send_header(StateData, ?MYNAME, "", DefaultLang), - send_element(StateData, ?INVALID_NS_ERR), - send_trailer(StateData), - {stop, normal, StateData} + _ -> + case Name of + <<"policy-file-request">> -> + send_text(StateData, flash_policy_string()), + {stop, normal, StateData}; + _ -> + send_header(StateData, ?MYNAME, "", DefaultLang), + send_element(StateData, ?INVALID_NS_ERR), + send_trailer(StateData), + {stop, normal, StateData} + end end; wait_for_stream(timeout, StateData) -> @@ -1565,8 +1589,15 @@ change_shaper(StateData, JID) -> send_text(StateData, Text) when StateData#state.xml_socket -> ?DEBUG("Send Text on stream = ~p", [lists:flatten(Text)]), + Text1 = + if ?FLASH_HACK and StateData#state.flash_connection -> + %% send a null byte after each stanza to Flash clients + [Text, 0]; + true -> + Text + end, (StateData#state.sockmod):send_xml(StateData#state.socket, - {xmlstreamraw, Text}); + {xmlstreamraw, Text1}); send_text(StateData, Text) -> ?DEBUG("Send XML on stream = ~s", [Text]), (StateData#state.sockmod):send(StateData#state.socket, Text). @@ -1579,6 +1610,15 @@ send_element(StateData, El) when StateData#state.xml_socket -> send_element(StateData, El) -> send_text(StateData, exmpp_stanza:to_iolist(El)). +send_header(StateData,Server, Version, Lang) + when StateData#state.flash_connection -> + Header = io_lib:format(?FLASH_STREAM_HEADER, + [StateData#state.streamid, + Server, + Version, + Lang]), + send_text(StateData, Header); + send_header(StateData, Server, Version, Lang) when StateData#state.xml_socket -> VersionAttr = @@ -2361,3 +2401,28 @@ pack_string(String, Pack) -> none -> {String, gb_trees:insert(String, String, Pack)} end. + + +%% @spec () -> string() +%% @doc Build the content of a Flash policy file. +%% It specifies as domain "*". +%% It specifies as to-ports the ports that serve ejabberd_c2s. +flash_policy_string() -> + Listen = ejabberd_config:get_local_option(listen), + ClientPortsDeep = ["," ++ integer_to_list(Port) + || {{Port,_,_}, ejabberd_c2s, _Opts} <- Listen], + %% NOTE: The function string:join/2 was introduced in Erlang/OTP R12B-0 + %% so it can't be used yet in ejabberd. + ToPortsString = case lists:flatten(ClientPortsDeep) of + [$, | Tail] -> Tail; + _ -> [] + end, + + "\n" + "\n" + "\n" + " \n" + "\n\0".