]> granicus.if.org Git - ejabberd/commitdiff
Ported flash clients patch from 2.1.x
authorAlexey Shchepin <alexey@process-one.net>
Fri, 8 Jul 2011 15:17:05 +0000 (18:17 +0300)
committerAlexey Shchepin <alexey@process-one.net>
Fri, 8 Jul 2011 15:17:05 +0000 (18:17 +0300)
doc/guide.tex
src/Makefile.in
src/configure.ac
src/ejabberd.hrl
src/ejabberd_c2s.erl

index 5b999b15b298022b12c41ddb75fd445a9c199093..c72b305ada769befe374e4478f5be9c6c81d6638 100644 (file)
@@ -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}
index f11360a6417ce65a6417ab1d5198eb9648745a99..83668c0f1d3b83bfc14c712689b6452c1fa9732a 100644 (file)
@@ -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) \
index 5aa34de249429c4dc64c58ba897686944f547ca2..a902c3aab982b22f0b011bb589bfd7234cca6bd4 100644 (file)
@@ -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
index d77769a99a725fc4571b542e67c49e66d91d8404..8c07db530c33612de19bf8df51311e52eecf35ab 100644 (file)
 -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).
index c84b9527976fdce27ac91a8f7c1c599c52ce562e..73e8831733e82d1835c87c337a765bb3354c636c 100644 (file)
                ip,
                aux_fields = [],
                fsm_limit_opts,
-               lang}).
+               lang,
+                flash_connection = false}).
 
 %-define(DBGFSM, true).
 
        "id='~s' from='~s'~s~s>"
        ).
 
+-define(FLASH_STREAM_HEADER,
+       "<?xml version='1.0'?>"
+       "<flash:stream xmlns='jabber:client' "
+       "xmlns:stream='http://etherx.jabber.org/streams' "
+       "id='~s' from='~s'~s~s>"
+       ).
+-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,
+
+    "<?xml version=\"1.0\"?>\n"
+       "<!DOCTYPE cross-domain-policy SYSTEM "
+        "\"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">\n"
+       "<cross-domain-policy>\n"
+       "  <allow-access-from domain=\"*\" to-ports=\""
+       ++ ToPortsString ++
+       "\"/>\n"
+       "</cross-domain-policy>\n\0".