mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
Initial revision
SVN Revision: 2
This commit is contained in:
parent
58e6ff32a0
commit
e0b348319a
18
src/Makefile
Normal file
18
src/Makefile
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# $Id$
|
||||||
|
|
||||||
|
INCLUDES = -I/usr/lib/erlang/usr/include \
|
||||||
|
-I/usr/lib/erlang/lib/erl_interface-3.3.0/include
|
||||||
|
|
||||||
|
LIBDIRS = -L/usr/lib/erlang/lib/erl_interface-3.3.0/lib
|
||||||
|
|
||||||
|
all: expat_erl.so
|
||||||
|
erl -make
|
||||||
|
|
||||||
|
expat_erl.so: expat_erl.c
|
||||||
|
gcc -Wall $(INCLUDES) $(LIBDIRS) \
|
||||||
|
-lexpat \
|
||||||
|
expat_erl.c \
|
||||||
|
-lerl_interface \
|
||||||
|
-lei \
|
||||||
|
-o expat_erl.so -fpic -shared \
|
||||||
|
|
17
src/ejabberd.erl
Normal file
17
src/ejabberd.erl
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% File : ejabberd.erl
|
||||||
|
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
%%% Purpose :
|
||||||
|
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
%%% Id : $Id$
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(ejabberd).
|
||||||
|
-author('alexey@sevcom.net').
|
||||||
|
-vsn('$Revision$ ').
|
||||||
|
|
||||||
|
-export([start/0]).
|
||||||
|
|
||||||
|
start() ->
|
||||||
|
{ok, _} = erl_ddll:start(),
|
||||||
|
ejabberd_listener:start().
|
17
src/ejabberd.hrl
Normal file
17
src/ejabberd.hrl
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% File : ejabberd.hrl
|
||||||
|
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
%%% Purpose :
|
||||||
|
%%% Created : 17 Nov 2002 by Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
%%% Id : $Id$
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
-define(ejabberd_debug, true).
|
||||||
|
|
||||||
|
-ifdef(ejabberd_debug).
|
||||||
|
-define(DEBUG(Format, Args), io:format("D(~p:~p:~p) : "++Format++"~n",
|
||||||
|
[self(),?MODULE,?LINE]++Args)).
|
||||||
|
-else.
|
||||||
|
-define(DEBUG(F,A),[]).
|
||||||
|
-endif.
|
||||||
|
|
219
src/ejabberd_c2s.erl
Normal file
219
src/ejabberd_c2s.erl
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% File : ejabberd_c2s.erl
|
||||||
|
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
%%% Purpose :
|
||||||
|
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
%%% Id : $Id$
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(ejabberd_c2s).
|
||||||
|
-author('alexey@sevcom.net').
|
||||||
|
-vsn('$Revision$ ').
|
||||||
|
|
||||||
|
-behaviour(gen_fsm).
|
||||||
|
|
||||||
|
%% External exports
|
||||||
|
-export([start/1, receiver/2, sender/1, send_text/2]).
|
||||||
|
|
||||||
|
%% gen_fsm callbacks
|
||||||
|
%-export([init/1, state_name/2, state_name/3, handle_event/3,
|
||||||
|
% handle_sync_event/4, handle_info/3, terminate/3]).
|
||||||
|
%
|
||||||
|
-export([init/1, wait_for_stream/2, wait_for_auth/2, terminate/3]).
|
||||||
|
|
||||||
|
-record(state, {socket, sender, receiver}).
|
||||||
|
|
||||||
|
-include("ejabberd.hrl").
|
||||||
|
|
||||||
|
%start_old(Socket) ->
|
||||||
|
% spawn(?MODULE, init, [Socket]).
|
||||||
|
|
||||||
|
%init_old(Socket) ->
|
||||||
|
% SenderPid = spawn(?MODULE, sender, [Socket]),
|
||||||
|
% ReceiverPid = spawn(?MODULE, receiver, [Socket, self()]),
|
||||||
|
% loop_old(Socket, SenderPid, ReceiverPid).
|
||||||
|
%
|
||||||
|
%loop_old(Socket, SenderPid, ReceiverPid) ->
|
||||||
|
% receive
|
||||||
|
% {xmlstreamstart, Name, Attrs} ->
|
||||||
|
% ?DEBUG("Socket(~p) -> XML Stream start~n"
|
||||||
|
% " Name: ~s~n"
|
||||||
|
% " Attrs: ~p~n", [Socket, Name, Attrs]),
|
||||||
|
% loop_old(Socket, SenderPid, ReceiverPid);
|
||||||
|
% {xmlstreamend, Name} ->
|
||||||
|
% ?DEBUG("Socket(~p) -> XML Stream end~n"
|
||||||
|
% " Name: ~s~n", [Socket, Name]),
|
||||||
|
% loop_old(Socket, SenderPid, ReceiverPid);
|
||||||
|
% {xmlstreamelement, El} ->
|
||||||
|
% ?DEBUG("Socket(~p) -> XML Stream element~n"
|
||||||
|
% " Element: ~p~n", [Socket, El]),
|
||||||
|
% loop_old(Socket, SenderPid, ReceiverPid);
|
||||||
|
% {xmlstreamerror, Err} ->
|
||||||
|
% ?DEBUG("Socket(~p) -> XML Stream error~n"
|
||||||
|
% " Error: ~p~n", [Socket, Err]),
|
||||||
|
% loop_old(Socket, SenderPid, ReceiverPid)
|
||||||
|
% end.
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
-define(DBGFSM, true).
|
||||||
|
|
||||||
|
-ifdef(DBGFSM).
|
||||||
|
-define(FSMOPTS, [{debug, [trace]}]).
|
||||||
|
-else.
|
||||||
|
-define(FSMOPTS, []).
|
||||||
|
-endif.
|
||||||
|
|
||||||
|
-define(STREAM_HEADER,
|
||||||
|
"<stream:stream xmlns='jabber:client' "
|
||||||
|
"xmlns:stream='http://etherx.jabber.org/streams' "
|
||||||
|
"id='~s' from='~s'>"
|
||||||
|
).
|
||||||
|
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% API
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
start(Socket) ->
|
||||||
|
gen_fsm:start(ejabberd_c2s, [Socket], ?FSMOPTS).
|
||||||
|
%start_old(Socket) ->
|
||||||
|
% spawn(?MODULE, init, [Socket]).
|
||||||
|
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% Callback functions from gen_fsm
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
%%----------------------------------------------------------------------
|
||||||
|
%% Func: init/1
|
||||||
|
%% Returns: {ok, StateName, StateData} |
|
||||||
|
%% {ok, StateName, StateData, Timeout} |
|
||||||
|
%% ignore |
|
||||||
|
%% {stop, StopReason}
|
||||||
|
%%----------------------------------------------------------------------
|
||||||
|
init([Socket]) ->
|
||||||
|
SenderPid = spawn(?MODULE, sender, [Socket]),
|
||||||
|
ReceiverPid = spawn(?MODULE, receiver, [Socket, self()]),
|
||||||
|
{ok, wait_for_stream, #state{socket = Socket,
|
||||||
|
receiver = ReceiverPid,
|
||||||
|
sender = SenderPid}}.
|
||||||
|
|
||||||
|
%%----------------------------------------------------------------------
|
||||||
|
%% Func: StateName/2
|
||||||
|
%% Returns: {next_state, NextStateName, NextStateData} |
|
||||||
|
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||||
|
%% {stop, Reason, NewStateData}
|
||||||
|
%%----------------------------------------------------------------------
|
||||||
|
state_name(Event, StateData) ->
|
||||||
|
{next_state, state_name, StateData}.
|
||||||
|
|
||||||
|
wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
|
||||||
|
case lists:keysearch("xmlns:stream", 1, Attrs) of
|
||||||
|
{value, {"xmlns:stream", "http://etherx.jabber.org/streams"}} ->
|
||||||
|
% TODO
|
||||||
|
Header = io_lib:format(?STREAM_HEADER, ["SID", "localhost"]),
|
||||||
|
StateData#state.sender ! {text, Header},
|
||||||
|
{next_state, wait_for_auth, StateData};
|
||||||
|
_ ->
|
||||||
|
{stop, error, StateData}
|
||||||
|
end;
|
||||||
|
|
||||||
|
wait_for_stream(closed, StateData) ->
|
||||||
|
{stop, normal, StateData}.
|
||||||
|
|
||||||
|
|
||||||
|
wait_for_auth({xmlstreamelement, El}, StateData) ->
|
||||||
|
% TODO
|
||||||
|
{next_state, wait_for_auth, StateData};
|
||||||
|
|
||||||
|
wait_for_auth({xmlstreamend, Name}, StateData) ->
|
||||||
|
% TODO
|
||||||
|
{stop, normal, StateData};
|
||||||
|
|
||||||
|
wait_for_auth(closed, StateData) ->
|
||||||
|
{stop, normal, StateData}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%----------------------------------------------------------------------
|
||||||
|
%% Func: StateName/3
|
||||||
|
%% Returns: {next_state, NextStateName, NextStateData} |
|
||||||
|
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||||
|
%% {reply, Reply, NextStateName, NextStateData} |
|
||||||
|
%% {reply, Reply, NextStateName, NextStateData, Timeout} |
|
||||||
|
%% {stop, Reason, NewStateData} |
|
||||||
|
%% {stop, Reason, Reply, NewStateData}
|
||||||
|
%%----------------------------------------------------------------------
|
||||||
|
state_name(Event, From, StateData) ->
|
||||||
|
Reply = ok,
|
||||||
|
{reply, Reply, state_name, StateData}.
|
||||||
|
|
||||||
|
%%----------------------------------------------------------------------
|
||||||
|
%% Func: handle_event/3
|
||||||
|
%% Returns: {next_state, NextStateName, NextStateData} |
|
||||||
|
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||||
|
%% {stop, Reason, NewStateData}
|
||||||
|
%%----------------------------------------------------------------------
|
||||||
|
handle_event(Event, StateName, StateData) ->
|
||||||
|
{next_state, StateName, StateData}.
|
||||||
|
|
||||||
|
%%----------------------------------------------------------------------
|
||||||
|
%% Func: handle_sync_event/4
|
||||||
|
%% Returns: {next_state, NextStateName, NextStateData} |
|
||||||
|
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||||
|
%% {reply, Reply, NextStateName, NextStateData} |
|
||||||
|
%% {reply, Reply, NextStateName, NextStateData, Timeout} |
|
||||||
|
%% {stop, Reason, NewStateData} |
|
||||||
|
%% {stop, Reason, Reply, NewStateData}
|
||||||
|
%%----------------------------------------------------------------------
|
||||||
|
handle_sync_event(Event, From, StateName, StateData) ->
|
||||||
|
Reply = ok,
|
||||||
|
{reply, Reply, StateName, StateData}.
|
||||||
|
|
||||||
|
%%----------------------------------------------------------------------
|
||||||
|
%% Func: handle_info/3
|
||||||
|
%% Returns: {next_state, NextStateName, NextStateData} |
|
||||||
|
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||||
|
%% {stop, Reason, NewStateData}
|
||||||
|
%%----------------------------------------------------------------------
|
||||||
|
handle_info(Info, StateName, StateData) ->
|
||||||
|
{next_state, StateName, StateData}.
|
||||||
|
|
||||||
|
%%----------------------------------------------------------------------
|
||||||
|
%% Func: terminate/3
|
||||||
|
%% Purpose: Shutdown the fsm
|
||||||
|
%% Returns: any
|
||||||
|
%%----------------------------------------------------------------------
|
||||||
|
terminate(Reason, StateName, StatData) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% Internal functions
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
receiver(Socket, C2SPid) ->
|
||||||
|
XMLStreamPid = xml_stream:start(C2SPid),
|
||||||
|
receiver(Socket, C2SPid, XMLStreamPid).
|
||||||
|
|
||||||
|
receiver(Socket, C2SPid, XMLStreamPid) ->
|
||||||
|
case gen_tcp:recv(Socket, 0) of
|
||||||
|
{ok, Text} ->
|
||||||
|
xml_stream:send_text(XMLStreamPid, Text),
|
||||||
|
receiver(Socket, C2SPid, XMLStreamPid);
|
||||||
|
{error, closed} ->
|
||||||
|
gen_fsm:send_event(C2SPid, closed),
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
|
sender(Socket) ->
|
||||||
|
receive
|
||||||
|
{text, Text} ->
|
||||||
|
gen_tcp:send(Socket,Text),
|
||||||
|
sender(Socket);
|
||||||
|
closed ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
|
send_text(Pid, Text) ->
|
||||||
|
Pid ! {text, Text}.
|
||||||
|
|
42
src/ejabberd_listener.erl
Normal file
42
src/ejabberd_listener.erl
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% File : ejabberd_listener.erl
|
||||||
|
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
%%% Purpose :
|
||||||
|
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
%%% Id : $Id$
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(ejabberd_listener).
|
||||||
|
-author('alexey@sevcom.net').
|
||||||
|
-vsn('$Revision$ ').
|
||||||
|
|
||||||
|
-export([start/0, init/0]).
|
||||||
|
|
||||||
|
start() ->
|
||||||
|
register(ejabberd_listener, spawn(?MODULE, init, [])).
|
||||||
|
|
||||||
|
init() ->
|
||||||
|
{ok, ListenSocket} = gen_tcp:listen(5522, [binary,
|
||||||
|
{packet, 0},
|
||||||
|
{active, false},
|
||||||
|
{reuseaddr, true}]),
|
||||||
|
accept(ListenSocket).
|
||||||
|
|
||||||
|
accept(ListenSocket) ->
|
||||||
|
case gen_tcp:accept(ListenSocket) of
|
||||||
|
{ok,Socket} ->
|
||||||
|
ejabberd_c2s:start(Socket),
|
||||||
|
accept(ListenSocket)
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
do_recv(Sock, Bs) ->
|
||||||
|
case gen_tcp:recv(Sock, 0) of
|
||||||
|
{ok, B} ->
|
||||||
|
do_recv(Sock, [Bs, B]);
|
||||||
|
{error, closed} ->
|
||||||
|
{ok, list_to_binary(Bs)}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
155
src/expat_erl.c
Normal file
155
src/expat_erl.c
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
/* $Id$ */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <erl_driver.h>
|
||||||
|
#include <ei.h>
|
||||||
|
#include <expat.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ErlDrvPort port;
|
||||||
|
XML_Parser parser;
|
||||||
|
} expat_data;
|
||||||
|
|
||||||
|
|
||||||
|
void *erlXML_StartElementHandler(expat_data *d,
|
||||||
|
const XML_Char *name,
|
||||||
|
const XML_Char **atts)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
ei_x_buff buf;
|
||||||
|
|
||||||
|
ei_x_new_with_version(&buf);
|
||||||
|
ei_x_encode_tuple_header(&buf, 2);
|
||||||
|
ei_x_encode_atom(&buf, "xmlstart");
|
||||||
|
ei_x_encode_tuple_header(&buf, 2);
|
||||||
|
ei_x_encode_string(&buf, name);
|
||||||
|
|
||||||
|
for (i = 0; atts[i]; i += 2) {}
|
||||||
|
|
||||||
|
ei_x_encode_list_header(&buf, i/2);
|
||||||
|
|
||||||
|
for (i = 0; atts[i]; i += 2)
|
||||||
|
{
|
||||||
|
ei_x_encode_tuple_header(&buf, 2);
|
||||||
|
ei_x_encode_string(&buf, atts[i]);
|
||||||
|
ei_x_encode_string(&buf, atts[i+1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ei_x_encode_empty_list(&buf);
|
||||||
|
|
||||||
|
driver_output(d->port, buf.buff, buf.index);
|
||||||
|
ei_x_free(&buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *erlXML_EndElementHandler(expat_data *d,
|
||||||
|
const XML_Char *name)
|
||||||
|
{
|
||||||
|
ei_x_buff buf;
|
||||||
|
|
||||||
|
ei_x_new_with_version(&buf);
|
||||||
|
ei_x_encode_tuple_header(&buf, 2);
|
||||||
|
ei_x_encode_atom(&buf, "xmlend");
|
||||||
|
ei_x_encode_string(&buf, name);
|
||||||
|
|
||||||
|
driver_output(d->port, buf.buff, buf.index);
|
||||||
|
ei_x_free(&buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *erlXML_CharacterDataHandler(expat_data *d,
|
||||||
|
const XML_Char *s,
|
||||||
|
int len)
|
||||||
|
{
|
||||||
|
ei_x_buff buf;
|
||||||
|
|
||||||
|
ei_x_new_with_version(&buf);
|
||||||
|
ei_x_encode_tuple_header(&buf, 2);
|
||||||
|
ei_x_encode_atom(&buf, "xmlcdata");
|
||||||
|
ei_x_encode_string_len(&buf, s, len);
|
||||||
|
|
||||||
|
driver_output(d->port, buf.buff, buf.index);
|
||||||
|
ei_x_free(&buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ErlDrvData expat_erl_start(ErlDrvPort port, char *buff)
|
||||||
|
{
|
||||||
|
expat_data* d = (expat_data*)driver_alloc(sizeof(expat_data));
|
||||||
|
d->port = port;
|
||||||
|
d->parser = XML_ParserCreate("UTF-8");
|
||||||
|
XML_SetUserData(d->parser, d);
|
||||||
|
|
||||||
|
XML_SetStartElementHandler(
|
||||||
|
d->parser, (XML_StartElementHandler)erlXML_StartElementHandler);
|
||||||
|
XML_SetEndElementHandler(
|
||||||
|
d->parser, (XML_EndElementHandler)erlXML_EndElementHandler);
|
||||||
|
XML_SetCharacterDataHandler(
|
||||||
|
d->parser, (XML_CharacterDataHandler)erlXML_CharacterDataHandler);
|
||||||
|
|
||||||
|
|
||||||
|
return (ErlDrvData)d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void expat_erl_stop(ErlDrvData handle)
|
||||||
|
{
|
||||||
|
/* TODO: free parser */
|
||||||
|
driver_free((char*)handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void expat_erl_output(ErlDrvData handle, char *buff, int bufflen)
|
||||||
|
{
|
||||||
|
expat_data* d = (expat_data*)handle;
|
||||||
|
int res, errcode;
|
||||||
|
char *errstring;
|
||||||
|
ei_x_buff buf;
|
||||||
|
|
||||||
|
/*buff[bufflen] = 0;
|
||||||
|
|
||||||
|
fprintf(stderr, "RCVD: '%s'\n", buff);
|
||||||
|
fflush(stderr);*/
|
||||||
|
|
||||||
|
res = XML_Parse(d->parser, buff, bufflen, 0);
|
||||||
|
|
||||||
|
if(!res)
|
||||||
|
{
|
||||||
|
errcode = XML_GetErrorCode(d->parser);
|
||||||
|
errstring = (char *)XML_ErrorString(errcode);
|
||||||
|
|
||||||
|
ei_x_new_with_version(&buf);
|
||||||
|
ei_x_encode_tuple_header(&buf, 2);
|
||||||
|
ei_x_encode_atom(&buf, "xmlerror");
|
||||||
|
ei_x_encode_tuple_header(&buf, 2);
|
||||||
|
ei_x_encode_long(&buf, errcode);
|
||||||
|
ei_x_encode_string(&buf, errstring);
|
||||||
|
|
||||||
|
driver_output(d->port, buf.buff, buf.index);
|
||||||
|
ei_x_free(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
//driver_output(d->port, &res, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ErlDrvEntry expat_driver_entry = {
|
||||||
|
NULL, /* F_PTR init, N/A */
|
||||||
|
expat_erl_start, /* L_PTR start, called when port is opened */
|
||||||
|
expat_erl_stop, /* F_PTR stop, called when port is closed */
|
||||||
|
expat_erl_output, /* F_PTR output, called when erlang has sent */
|
||||||
|
NULL, /* F_PTR ready_input, called when input descriptor ready */
|
||||||
|
NULL, /* F_PTR ready_output, called when output descriptor ready */
|
||||||
|
"expat_erl", /* char *driver_name, the argument to open_port */
|
||||||
|
NULL, /* F_PTR finish, called when unloaded */
|
||||||
|
NULL, /* F_PTR control, port_command callback */
|
||||||
|
NULL, /* F_PTR timeout, reserved */
|
||||||
|
NULL /* F_PTR outputv, reserved */
|
||||||
|
};
|
||||||
|
|
||||||
|
DRIVER_INIT(expat_erl) /* must match name in driver_entry */
|
||||||
|
{
|
||||||
|
return &expat_driver_entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
77
src/xml_stream.erl
Normal file
77
src/xml_stream.erl
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% File : xml_stream.erl
|
||||||
|
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
%%% Purpose :
|
||||||
|
%%% Created : 17 Nov 2002 by Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
%%% Id : $Id$
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(xml_stream).
|
||||||
|
-author('alexey@sevcom.net').
|
||||||
|
-vsn('$Revision$ ').
|
||||||
|
|
||||||
|
-export([start/1, init/1, send_text/2]).
|
||||||
|
|
||||||
|
start(CallbackPid) ->
|
||||||
|
spawn(?MODULE, init, [CallbackPid]).
|
||||||
|
|
||||||
|
init(CallbackPid) ->
|
||||||
|
ok = erl_ddll:load_driver(".", expat_erl),
|
||||||
|
Port = open_port({spawn, expat_erl}, [binary]),
|
||||||
|
loop(CallbackPid, Port, []).
|
||||||
|
|
||||||
|
loop(CallbackPid, Port, Stack) ->
|
||||||
|
receive
|
||||||
|
{Port, {data, Bin}} ->
|
||||||
|
%CallbackPid ! binary_to_term(Bin),
|
||||||
|
Data = binary_to_term(Bin),
|
||||||
|
loop(CallbackPid, Port, process_data(CallbackPid, Stack, Data));
|
||||||
|
{From, {send, Str}} ->
|
||||||
|
Port ! {self(), {command, Str}},
|
||||||
|
loop(CallbackPid, Port, Stack)
|
||||||
|
end.
|
||||||
|
|
||||||
|
process_data(CallbackPid, Stack, Data) ->
|
||||||
|
case Data of
|
||||||
|
{xmlstart, {Name, Attrs}} ->
|
||||||
|
if Stack == [] ->
|
||||||
|
gen_fsm:send_event(CallbackPid,
|
||||||
|
{xmlstreamstart, Name, Attrs});
|
||||||
|
true -> true
|
||||||
|
end,
|
||||||
|
[{xmlelement, Name, Attrs, []} | Stack];
|
||||||
|
{xmlend, EndName} ->
|
||||||
|
case Stack of
|
||||||
|
[{xmlelement, Name, Attrs, Els} | Tail] ->
|
||||||
|
NewEl = {xmlelement, Name, Attrs, lists:reverse(Els)},
|
||||||
|
Len = length(Tail),
|
||||||
|
if
|
||||||
|
Len > 1 -> add_subelement(NewEl, Tail);
|
||||||
|
Len == 1 ->
|
||||||
|
gen_fsm:send_event(CallbackPid,
|
||||||
|
{xmlstreamelement, NewEl}),
|
||||||
|
Tail;
|
||||||
|
Len == 0 ->
|
||||||
|
gen_fsm:send_event(CallbackPid,
|
||||||
|
{xmlstreamend, EndName}),
|
||||||
|
Tail
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
{xmlcdata, CData} ->
|
||||||
|
add_subelement({xmlcdata, CData}, Stack);
|
||||||
|
{xmlerror, Err} -> gen_fsm:send_event(CallbackPid,
|
||||||
|
{xmlstreamerror, Err})
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
add_subelement(El, Stack) ->
|
||||||
|
case Stack of
|
||||||
|
[{xmlelement, Name, Attrs, Els} | Tail] ->
|
||||||
|
[{xmlelement, Name, Attrs, [El | Els]} | Tail];
|
||||||
|
[] -> []
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
send_text(Pid, Text) ->
|
||||||
|
Pid ! {self(), {send, Text}}.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user