📄 mod_irc_connection.erl
字号:
%%%----------------------------------------------------------------------%%% File : mod_irc_connection.erl%%% Author : Alexey Shchepin <alexey@sevcom.net>%%% Purpose : %%% Created : 15 Feb 2003 by Alexey Shchepin <alexey@sevcom.net>%%% Id : $Id: mod_irc_connection.erl,v 1.20 2004/08/02 22:17:05 aleksey Exp $%%%-----------------------------------------------------------------------module(mod_irc_connection).-author('alexey@sevcom.net').-vsn('$Revision: 1.20 $ ').-behaviour(gen_fsm).%% External exports-export([start/5, receiver/2, route_chan/4, route_nick/3]).%% gen_fsm callbacks-export([init/1, open_socket/2, wait_for_registration/2, stream_established/2, handle_event/3, handle_sync_event/4, handle_info/3, terminate/3, code_change/4]).-include("ejabberd.hrl").-include("jlib.hrl").-define(SETS, gb_sets).-record(state, {socket, encoding, receiver, queue, user, myname, server, nick, channels = dict:new(), inbuf = "", outbuf = ""}).%-define(DBGFSM, true).-ifdef(DBGFSM).-define(FSMOPTS, [{debug, [trace]}]).-else.-define(FSMOPTS, []).-endif.%%%----------------------------------------------------------------------%%% API%%%----------------------------------------------------------------------start(From, Host, Server, Username, Encoding) -> gen_fsm:start(?MODULE, [From, Host, Server, Username, Encoding], ?FSMOPTS).%%%----------------------------------------------------------------------%%% Callback functions from gen_fsm%%%----------------------------------------------------------------------%%----------------------------------------------------------------------%% Func: init/1%% Returns: {ok, StateName, StateData} |%% {ok, StateName, StateData, Timeout} |%% ignore |%% {stop, StopReason} %%----------------------------------------------------------------------init([From, Host, Server, Username, Encoding]) -> gen_fsm:send_event(self(), init), {ok, open_socket, #state{queue = queue:new(), encoding = Encoding, user = From, nick = Username, myname = Host, server = Server}}.%%----------------------------------------------------------------------%% Func: StateName/2%% Returns: {next_state, NextStateName, NextStateData} |%% {next_state, NextStateName, NextStateData, Timeout} |%% {stop, Reason, NewStateData} %%----------------------------------------------------------------------open_socket(init, StateData) -> Addr = StateData#state.server, Port = 6667, ?DEBUG("connecting to ~s:~p~n", [Addr, Port]), case gen_tcp:connect(Addr, Port, [binary, {packet, 0}]) of {ok, Socket} -> NewStateData = StateData#state{socket = Socket}, send_text(NewStateData, io_lib:format("NICK ~s\r\n", [StateData#state.nick])), send_text(NewStateData, io_lib:format( "USER ~s ~s ~s :~s\r\n", [StateData#state.nick, StateData#state.nick, StateData#state.myname, StateData#state.nick])), send_text(NewStateData, io_lib:format("CODEPAGE ~s\r\n", [StateData#state.encoding])), {next_state, wait_for_registration, NewStateData}; {error, Reason} -> ?DEBUG("connect return ~p~n", [Reason]), Text = case Reason of timeout -> "Server Connect Timeout"; _ -> "Server Connect Failed" end, bounce_messages(Text), {stop, normal, StateData} end.wait_for_registration(closed, StateData) -> {stop, normal, StateData}.stream_established({xmlstreamend, Name}, StateData) -> {stop, normal, StateData};stream_established(timeout, StateData) -> {stop, normal, StateData};stream_established(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}.code_change(OldVsn, StateName, StateData, Extra) -> {ok, StateName, StateData}.-define(SEND(S), if StateName == stream_established -> send_text(StateData, S), StateData; true -> StateData#state{outbuf = StateData#state.outbuf ++ S} end).%%----------------------------------------------------------------------%% Func: handle_info/3%% Returns: {next_state, NextStateName, NextStateData} |%% {next_state, NextStateName, NextStateData, Timeout} |%% {stop, Reason, NewStateData} %%----------------------------------------------------------------------handle_info({route_chan, Channel, Resource, {xmlelement, "presence", Attrs, Els}}, StateName, StateData) -> NewStateData = case xml:get_attr_s("type", Attrs) of "unavailable" -> S1 = ?SEND(io_lib:format("PART #~s\r\n", [Channel])), S1#state{channels = dict:erase(Channel, S1#state.channels)}; "subscribe" -> StateData; "subscribed" -> StateData; "unsubscribe" -> StateData; "unsubscribed" -> StateData; "error" -> stop; _ -> Nick = case Resource of "" -> StateData#state.nick; _ -> Resource end, S1 = ?SEND(io_lib:format("NICK ~s\r\n" "JOIN #~s\r\n", [Nick, Channel])), case dict:is_key(Channel, S1#state.channels) of true -> S1#state{nick = Nick}; _ -> S1#state{nick = Nick, channels = dict:store(Channel, ?SETS:new(), S1#state.channels)} end end, if NewStateData == stop -> {stop, normal, StateData}; true -> case length(dict:fetch_keys(NewStateData#state.channels)) of 0 -> {stop, normal, NewStateData}; _ -> {next_state, StateName, NewStateData} end end;handle_info({route_chan, Channel, Resource, {xmlelement, "message", Attrs, Els} = El}, StateName, StateData) -> NewStateData = case xml:get_attr_s("type", Attrs) of "groupchat" -> case xml:get_path_s(El, [{elem, "subject"}, cdata]) of "" -> ejabberd_router:route( jlib:make_jid( lists:concat( [Channel, "%", StateData#state.server]), StateData#state.myname, StateData#state.nick), StateData#state.user, El), Body = xml:get_path_s(El, [{elem, "body"}, cdata]), case Body of "/quote " ++ Rest -> ?SEND(Rest ++ "\r\n"); _ -> Body1 = case Body of [$/, $m, $e, $ | Rest] -> "\001ACTION " ++ Rest ++ "\001"; _ -> Body end, Strings = string:tokens(Body1, "\n"), Res = lists:concat( lists:map( fun(S) -> io_lib:format( "PRIVMSG #~s :~s\r\n", [Channel, S]) end, Strings)), ?SEND(Res) end; Subject -> Strings = string:tokens(Subject, "\n"), Res = lists:concat( lists:map( fun(S) -> io_lib:format("TOPIC #~s :~s\r\n", [Channel, S]) end, Strings)), ?SEND(Res) end; "chat" -> Body = xml:get_path_s(El, [{elem, "body"}, cdata]), case Body of "/quote " ++ Rest -> ?SEND(Rest ++ "\r\n"); _ -> Body1 = case Body of [$/, $m, $e, $ | Rest] -> "\001ACTION " ++ Rest ++ "\001"; _ -> Body end, Strings = string:tokens(Body1, "\n"), Res = lists:concat( lists:map( fun(S) -> io_lib:format("PRIVMSG ~s :~s\r\n", [Resource, S]) end, Strings)), ?SEND(Res) end; "error" -> stop; _ -> StateData end, if NewStateData == stop -> {stop, normal, StateData}; true -> {next_state, StateName, NewStateData} end;handle_info({route_chan, Channel, Resource, {xmlelement, "iq", Attrs, Els} = El}, StateName, StateData) -> From = StateData#state.user, To = jlib:make_jid(lists:concat([Channel, "%", StateData#state.server]), StateData#state.myname, StateData#state.nick), case jlib:iq_query_info(El) of #iq{xmlns = ?NS_MUC_ADMIN} = IQ -> iq_admin(StateData, Channel, From, To, IQ); #iq{xmlns = ?NS_VERSION} -> Res = io_lib:format("PRIVMSG ~s :\001VERSION\001\r\n", [Resource]), ?SEND(Res), Err = jlib:make_error_reply( El, ?ERR_FEATURE_NOT_IMPLEMENTED), ejabberd_router:route(To, From, Err); #iq{xmlns = ?NS_TIME} -> Res = io_lib:format("PRIVMSG ~s :\001TIME\001\r\n", [Resource]), ?SEND(Res), Err = jlib:make_error_reply( El, ?ERR_FEATURE_NOT_IMPLEMENTED), ejabberd_router:route(To, From, Err); #iq{} -> Err = jlib:make_error_reply( El, ?ERR_FEATURE_NOT_IMPLEMENTED), ejabberd_router:route(To, From, Err); _ -> ok end, {next_state, StateName, StateData};handle_info({route_chan, Channel, Resource, Packet}, StateName, StateData) -> {next_state, StateName, StateData};handle_info({route_nick, Nick, {xmlelement, "message", Attrs, Els} = El}, StateName, StateData) -> NewStateData = case xml:get_attr_s("type", Attrs) of "chat" -> Body = xml:get_path_s(El, [{elem, "body"}, cdata]), case Body of "/quote " ++ Rest -> ?SEND(Rest ++ "\r\n"); _ -> Body1 = case Body of [$/, $m, $e, $ | Rest] -> "\001ACTION " ++ Rest ++ "\001"; _ -> Body end, Strings = string:tokens(Body1, "\n"),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -