),
{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.
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.