From c8e512baf5c28696cf3935ce148083cedb9ca4c8 Mon Sep 17 00:00:00 2001 From: href Date: Sat, 9 Jan 2021 15:58:59 +0100 Subject: Some fixes --- lib/irc/connection.ex | 63 ++++++++++++++++++++++++++++++++------------------ lib/irc/parser/line.ex | 11 ++++++++- lib/irc/shout.ex | 6 ++--- 3 files changed, 54 insertions(+), 26 deletions(-) diff --git a/lib/irc/connection.ex b/lib/irc/connection.ex index 7b82cea..23eee3f 100644 --- a/lib/irc/connection.ex +++ b/lib/irc/connection.ex @@ -340,7 +340,7 @@ defmodule Irc.Connection do {:ok, args} <- process_args(args), backoff <- :backoff.init(backoff_min, backoff_max) do - {tls, sts, port} = case {args.sts, Irc.STS.lookup(args.host, args.port)} do + {tls, sts, port} = case {args.sts, Irc.STS.lookup(args.host)} do {true, {:ok, port}} -> {true, true, port} _ -> {args.tls, false, args.port} end @@ -429,13 +429,15 @@ defmodule Irc.Connection do end # multiline capab - def cap_ls(:info, {_, _, %Line{command: "CAP", args: [_, "LS", "*", rest]}}, data) do + def cap_ls(:info, {_, _, %Line{command: "CAP", args: [_, "LS", "*", rest]} = line}, data) do + Logger.debug "#{inspect(data)} <<< #{inspect(line)}" capabs = Map.merge(data.server_capabs, Parser.Capabs.parse(rest)) {:keep_state, %State{data | server_capabs: capabs, cap_302: true}, {:state_timeout, @reply_timeout, nil}} end # end of multiline or no multiline indicator - def cap_ls(:info, {_, _, %Line{command: "CAP", args: [_, "LS", rest]}}, data) do + def cap_ls(:info, {_, _, %Line{command: "CAP", args: [_, "LS", rest]} = line}, data) do + Logger.debug "#{inspect(data)} <<< #{inspect(line)}" capabs = Map.merge(data.server_capabs, Parser.Capabs.parse(rest)) if data.cap_302 do {:next_state, :cap_sts, %State{data | server_capabs: capabs}, @internal} @@ -461,7 +463,7 @@ defmodule Irc.Connection do @doc false def cap_sts(:internal, _, data = %{args: %{sts: true}, sts: false, port: current_port, server_capabs: %{"sts" => policy = %{"port" => sts_port}}}) when current_port != sts_port do - socksend(data, Line.new("QUIT", ["Following STS policy."])) + socksend(data, Line.new("QUIT", ["Reconnecting following STS policy."])) ConnectionSocket.close(data.socket) {:next_state, :connect, %State{data | sts: true, port: sts_port, tls: true, socket: nil}, @internal} end @@ -497,7 +499,8 @@ defmodule Irc.Connection do {:next_state, :reg_nick, data, @internal} end - def reg_pass(:info, {_, _, %Line{command: err_PASSWDMISMATCH()}}, data) do + def reg_pass(:info, {_, _, %Line{command: err_PASSWDMISMATCH()}} = line, data) do + Logger.debug "#{inspect(data)} <<< #{inspect(line)}" {:next_state, :error, {:invalid_password, data.args.pass}} end @@ -519,12 +522,14 @@ defmodule Irc.Connection do end end - def reg_nick(:info, {_, _, %Line{command: cmd}}, data) when cmd in [err_NICKNAMEINUSE(), err_NICKCOLLISION() ]do + def reg_nick(:info, {_, _, %Line{command: cmd}} = line, data) when cmd in [err_NICKNAMEINUSE(), err_NICKCOLLISION() ]do + Logger.debug "#{inspect(data)} <<< #{inspect(line)}" new_nick = data.args.nick <> to_string(:random.uniform(9999)) {:keep_state, data, {:next_event, :internal, new_nick}} end def reg_nick(:info, {_, _, line = %Line{command: cmd}}, data) when cmd in [err_ERRONEUSNICKNAME(), err_NONICKNAMEGIVEN()] do + Logger.debug "#{inspect(data)} <<< #{inspect(line)}" {:next_state, :error, data, {:next_event, :internal, {:invalid_nickname, data.args.nick, line}}} end @@ -564,9 +569,11 @@ defmodule Irc.Connection do req = Enum.filter(client_capabs, fn(capab) -> Map.has_key?(server_capabs, capab) end) |> Enum.uniq() |> Enum.join(" ") - case socksend(data, Line.new("CAP", args: ["REQ", req])) do - :ok -> {:next_state, :cap_wait_ack, data} - error -> to_disconnected(error, data) + case socksend(data, Line.new("CAP", ["REQ", req])) do + :ok -> + {:next_state, :cap_wait_ack, data} + error -> + to_disconnected(error, data) end end @@ -583,12 +590,14 @@ defmodule Irc.Connection do # FIXME: Support multiline ACK/NACK ??? # TODO: VERIFY SPEC CONFORMITY - def cap_wait_ack(:info, {_, _, %Line{command: "CAP", args: [_, "ACK", capabs]}}, data) do + def cap_wait_ack(:info, {_, _, %Line{command: "CAP", args: [_, "ACK", capabs]} = line}, data) do + Logger.debug "#{inspect(data)} <<< #{inspect(line)}" capabs = String.split(capabs, " ") {:keep_state, %State{data | capabs: capabs}, {:next_event, :internal, :end}} end - def cap_wait_ack(:info, {_, _, %Line{command: "CAP", args: [_, "NACK", capabs]}}, data) do + def cap_wait_ack(:info, {_, _, %Line{command: "CAP", args: [_, "NACK", capabs]} = line}, data) do + Logger.debug "#{inspect(data)} <<< #{inspect(line)}" capabs = String.split(capabs, " ") {:keep_state, %State{data | capabs: data.capabs -- capabs}, {:next_event, :internal, :end}} end @@ -612,12 +621,14 @@ defmodule Irc.Connection do end def welcome(:info, {_, _, l = %Line{command: rpl_WELCOME(), source: source, args: [nick, _]}}, data) do + Logger.debug "#{inspect(data)} <<< #{inspect(l)}" {:keep_state, %State{data | nick: nick, welcome: [l | data.welcome], server: source}, {:state_timeout, @reply_timeout, nil}} end @welcome_numeric [rpl_WELCOME, rpl_YOURHOST, rpl_CREATED, rpl_MYINFO, rpl_ISUPPORT] def welcome(:info, {_, _, l = %Line{command: rpl_MYINFO(), source: source, args: [_, _, version, umodes, cmodes | rest]}}, data) do + Logger.debug "#{inspect(data)} <<< #{inspect(l)}" cmodes_with_params = case rest do [] -> nil [c] -> c @@ -627,7 +638,8 @@ defmodule Irc.Connection do {:keep_state, data, {:state_timeout, @reply_timeout, nil}} end - def welcome(:info, {_, _, %Line{command: rpl_ISUPPORT(), args: [_ | isupport]}}, data) do + def welcome(:info, {_, _, %Line{command: rpl_ISUPPORT(), args: [_ | isupport]} = line}, data) do + Logger.debug "#{inspect(data)} <<< #{inspect(line)}" supports = Irc.Parser.Isupport.parse(isupport, data.isupport) {:keep_state, %State{data | isupport: supports}, {:state_timeout, @reply_timeout, nil}} end @@ -652,20 +664,23 @@ defmodule Irc.Connection do {:keep_state_and_data, {:state_timeout, @reply_timeout, nil}} end - def motd(:info, {_, _, %Line{command: err_NOMOTD()}}, data) do + def motd(:info, {_, _, %Line{command: err_NOMOTD()} = line}, data) do + Logger.debug "#{inspect(data)} <<< #{inspect(line)}" {:next_state, :registered, %State{data | motd: []}} end - def motd(:info, {_, _, %Line{command: rpl_MOTDSTART(), args: [_, line]}}, data) do + def motd(:info, {_, _, %Line{command: rpl_MOTDSTART(), args: [_, line]} = line}, data) do + Logger.debug "#{inspect(data)} <<< #{inspect(line)}" {:keep_state, %State{data | motd: [line]}, {:state_timeout, @reply_timeout, nil}} end - def motd(:info, {_, _, %Line{command: rpl_MOTD(), args: [_, line]}}, data) do - {:keep_state, %State{data | motd: [line | data.motd]}, {:state_timeout, @reply_timeout, nil}} + def motd(:info, {_, _, %Line{command: rpl_MOTD(), args: [_, motd_line]} = line}, data) do + {:keep_state, %State{data | motd: [motd_line | data.motd]}, {:state_timeout, @reply_timeout, nil}} end - def motd(:info, {_, _, %Line{command: rpl_ENDOFMOTD(), args: [_, line]}}, data) do - {:next_state, :registered, %State{data | motd: List.reverse([line | data.motd])}} + def motd(:info, {_, _, %Line{command: rpl_ENDOFMOTD(), args: [_, motd_line]} = line}, data) do + Logger.debug "#{inspect(data)} <<< #{inspect(line)}" + {:next_state, :registered, %State{data | motd: Enum.reverse([motd_line | data.motd])}} end def motd(:state_timeout, _, data) do @@ -728,7 +743,7 @@ defmodule Irc.Connection do end def registered(:state_timeout, :ping, data) do - case socksend(data, [?P, ?I, ?N, ?G, 0x20, String.to_charlist(data.server)]) do + case socksend(data, [?P, ?I, ?N, ?G, 0x20, String.to_charlist(data.server.server)]) do :ok -> {:keep_state_and_data, @conn_pong_timeout} error -> to_disconnected(error, data) end @@ -763,7 +778,7 @@ defmodule Irc.Connection do to_disconnected({:irc_error, Enum.join(args, " ")}, data) end - def process_line(%Line{command: "PONG", args: [server | _]}, data = %{server: server}) do + def process_line(%Line{command: "PONG", source: server}, data = %{server: server}) do {:keep_state_and_data, @conn_ping_timeout} end @@ -964,8 +979,8 @@ defmodule Irc.Connection do @doc false def terminate(reason, state, data) do - if state.socket do - ConnectionSocket.close(state.socket) + if data.socket do + ConnectionSocket.close(data.socket) end unless data.errored do send(data.process, {:irc_conn_error, self(), :down}) @@ -1019,6 +1034,8 @@ defmodule Irc.Connection do capabs = Map.get(args, :capabs) || [] reconnect = Map.get(args, :reconnect, true) batch = Map.get(args, :batch, true) + sasl = Map.get(args, :sasl, false) + echo = Map.get(args, :echo, true) connect_opts = Map.get(args, :connect_opts) || [] with \ @@ -1038,6 +1055,8 @@ defmodule Irc.Connection do pass: pass, reconnect: reconnect, batch: batch, + sasl: sasl, + echo: echo, connect_opts: connect_opts, connect_timeout: connect_timeout }} diff --git a/lib/irc/parser/line.ex b/lib/irc/parser/line.ex index 5aa5a9b..48ddd9c 100644 --- a/lib/irc/parser/line.ex +++ b/lib/irc/parser/line.ex @@ -242,5 +242,14 @@ defmodule Irc.Parser.Line do end end -end + defimpl Inspect, for: __MODULE__ do + @moduledoc false + import Inspect.Algebra + def inspect(struct, _opts) do + tags = Enum.map(struct.tags, fn({k, v}) -> concat([k, "=", v]) end) |> Enum.join(",") + Enum.join(["#IRC.Line<", struct.source, " ", struct.command, " ", inspect(struct.args), " (", tags, ")>"], "") + end + end + +end diff --git a/lib/irc/shout.ex b/lib/irc/shout.ex index 8a3966b..912517c 100644 --- a/lib/irc/shout.ex +++ b/lib/irc/shout.ex @@ -12,9 +12,9 @@ defmodule Irc.Shout do def do_shout({:ok, conn}, target, message, opts) do mon = Process.monitor(conn) result = with \ - {:ok, _info} <- Connection.await_up(conn, Keyword.get(opts, :await_up_timeout)), - :ok <- join(conn, target), - :ok <- Connection.sendline(conn, ['PRIVMSG ', target, ' :', message]) + {_, {:ok, _info}} <- {:await_up, Connection.await_up(conn, Keyword.get(opts, :await_up_timeout))}, + {_, :ok} <- {:join, join(conn, target)}, + {_, :ok} <- {:send, Connection.sendline(conn, ['PRIVMSG ', target, ' :', message])} do :ok else -- cgit v1.2.3