From: Matt Mullins Date: Thu, 19 May 2011 23:00:45 +0000 (-0500) Subject: Finished writing the buffering/parsing code for handling messages from the IRC server X-Git-Tag: v4~13 X-Git-Url: http://git.mmlx.us/?a=commitdiff_plain;h=696d02539915e1eca7b882f63fef970be0b6cd5a;p=erlbot.git Finished writing the buffering/parsing code for handling messages from the IRC server --- diff --git a/irc/irc_conn.erl b/irc/irc_conn.erl index 3af4399..ab7c6ed 100644 --- a/irc/irc_conn.erl +++ b/irc/irc_conn.erl @@ -49,8 +49,32 @@ handle_cast({send_command, Command}, State) -> ), {noreply, State}. -handle_info(_Message, _State) -> - {noreply, _State}. +%% Handle incoming data +handle_info({tcp, _Socket, Data}, State = #irc_state{ socket = _Socket }) -> + Buf1 = State#irc_state.buffer ++ Data, + Buf2 = case parse_lines(Buf1) of + {ok, Lines, Rem} -> + lists:foreach(fun do_line/1, Lines), + Rem; + none -> + Buf1 + end, + {noreply, State#irc_state{buffer = Buf2}}. + +%% @doc Handles a line received from the IRC server. +do_line(Line) -> + Command = irc_util:list_to_command(Line), + case Command#irc_command.command of + "PING" -> + error_logger:info_msg("Received a PING from server ~p~n", [Line]), + % return the command to the IRC server with a PONG + % leaving the rest of the line (usually a timestamp) alone + NewCommand = Command#irc_command{prefix = none, command = "PONG"}, + send_command(NewCommand); + _ -> + % for now, just know that it happened + error_logger:info_msg("Received a line ~p~n", [Line]) + end. terminate(_Reason, _State) -> ok. @@ -64,3 +88,27 @@ send_command(Command) -> join_channel(Channel) -> Command = #irc_command{command = "JOIN", middles = [Channel]}, send_command(Command). + +%% @doc Splits a buffer into full lines, keeping whatever is left over +%% Returns either {ok, [Line], Remaining} or none. +parse_lines(Buffer) -> + % "if" would be more appropriate here, but I can't use member() in a guard + case lists:member($\n, Buffer) of + true -> + {Line, RHS} = lists:splitwith( + fun (Char) -> (Char /= $\n) and (Char /= $\r) end, + Buffer), + Rem = case RHS of + "\r\n" ++ Rest -> Rest; % Strip off CR+LF, as specified by RFC + "\n" ++ Rest -> Rest % Accept simple LF separators too + % If the RHS doesn't contain a newline, then crash, because + % something is horribly wrong. + end, + % recurse and put together the results + case parse_lines(Rem) of + {ok, Lines, FinalRem} -> {ok, [Line|Lines], FinalRem}; + none -> {ok, [Line], Rem} + end; + false -> + none + end.