diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/exirc/client.ex | 22 | ||||
-rw-r--r-- | lib/exirc/commands.ex | 45 | ||||
-rw-r--r-- | lib/exirc/example_handler.ex | 4 | ||||
-rw-r--r-- | lib/exirc/utils.ex | 17 |
4 files changed, 61 insertions, 27 deletions
diff --git a/lib/exirc/client.ex b/lib/exirc/client.ex index 0cd92fd..d569486 100644 --- a/lib/exirc/client.ex +++ b/lib/exirc/client.ex @@ -104,6 +104,13 @@ defmodule ExIrc.Client do :gen_server.call(client, {:msg, type, nick, msg}, :infinity) end @doc """ + Send an action message, i.e. (/me slaps someone with a big trout) + """ + @spec me(client :: pid, channel :: binary, msg :: binary) :: :ok | {:error, atom} + def me(client, channel, msg) do + :gen_server.call(client, {:me, channel, msg}, :infinity) + end + @doc """ Change the client's nick """ @spec nick(client :: pid, new_nick :: binary) :: :ok | {:error, atom} @@ -330,6 +337,12 @@ defmodule ExIrc.Client do send! state.socket, data {:reply, :ok, state} end + # Handle /me messages + def handle_call({:me, channel, msg}, _from, state) do + data = me!(channel, msg) + send! state.socket, data + {:reply, :ok, state} + end # Handles call to join a channel def handle_call({:join, channel, key}, _from, state) do send!(state.socket, join!(channel, key)); {:reply, :ok, state} end # Handles a call to leave a channel @@ -418,10 +431,9 @@ defmodule ExIrc.Client do debug? = state.debug? case Utils.parse(data) do %IrcMessage{:ctcp => true} = msg -> - send_event msg, state + handle_data msg, state {:noreply, state} %IrcMessage{:ctcp => false} = msg -> - send_event msg, state handle_data msg, state %IrcMessage{:ctcp => :invalid} = msg when debug? -> send_event msg, state @@ -610,6 +622,12 @@ defmodule ExIrc.Client do end {:noreply, state} end + # Called when someone uses ACTION, i.e. `/me dies` + def handle_data(%IrcMessage{:nick => from, :cmd => "ACTION", :args => [channel, message]} = _msg, state) do + if state.debug?, do: debug "* #{from} #{message} in #{channel}" + send_event {:me, message, from, channel}, state + {:noreply, state} + end # Called any time we receive an unrecognized message def handle_data(msg, state) do if state.debug? do debug "UNRECOGNIZED MSG: #{msg.cmd}"; IO.inspect(msg) end diff --git a/lib/exirc/commands.ex b/lib/exirc/commands.ex index 0d3862e..6f2d385 100644 --- a/lib/exirc/commands.ex +++ b/lib/exirc/commands.ex @@ -165,6 +165,7 @@ defmodule Irc.Commands do ############ # Helpers ############ + @ctcp_delimiter <<0x01>> @doc """ Send data to a TCP socket. @@ -181,64 +182,72 @@ defmodule Irc.Commands do @doc """ Builds a valid IRC command. """ - def command!(cmd) when is_list(cmd), do: [cmd, '\r\n'] - def command!(cmd) when is_binary(cmd), do: command! String.to_char_list(cmd) + def command!(cmd), do: [cmd, '\r\n'] @doc """ Builds a valid CTCP command. """ - def ctcp!(cmd), do: [1, '#{cmd}', 1] + def ctcp!(cmd), do: command! [@ctcp_delimiter, cmd, @ctcp_delimiter] + def ctcp!(cmd, args) do + expanded = args |> Enum.intersperse(' ') + command! [@ctcp_delimiter, cmd, expanded, @ctcp_delimiter] + end # IRC Commands @doc """ Send password to server """ - def pass!(pwd), do: command! ['PASS ', '#{pwd}'] + def pass!(pwd), do: command! ['PASS ', pwd] @doc """ Send nick to server. (Changes or sets your nick) """ - def nick!(nick), do: command! ['NICK ', '#{nick}'] + def nick!(nick), do: command! ['NICK ', nick] @doc """ Send username to server. (Changes or sets your username) """ def user!(user, name) do - command! ['USER ', '#{user}', ' 0 * :', '#{name}'] + command! ['USER ', user, ' 0 * :', name] end @doc """ Send PONG in response to PING """ - def pong1!(nick), do: command! ['PONG ', '#{nick}'] + def pong1!(nick), do: command! ['PONG ', nick] @doc """ Send a targeted PONG in response to PING """ - def pong2!(nick, to), do: command! ['PONG ', '#{nick}', ' ', '#{to}'] + def pong2!(nick, to), do: command! ['PONG ', nick, ' ', to] @doc """ Send message to channel or user """ - def privmsg!(nick, msg), do: command! ['PRIVMSG ', '#{nick}', ' :', '#{msg}'] + def privmsg!(nick, msg), do: command! ['PRIVMSG ', nick, ' :', msg] + @doc """ + Send a `/me <msg>` CTCP command to t + """ + def me!(channel, msg), do: command! ['PRIVMSG ', channel, ' :', @ctcp_delimiter, 'ACTION ', msg, @ctcp_delimiter] @doc """ Send notice to channel or user """ - def notice!(nick, msg), do: command! ['NOTICE ', '#{nick}', ' :', '#{msg}'] + def notice!(nick, msg), do: command! ['NOTICE ', nick, ' :', msg] @doc """ Send join command to server (join a channel) """ - def join!(channel, key \\ ""), do: command! ['JOIN ', '#{channel}', ' ', '#{key}'] + def join!(channel), do: command! ['JOIN ', channel] + def join!(channel, key), do: command! ['JOIN ', channel, ' ', key] @doc """ Send part command to server (leave a channel) """ - def part!(channel), do: command! ['PART ', '#{channel}'] + def part!(channel), do: command! ['PART ', channel] @doc """ Send quit command to server (disconnect from server) """ - def quit!(msg \\ "Leaving"), do: command! ['QUIT :', '#{msg}'] + def quit!(msg \\ "Leaving"), do: command! ['QUIT :', msg] @doc """ Send kick command to server """ def kick!(channel, nick, message \\ "") do case "#{message}" |> String.length do - 0 -> command! ['KICK ', '#{channel}', ' ', '#{nick}'] - _ -> command! ['KICK ', '#{channel}', ' ', '#{nick}', ' ', '#{message}'] + 0 -> command! ['KICK ', channel, ' ', nick] + _ -> command! ['KICK ', channel, ' ', nick, ' ', message] end end @doc """ @@ -248,15 +257,15 @@ defmodule Irc.Commands do """ def mode!(channel_or_nick, flags, args \\ "") do case "#{args}" |> String.length do - 0 -> command! ['MODE ', '#{channel_or_nick}', ' ', '#{flags}'] - _ -> command! ['MODE ', '#{channel_or_nick}', ' ', '#{flags}', ' ', '#{args}'] + 0 -> command! ['MODE ', channel_or_nick, ' ', flags] + _ -> command! ['MODE ', channel_or_nick, ' ', flags, ' ', args] end end @doc """ Send an invite command """ def invite!(nick, channel) do - command! ['INVITE ', '#{nick}', ' ', '#{channel}'] + command! ['INVITE ', nick, ' ', channel] end end diff --git a/lib/exirc/example_handler.ex b/lib/exirc/example_handler.ex index bd3f142..4bc8e8c 100644 --- a/lib/exirc/example_handler.ex +++ b/lib/exirc/example_handler.ex @@ -99,6 +99,10 @@ defmodule ExampleHandler do debug "#{from} mentioned us in #{channel}: #{message}" {:noreply, nil} end + def handle_info({:me, message, from, channel}, _state) do + debug "* #{from} #{message} in #{channel}" + {:noreply, nil} + end # This is an example of how you can manually catch commands if ExIrc.Client doesn't send a specific message for it def handle_info(%IrcMessage{:nick => from, :cmd => "PRIVMSG", :args => ["testnick", msg]}, _state) do debug "Received a private message from #{from}: #{msg}" diff --git a/lib/exirc/utils.ex b/lib/exirc/utils.ex index c46f648..3221956 100644 --- a/lib/exirc/utils.ex +++ b/lib/exirc/utils.ex @@ -44,14 +44,17 @@ defmodule ExIrc.Utils do get_cmd([cmd, arg1, [1 | ctcp_trail] | restargs], msg) end - defp get_cmd([cmd, _arg1, [1 | ctcp_trail] | restargs], msg) when cmd == 'PRIVMSG' or cmd == 'NOTICE' do - args = ctcp_trail ++ for arg <- restargs, do: ' ' ++ arg - |> Enum.flatten - |> Enum.reverse + defp get_cmd([cmd, target, [1 | ctcp_cmd] | cmd_args], msg) when cmd == 'PRIVMSG' or cmd == 'NOTICE' do + args = cmd_args + |> Enum.map(&Enum.take_while(&1, fn c -> c != ?\001 end)) + |> Enum.map(&List.to_string/1) case args do - [1 | ctcp_rev] -> - [ctcp_cmd | args] = ctcp_rev |> Enum.reverse |> :string.tokens(' ') - %{msg | :cmd => to_string(ctcp_cmd), :args => args, :ctcp => true} + args when args != [] -> + %{msg | + :cmd => to_string(ctcp_cmd), + :args => [to_string(target), args |> Enum.join(" ")], + :ctcp => true + } _ -> %{msg | :cmd => to_string(cmd), :ctcp => :invalid} end |