From 696d02539915e1eca7b882f63fef970be0b6cd5a Mon Sep 17 00:00:00 2001 From: Matt Mullins Date: Thu, 19 May 2011 18:00:45 -0500 Subject: [PATCH] Finished writing the buffering/parsing code for handling messages from the IRC server --- irc/irc_conn.erl | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) 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. -- 2.11.0