mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
* src/mod_irc/: Added configuration interface
* src/mod_configure.erl: Use jabber:iq:data instead of
jabber❌data
* src/mod_disco.erl: Likewise
SVN Revision: 82
This commit is contained in:
parent
764a4288ce
commit
499a1117dc
@ -1,3 +1,11 @@
|
|||||||
|
2003-02-23 Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
|
||||||
|
* src/mod_irc/: Added configuration interface
|
||||||
|
|
||||||
|
* src/mod_configure.erl: Use jabber:iq:data instead of
|
||||||
|
jabber:x:data
|
||||||
|
* src/mod_disco.erl: Likewise
|
||||||
|
|
||||||
2003-02-22 Alexey Shchepin <alexey@sevcom.net>
|
2003-02-22 Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
|
||||||
* src/mod_configure.erl: Backup management support
|
* src/mod_configure.erl: Backup management support
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% File : mod_configure.erl
|
%%% File : mod_configure.erl
|
||||||
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||||
%%% Purpose : Support for online configuration of ejabberd via x:data
|
%%% Purpose : Support for online configuration of ejabberd
|
||||||
%%% Created : 19 Jan 2003 by Alexey Shchepin <alexey@sevcom.net>
|
%%% Created : 19 Jan 2003 by Alexey Shchepin <alexey@sevcom.net>
|
||||||
%%% Id : $Id$
|
%%% Id : $Id$
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
@ -23,15 +23,15 @@
|
|||||||
|
|
||||||
start(Opts) ->
|
start(Opts) ->
|
||||||
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
|
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
|
||||||
gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_XDATA,
|
gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_IQDATA,
|
||||||
?MODULE, process_local_iq, IQDisc),
|
?MODULE, process_local_iq, IQDisc),
|
||||||
gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_XDATA,
|
gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_IQDATA,
|
||||||
?MODULE, process_sm_iq, IQDisc),
|
?MODULE, process_sm_iq, IQDisc),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
stop() ->
|
stop() ->
|
||||||
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_XDATA),
|
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_IQDATA),
|
||||||
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_XDATA).
|
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_IQDATA).
|
||||||
|
|
||||||
|
|
||||||
process_local_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
|
process_local_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
|
||||||
|
@ -125,28 +125,28 @@ process_local_iq_info(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
|
|||||||
{iq, ID, result, XMLNS, [{xmlelement,
|
{iq, ID, result, XMLNS, [{xmlelement,
|
||||||
"query",
|
"query",
|
||||||
[{"xmlns", XMLNS}],
|
[{"xmlns", XMLNS}],
|
||||||
[feature_to_xml({?NS_XDATA})
|
[feature_to_xml({?NS_IQDATA})
|
||||||
]
|
]
|
||||||
}]};
|
}]};
|
||||||
["running nodes", ENode, "modules"] -> ?EMPTY_INFO_RESULT;
|
["running nodes", ENode, "modules"] -> ?EMPTY_INFO_RESULT;
|
||||||
["running nodes", ENode, "modules", _] ->
|
["running nodes", ENode, "modules", _] ->
|
||||||
{iq, ID, result, XMLNS,
|
{iq, ID, result, XMLNS,
|
||||||
[{xmlelement, "query", [{"xmlns", XMLNS}],
|
[{xmlelement, "query", [{"xmlns", XMLNS}],
|
||||||
[feature_to_xml({?NS_XDATA})]}]};
|
[feature_to_xml({?NS_IQDATA})]}]};
|
||||||
["running nodes", ENode, "backup"] -> ?EMPTY_INFO_RESULT;
|
["running nodes", ENode, "backup"] -> ?EMPTY_INFO_RESULT;
|
||||||
["running nodes", ENode, "backup", _] ->
|
["running nodes", ENode, "backup", _] ->
|
||||||
{iq, ID, result, XMLNS,
|
{iq, ID, result, XMLNS,
|
||||||
[{xmlelement, "query", [{"xmlns", XMLNS}],
|
[{xmlelement, "query", [{"xmlns", XMLNS}],
|
||||||
[feature_to_xml({?NS_XDATA})]}]};
|
[feature_to_xml({?NS_IQDATA})]}]};
|
||||||
["running nodes", ENode, "import"] -> ?EMPTY_INFO_RESULT;
|
["running nodes", ENode, "import"] -> ?EMPTY_INFO_RESULT;
|
||||||
["running nodes", ENode, "import", _] ->
|
["running nodes", ENode, "import", _] ->
|
||||||
{iq, ID, result, XMLNS,
|
{iq, ID, result, XMLNS,
|
||||||
[{xmlelement, "query", [{"xmlns", XMLNS}],
|
[{xmlelement, "query", [{"xmlns", XMLNS}],
|
||||||
[feature_to_xml({?NS_XDATA})]}]};
|
[feature_to_xml({?NS_IQDATA})]}]};
|
||||||
["config", _] ->
|
["config", _] ->
|
||||||
{iq, ID, result, XMLNS,
|
{iq, ID, result, XMLNS,
|
||||||
[{xmlelement, "query", [{"xmlns", XMLNS}],
|
[{xmlelement, "query", [{"xmlns", XMLNS}],
|
||||||
[feature_to_xml({?NS_XDATA})]}]};
|
[feature_to_xml({?NS_IQDATA})]}]};
|
||||||
_ ->
|
_ ->
|
||||||
{iq, ID, error, XMLNS,
|
{iq, ID, error, XMLNS,
|
||||||
[SubEl, {xmlelement, "error",
|
[SubEl, {xmlelement, "error",
|
||||||
@ -443,7 +443,7 @@ process_sm_iq_info(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
|
|||||||
"" ->
|
"" ->
|
||||||
{iq, ID, result, XMLNS,
|
{iq, ID, result, XMLNS,
|
||||||
[{xmlelement, "query", [{"xmlns", XMLNS}],
|
[{xmlelement, "query", [{"xmlns", XMLNS}],
|
||||||
[feature_to_xml({?NS_XDATA})]}]};
|
[feature_to_xml({?NS_IQDATA})]}]};
|
||||||
_ ->
|
_ ->
|
||||||
{iq, ID, error, XMLNS,
|
{iq, ID, error, XMLNS,
|
||||||
[SubEl, {xmlelement, "error",
|
[SubEl, {xmlelement, "error",
|
||||||
|
@ -12,15 +12,22 @@
|
|||||||
|
|
||||||
-behaviour(gen_mod).
|
-behaviour(gen_mod).
|
||||||
|
|
||||||
-export([start/1, init/1, stop/0, closed_conection/2]).
|
-export([start/1, init/1, stop/0, closed_conection/2,
|
||||||
|
get_user_and_encoding/2]).
|
||||||
|
|
||||||
-include("ejabberd.hrl").
|
-include("ejabberd.hrl").
|
||||||
-include("namespaces.hrl").
|
-include("namespaces.hrl").
|
||||||
|
|
||||||
|
-define(DEFAULT_IRC_ENCODING, "koi8-r").
|
||||||
|
|
||||||
-record(irc_connection, {userserver, pid}).
|
-record(irc_connection, {userserver, pid}).
|
||||||
|
-record(irc_custom, {userserver, data}).
|
||||||
|
|
||||||
start(Opts) ->
|
start(Opts) ->
|
||||||
iconv:start(),
|
iconv:start(),
|
||||||
|
mnesia:create_table(irc_custom,
|
||||||
|
[{disc_copies, [node()]},
|
||||||
|
{attributes, record_info(fields, irc_custom)}]),
|
||||||
Host = gen_mod:get_opt(host, Opts, "irc." ++ ?MYNAME),
|
Host = gen_mod:get_opt(host, Opts, "irc." ++ ?MYNAME),
|
||||||
register(ejabberd_mod_irc, spawn(?MODULE, init, [Host])).
|
register(ejabberd_mod_irc, spawn(?MODULE, init, [Host])).
|
||||||
|
|
||||||
@ -60,15 +67,12 @@ do_route(Host, From, To, Packet) ->
|
|||||||
Res = {iq, ID, result, XMLNS,
|
Res = {iq, ID, result, XMLNS,
|
||||||
[{xmlelement, "query",
|
[{xmlelement, "query",
|
||||||
[{"xmlns", XMLNS}],
|
[{"xmlns", XMLNS}],
|
||||||
[{xmlelement, "identity",
|
iq_disco()}]},
|
||||||
[{"category", "conference"},
|
|
||||||
{"type", "irc"},
|
|
||||||
{"name", "ejabberd"}], []},
|
|
||||||
{xmlelement, "feature",
|
|
||||||
[{"var", ?NS_MUC}], []}]}]},
|
|
||||||
ejabberd_router:route(To,
|
ejabberd_router:route(To,
|
||||||
From,
|
From,
|
||||||
jlib:iq_to_xml(Res));
|
jlib:iq_to_xml(Res));
|
||||||
|
{iq, ID, Type, ?NS_IQDATA = XMLNS, SubEl} ->
|
||||||
|
iq_data(From, To, ID, XMLNS, Type, SubEl);
|
||||||
_ ->
|
_ ->
|
||||||
Err = jlib:make_error_reply(
|
Err = jlib:make_error_reply(
|
||||||
Packet, "503", "Service Unavailable"),
|
Packet, "503", "Service Unavailable"),
|
||||||
@ -85,8 +89,11 @@ do_route(Host, From, To, Packet) ->
|
|||||||
case ets:lookup(irc_connection, {From, Server}) of
|
case ets:lookup(irc_connection, {From, Server}) of
|
||||||
[] ->
|
[] ->
|
||||||
io:format("open new connection~n"),
|
io:format("open new connection~n"),
|
||||||
|
{Username, Encoding} = get_user_and_encoding(
|
||||||
|
From, Server),
|
||||||
{ok, Pid} = mod_irc_connection:start(
|
{ok, Pid} = mod_irc_connection:start(
|
||||||
From, Host, Server),
|
From, Host, Server,
|
||||||
|
Username, Encoding),
|
||||||
ets:insert(
|
ets:insert(
|
||||||
irc_connection,
|
irc_connection,
|
||||||
#irc_connection{userserver = {From, Server},
|
#irc_connection{userserver = {From, Server},
|
||||||
@ -137,3 +144,225 @@ stop() ->
|
|||||||
closed_conection(From, Server) ->
|
closed_conection(From, Server) ->
|
||||||
ets:delete(irc_connection, {From, Server}).
|
ets:delete(irc_connection, {From, Server}).
|
||||||
|
|
||||||
|
|
||||||
|
iq_disco() ->
|
||||||
|
[{xmlelement, "identity",
|
||||||
|
[{"category", "conference"},
|
||||||
|
{"type", "irc"},
|
||||||
|
{"name", "ejabberd/mod_irc"}], []},
|
||||||
|
{xmlelement, "feature",
|
||||||
|
[{"var", ?NS_MUC}], []},
|
||||||
|
{xmlelement, "feature",
|
||||||
|
[{"var", ?NS_IQDATA}], []}].
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
iq_data(From, To, ID, XMLNS, Type, SubEl) ->
|
||||||
|
case catch process_iq_data(From, To, ID, XMLNS, Type, SubEl) of
|
||||||
|
{'EXIT', Reason} ->
|
||||||
|
?ERROR_MSG("~p", [Reason]);
|
||||||
|
ResIQ ->
|
||||||
|
if
|
||||||
|
ResIQ /= ignore ->
|
||||||
|
ejabberd_router:route(To, From,
|
||||||
|
jlib:iq_to_xml(ResIQ));
|
||||||
|
true ->
|
||||||
|
ok
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
process_iq_data(From, To, ID, XMLNS, Type, SubEl) ->
|
||||||
|
Lang = xml:get_tag_attr_s("xml:lang", SubEl),
|
||||||
|
case Type of
|
||||||
|
set ->
|
||||||
|
case xml:get_tag_attr_s("type", SubEl) of
|
||||||
|
"cancel" ->
|
||||||
|
{iq, ID, result, XMLNS,
|
||||||
|
[{xmlelement, "query", [{"xmlns", XMLNS}], []}]};
|
||||||
|
"submit" ->
|
||||||
|
XData = jlib:parse_xdata_submit(SubEl),
|
||||||
|
case XData of
|
||||||
|
invalid ->
|
||||||
|
{iq, ID, error, XMLNS,
|
||||||
|
[SubEl, {xmlelement, "error",
|
||||||
|
[{"code", "400"}],
|
||||||
|
[{xmlcdata, "Bad Request"}]}]};
|
||||||
|
_ ->
|
||||||
|
Node =
|
||||||
|
string:tokens(
|
||||||
|
xml:get_tag_attr_s("node", SubEl),
|
||||||
|
"/"),
|
||||||
|
case set_form(From, Node, Lang, XData) of
|
||||||
|
{result, Res} ->
|
||||||
|
{iq, ID, result, XMLNS,
|
||||||
|
[{xmlelement, "query",
|
||||||
|
[{"xmlns", XMLNS}],
|
||||||
|
Res
|
||||||
|
}]};
|
||||||
|
{error, Code, Desc} ->
|
||||||
|
{iq, ID, error, XMLNS,
|
||||||
|
[SubEl, {xmlelement, "error",
|
||||||
|
[{"code", Code}],
|
||||||
|
[{xmlcdata, Desc}]}]}
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
{iq, ID, error, XMLNS,
|
||||||
|
[SubEl, {xmlelement, "error",
|
||||||
|
[{"code", "405"}],
|
||||||
|
[{xmlcdata, "Not Allowed"}]}]}
|
||||||
|
end;
|
||||||
|
get ->
|
||||||
|
Node =
|
||||||
|
string:tokens(xml:get_tag_attr_s("node", SubEl), "/"),
|
||||||
|
case get_form(From, Node, Lang) of
|
||||||
|
{result, Res} ->
|
||||||
|
{iq, ID, result, XMLNS,
|
||||||
|
[{xmlelement, "query", [{"xmlns", XMLNS}],
|
||||||
|
Res
|
||||||
|
}]};
|
||||||
|
{error, Code, Desc} ->
|
||||||
|
{iq, ID, error, XMLNS,
|
||||||
|
[SubEl, {xmlelement, "error",
|
||||||
|
[{"code", Code}],
|
||||||
|
[{xmlcdata, Desc}]}]}
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
get_form(From, [], Lang) ->
|
||||||
|
{User, Server, _} = From,
|
||||||
|
{LUser, LServer, _} = jlib:jid_tolower(From),
|
||||||
|
Customs =
|
||||||
|
case catch mnesia:dirty_read({irc_custom, {LUser, LServer}}) of
|
||||||
|
{'EXIT', Reason} ->
|
||||||
|
{error, "500", "Internal Server Error"};
|
||||||
|
[] ->
|
||||||
|
{User, []};
|
||||||
|
[#irc_custom{data = Data}] ->
|
||||||
|
{xml:get_attr_s(username, Data),
|
||||||
|
xml:get_attr_s(encodings, Data)}
|
||||||
|
end,
|
||||||
|
case Customs of
|
||||||
|
{error, _, _} ->
|
||||||
|
Customs;
|
||||||
|
{Username, Encodings} ->
|
||||||
|
{result,
|
||||||
|
[{xmlelement, "title", [],
|
||||||
|
[{xmlcdata,
|
||||||
|
User ++ "@" ++ Server ++ " " ++
|
||||||
|
translate:translate(Lang, "Configuration")}]},
|
||||||
|
%{xmlelement, "instructions", [],
|
||||||
|
% [{xmlcdata,
|
||||||
|
% translate:translate(
|
||||||
|
% Lang, "")}]},
|
||||||
|
{xmlelement, "field", [{"type", "text-single"},
|
||||||
|
{"label",
|
||||||
|
translate:translate(
|
||||||
|
Lang, "IRC Username")},
|
||||||
|
{"var", "username"}],
|
||||||
|
[{xmlelement, "value", [], [{xmlcdata, Username}]}]},
|
||||||
|
{xmlelement, "field", [{"type", "fixed"}],
|
||||||
|
[{xmlelement, "value", [],
|
||||||
|
[{xmlcdata,
|
||||||
|
lists:flatten(
|
||||||
|
io_lib:format(
|
||||||
|
translate:translate(
|
||||||
|
Lang,
|
||||||
|
"If you want to specify different encodings "
|
||||||
|
"for IRC servers, fill this list with values "
|
||||||
|
"in format '{\"irc server\", \"encoding\"}'. "
|
||||||
|
"By default this service use \"~s\" encoding."),
|
||||||
|
[?DEFAULT_IRC_ENCODING]))}]}]},
|
||||||
|
{xmlelement, "field", [{"type", "fixed"}],
|
||||||
|
[{xmlelement, "value", [],
|
||||||
|
[{xmlcdata,
|
||||||
|
translate:translate(
|
||||||
|
Lang,
|
||||||
|
"Example: [{\"irc.lucky.net\", \"koi8-r\"}, "
|
||||||
|
"{\"vendetta.fef.net\", \"iso8859-1\"}]."
|
||||||
|
)}]}]},
|
||||||
|
{xmlelement, "field", [{"type", "text-multi"},
|
||||||
|
{"label",
|
||||||
|
translate:translate(Lang, "Encodings")},
|
||||||
|
{"var", "encodings"}],
|
||||||
|
lists:map(
|
||||||
|
fun(S) ->
|
||||||
|
{xmlelement, "value", [], [{xmlcdata, S}]}
|
||||||
|
end,
|
||||||
|
string:tokens(
|
||||||
|
lists:flatten(
|
||||||
|
io_lib:format("~p.", [Encodings])),
|
||||||
|
"\n"))
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
get_form(_, _, Lang) ->
|
||||||
|
{error, "503", "Service Unavailable"}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
set_form(From, [], Lang, XData) ->
|
||||||
|
{LUser, LServer, _} = jlib:jid_tolower(From),
|
||||||
|
case {lists:keysearch("username", 1, XData),
|
||||||
|
lists:keysearch("encodings", 1, XData)} of
|
||||||
|
{{value, {_, [Username]}}, {value, {_, Strings}}} ->
|
||||||
|
EncString = lists:foldl(fun(S, Res) ->
|
||||||
|
Res ++ S ++ "\n"
|
||||||
|
end, "", Strings),
|
||||||
|
case erl_scan:string(EncString) of
|
||||||
|
{ok, Tokens, _} ->
|
||||||
|
case erl_parse:parse_term(Tokens) of
|
||||||
|
{ok, Encodings} ->
|
||||||
|
case mnesia:transaction(
|
||||||
|
fun() ->
|
||||||
|
mnesia:write(
|
||||||
|
#irc_custom{userserver =
|
||||||
|
{LUser, LServer},
|
||||||
|
data =
|
||||||
|
[{username,
|
||||||
|
Username},
|
||||||
|
{encodings,
|
||||||
|
Encodings}]})
|
||||||
|
end) of
|
||||||
|
{atomic, _} ->
|
||||||
|
{result, []};
|
||||||
|
_ ->
|
||||||
|
{error, "406", "Not Acceptable"}
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
{error, "406", "Not Acceptable"}
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
{error, "406", "Not Acceptable"}
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
{error, "406", "Not Acceptable"}
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
set_form(_, _, Lang, XData) ->
|
||||||
|
{error, "503", "Service Unavailable"}.
|
||||||
|
|
||||||
|
|
||||||
|
get_user_and_encoding(From, IRCServer) ->
|
||||||
|
{User, Server, _} = From,
|
||||||
|
{LUser, LServer, _} = jlib:jid_tolower(From),
|
||||||
|
case catch mnesia:dirty_read({irc_custom, {LUser, LServer}}) of
|
||||||
|
{'EXIT', Reason} ->
|
||||||
|
{User, ?DEFAULT_IRC_ENCODING};
|
||||||
|
[] ->
|
||||||
|
{User, ?DEFAULT_IRC_ENCODING};
|
||||||
|
[#irc_custom{data = Data}] ->
|
||||||
|
{xml:get_attr_s(username, Data),
|
||||||
|
case xml:get_attr_s(IRCServer, xml:get_attr_s(encodings, Data)) of
|
||||||
|
"" -> ?DEFAULT_IRC_ENCODING;
|
||||||
|
E -> E
|
||||||
|
end}
|
||||||
|
end.
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
-behaviour(gen_fsm).
|
-behaviour(gen_fsm).
|
||||||
|
|
||||||
%% External exports
|
%% External exports
|
||||||
-export([start/3, receiver/2, route_chan/4, route_nick/3]).
|
-export([start/5, receiver/2, route_chan/4, route_nick/3]).
|
||||||
|
|
||||||
%% gen_fsm callbacks
|
%% gen_fsm callbacks
|
||||||
-export([init/1,
|
-export([init/1,
|
||||||
@ -31,13 +31,11 @@
|
|||||||
|
|
||||||
-define(SETS, gb_sets).
|
-define(SETS, gb_sets).
|
||||||
|
|
||||||
-record(state, {socket, receiver, queue,
|
-record(state, {socket, encoding, receiver, queue,
|
||||||
user, myname, server, nick,
|
user, myname, server, nick,
|
||||||
channels = dict:new(),
|
channels = dict:new(),
|
||||||
inbuf = "", outbuf = ""}).
|
inbuf = "", outbuf = ""}).
|
||||||
|
|
||||||
-define(IRC_ENCODING, "koi8-r").
|
|
||||||
|
|
||||||
-define(DBGFSM, true).
|
-define(DBGFSM, true).
|
||||||
|
|
||||||
-ifdef(DBGFSM).
|
-ifdef(DBGFSM).
|
||||||
@ -49,8 +47,8 @@
|
|||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% API
|
%%% API
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
start(From, Host, Server) ->
|
start(From, Host, Server, Username, Encoding) ->
|
||||||
gen_fsm:start(?MODULE, [From, Host, Server], ?FSMOPTS).
|
gen_fsm:start(?MODULE, [From, Host, Server, Username, Encoding], ?FSMOPTS).
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% Callback functions from gen_fsm
|
%%% Callback functions from gen_fsm
|
||||||
@ -63,12 +61,12 @@ start(From, Host, Server) ->
|
|||||||
%% ignore |
|
%% ignore |
|
||||||
%% {stop, StopReason}
|
%% {stop, StopReason}
|
||||||
%%----------------------------------------------------------------------
|
%%----------------------------------------------------------------------
|
||||||
init([From, Host, Server]) ->
|
init([From, Host, Server, Username, Encoding]) ->
|
||||||
gen_fsm:send_event(self(), init),
|
gen_fsm:send_event(self(), init),
|
||||||
{Nick, _, _} = From,
|
|
||||||
{ok, open_socket, #state{queue = queue:new(),
|
{ok, open_socket, #state{queue = queue:new(),
|
||||||
|
encoding = Encoding,
|
||||||
user = From,
|
user = From,
|
||||||
nick = Nick,
|
nick = Username,
|
||||||
myname = Host,
|
myname = Host,
|
||||||
server = Server}}.
|
server = Server}}.
|
||||||
|
|
||||||
@ -84,13 +82,10 @@ open_socket(init, StateData) ->
|
|||||||
?DEBUG("connecting to ~s:~p~n", [Addr, Port]),
|
?DEBUG("connecting to ~s:~p~n", [Addr, Port]),
|
||||||
case gen_tcp:connect(Addr, Port, [binary, {packet, 0}]) of
|
case gen_tcp:connect(Addr, Port, [binary, {packet, 0}]) of
|
||||||
{ok, Socket} ->
|
{ok, Socket} ->
|
||||||
% TODO: send nick, etc...
|
NewStateData = StateData#state{socket = Socket},
|
||||||
%send_text(Socket, io_lib:format(?STREAM_HEADER,
|
send_text(NewStateData,
|
||||||
% [StateData#state.server])),
|
io_lib:format("NICK ~s\r\n", [StateData#state.nick])),
|
||||||
%send_queue(StateData#state.socket, StateData#state.queue),
|
send_text(NewStateData,
|
||||||
send_text(Socket, io_lib:format("NICK ~s\r\n",
|
|
||||||
[StateData#state.nick])),
|
|
||||||
send_text(Socket,
|
|
||||||
io_lib:format(
|
io_lib:format(
|
||||||
"USER ~s ~s ~s :~s\r\n",
|
"USER ~s ~s ~s :~s\r\n",
|
||||||
[StateData#state.nick,
|
[StateData#state.nick,
|
||||||
@ -98,7 +93,7 @@ open_socket(init, StateData) ->
|
|||||||
StateData#state.myname,
|
StateData#state.myname,
|
||||||
StateData#state.nick])),
|
StateData#state.nick])),
|
||||||
{next_state, wait_for_registration,
|
{next_state, wait_for_registration,
|
||||||
StateData#state{socket = Socket}};
|
NewStateData};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?DEBUG("connect return ~p~n", [Reason]),
|
?DEBUG("connect return ~p~n", [Reason]),
|
||||||
Text = case Reason of
|
Text = case Reason of
|
||||||
@ -164,7 +159,7 @@ code_change(OldVsn, StateName, StateData, Extra) ->
|
|||||||
-define(SEND(S),
|
-define(SEND(S),
|
||||||
if
|
if
|
||||||
StateName == stream_established ->
|
StateName == stream_established ->
|
||||||
send_text(StateData#state.socket, S),
|
send_text(StateData, S),
|
||||||
StateData;
|
StateData;
|
||||||
true ->
|
true ->
|
||||||
StateData#state{outbuf = StateData#state.outbuf ++ S}
|
StateData#state{outbuf = StateData#state.outbuf ++ S}
|
||||||
@ -297,7 +292,7 @@ handle_info({route_nick, Nick, Packet}, StateName, StateData) ->
|
|||||||
|
|
||||||
|
|
||||||
handle_info({ircstring, [$P, $I, $N, $G, $ | ID]}, StateName, StateData) ->
|
handle_info({ircstring, [$P, $I, $N, $G, $ | ID]}, StateName, StateData) ->
|
||||||
send_text(StateData#state.socket, "PONG " ++ ID ++ "\r\n"),
|
send_text(StateData, "PONG " ++ ID ++ "\r\n"),
|
||||||
{next_state, StateName, StateData};
|
{next_state, StateName, StateData};
|
||||||
|
|
||||||
handle_info({ircstring, [$: | String]}, StateName, StateData) ->
|
handle_info({ircstring, [$: | String]}, StateName, StateData) ->
|
||||||
@ -343,7 +338,7 @@ handle_info({ircstring, [$: | String]}, StateName, StateData) ->
|
|||||||
"" ->
|
"" ->
|
||||||
NewStateData;
|
NewStateData;
|
||||||
Data ->
|
Data ->
|
||||||
send_text(NewStateData#state.socket, Data),
|
send_text(NewStateData, Data),
|
||||||
NewStateData#state{outbuf = ""}
|
NewStateData#state{outbuf = ""}
|
||||||
end,
|
end,
|
||||||
{next_state, stream_established, NewStateData1};
|
{next_state, stream_established, NewStateData1};
|
||||||
@ -360,22 +355,13 @@ handle_info({ircstring, String}, StateName, StateData) ->
|
|||||||
|
|
||||||
|
|
||||||
handle_info({send_text, Text}, StateName, StateData) ->
|
handle_info({send_text, Text}, StateName, StateData) ->
|
||||||
send_text(StateData#state.socket, Text),
|
send_text(StateData, Text),
|
||||||
{next_state, StateName, StateData};
|
{next_state, StateName, StateData};
|
||||||
handle_info({send_element, El}, StateName, StateData) ->
|
|
||||||
case StateName of
|
|
||||||
stream_established ->
|
|
||||||
send_element(StateData#state.socket, El),
|
|
||||||
{next_state, StateName, StateData};
|
|
||||||
_ ->
|
|
||||||
Q = queue:in(El, StateData#state.queue),
|
|
||||||
{next_state, StateName, StateData#state{queue = Q}}
|
|
||||||
end;
|
|
||||||
handle_info({tcp, Socket, Data}, StateName, StateData) ->
|
handle_info({tcp, Socket, Data}, StateName, StateData) ->
|
||||||
Buf = StateData#state.inbuf ++ binary_to_list(Data),
|
Buf = StateData#state.inbuf ++ binary_to_list(Data),
|
||||||
{ok, Strings} = regexp:split([C || C <- Buf, C /= $\r], "\n"),
|
{ok, Strings} = regexp:split([C || C <- Buf, C /= $\r], "\n"),
|
||||||
io:format("strings=~p~n", [Strings]),
|
io:format("strings=~p~n", [Strings]),
|
||||||
NewBuf = process_lines(Strings),
|
NewBuf = process_lines(StateData#state.encoding, Strings),
|
||||||
{next_state, StateName, StateData#state{inbuf = NewBuf}};
|
{next_state, StateName, StateData#state{inbuf = NewBuf}};
|
||||||
handle_info({tcp_closed, Socket}, StateName, StateData) ->
|
handle_info({tcp_closed, Socket}, StateName, StateData) ->
|
||||||
gen_fsm:send_event(self(), closed),
|
gen_fsm:send_event(self(), closed),
|
||||||
@ -430,13 +416,11 @@ receiver(Socket, C2SPid, XMLStreamPid) ->
|
|||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
send_text(Socket, Text) ->
|
send_text(#state{socket = Socket, encoding = Encoding}, Text) ->
|
||||||
CText = iconv:convert("utf-8", ?IRC_ENCODING, lists:flatten(Text)),
|
CText = iconv:convert("utf-8", Encoding, lists:flatten(Text)),
|
||||||
%io:format("IRC OUTu: ~s~nIRC OUTk: ~s~n", [Text, CText]),
|
%io:format("IRC OUTu: ~s~nIRC OUTk: ~s~n", [Text, CText]),
|
||||||
gen_tcp:send(Socket, CText).
|
gen_tcp:send(Socket, CText).
|
||||||
|
|
||||||
send_element(Socket, El) ->
|
|
||||||
send_text(Socket, xml:element_to_string(El)).
|
|
||||||
|
|
||||||
%send_queue(Socket, Q) ->
|
%send_queue(Socket, Q) ->
|
||||||
% case queue:out(Q) of
|
% case queue:out(Q) of
|
||||||
@ -474,11 +458,11 @@ route_nick(Pid, Nick, Packet) ->
|
|||||||
Pid ! {route_nick, Nick, Packet}.
|
Pid ! {route_nick, Nick, Packet}.
|
||||||
|
|
||||||
|
|
||||||
process_lines([S]) ->
|
process_lines(Encoding, [S]) ->
|
||||||
S;
|
S;
|
||||||
process_lines([S | Ss]) ->
|
process_lines(Encoding, [S | Ss]) ->
|
||||||
self() ! {ircstring, iconv:convert(?IRC_ENCODING, "utf-8", S)},
|
self() ! {ircstring, iconv:convert(Encoding, "utf-8", S)},
|
||||||
process_lines(Ss).
|
process_lines(Encoding, Ss).
|
||||||
|
|
||||||
process_channel_list(StateData, Items) ->
|
process_channel_list(StateData, Items) ->
|
||||||
process_channel_list_find_chan(StateData, Items).
|
process_channel_list_find_chan(StateData, Items).
|
||||||
@ -580,7 +564,7 @@ process_privmsg(StateData, Nick, From, String) ->
|
|||||||
process_version(StateData, Nick, From) ->
|
process_version(StateData, Nick, From) ->
|
||||||
[FromUser | _] = string:tokens(From, "!"),
|
[FromUser | _] = string:tokens(From, "!"),
|
||||||
send_text(
|
send_text(
|
||||||
StateData#state.socket,
|
StateData,
|
||||||
io_lib:format("NOTICE ~s :\001VERSION "
|
io_lib:format("NOTICE ~s :\001VERSION "
|
||||||
"ejabberd IRC transport ~s (c) Alexey Shchepin"
|
"ejabberd IRC transport ~s (c) Alexey Shchepin"
|
||||||
"\001\r\n",
|
"\001\r\n",
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
-define(NS_VERSION, "jabber:iq:version").
|
-define(NS_VERSION, "jabber:iq:version").
|
||||||
-define(NS_TIME, "jabber:iq:time").
|
-define(NS_TIME, "jabber:iq:time").
|
||||||
-define(NS_XDATA, "jabber:x:data").
|
-define(NS_XDATA, "jabber:x:data").
|
||||||
|
-define(NS_IQDATA, "jabber:iq:data").
|
||||||
-define(NS_DELAY, "jabber:x:delay").
|
-define(NS_DELAY, "jabber:x:delay").
|
||||||
-define(NS_EVENT, "jabber:x:event").
|
-define(NS_EVENT, "jabber:x:event").
|
||||||
-define(NS_STATS, "http://jabber.org/protocol/stats").
|
-define(NS_STATS, "http://jabber.org/protocol/stats").
|
||||||
|
Loading…
Reference in New Issue
Block a user