diff options
Diffstat (limited to 'lib/exirc/client.ex')
-rw-r--r-- | lib/exirc/client.ex | 111 |
1 files changed, 64 insertions, 47 deletions
diff --git a/lib/exirc/client.ex b/lib/exirc/client.ex index 4c49106..4dd4d25 100644 --- a/lib/exirc/client.ex +++ b/lib/exirc/client.ex @@ -1,15 +1,15 @@ -defmodule ExIrc.Client do +defmodule ExIRC.Client do @moduledoc """ Maintains the state and behaviour for individual IRC client connections """ - use Irc.Commands + use ExIRC.Commands use GenServer - import ExIrc.Logger + import ExIRC.Logger - alias ExIrc.Channels - alias ExIrc.Utils - alias ExIrc.SenderInfo - alias ExIrc.Client.Transport + alias ExIRC.Channels + alias ExIRC.Utils + alias ExIRC.SenderInfo + alias ExIRC.Client.Transport # Client internal state defmodule ClientState do @@ -310,7 +310,7 @@ defmodule ExIrc.Client do autoping: autoping, logged_on?: false, debug?: debug, - channels: ExIrc.Channels.init(), + channels: ExIRC.Channels.init(), owner: {owner, ref}}} end @doc """ @@ -503,12 +503,12 @@ defmodule ExIrc.Client do def handle_info({:tcp, _, data}, state) do debug? = state.debug? case Utils.parse(data) do - %IrcMessage{ctcp: true} = msg -> + %ExIRC.Message{ctcp: true} = msg -> handle_data msg, state {:noreply, state} - %IrcMessage{ctcp: false} = msg -> + %ExIRC.Message{ctcp: false} = msg -> handle_data msg, state - %IrcMessage{ctcp: :invalid} = msg when debug? -> + %ExIRC.Message{ctcp: :invalid} = msg when debug? -> send_event msg, state {:noreply, state} _ -> @@ -552,22 +552,23 @@ defmodule ExIrc.Client do ################ @doc """ - Handle IrcMessages received from the server. + Handle ExIRC.Messages received from the server. """ # Called upon successful login - def handle_data(%IrcMessage{cmd: @rpl_welcome}, %ClientState{logged_on?: false} = state) do + def handle_data(%ExIRC.Message{cmd: @rpl_welcome}, %ClientState{logged_on?: false} = state) do if state.debug?, do: debug "SUCCESFULLY LOGGED ON" new_state = %{state | logged_on?: true, login_time: :erlang.timestamp()} send_event :logged_in, new_state {:noreply, new_state} end # Called when the server sends it's current capabilities - def handle_data(%IrcMessage{cmd: @rpl_isupport} = msg, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_isupport} = msg, state) do if state.debug?, do: debug "RECEIVING SERVER CAPABILITIES" {:noreply, Utils.isup(msg.args, state)} end # Called when the client enters a channel - def handle_data(%IrcMessage{nick: nick, cmd: "JOIN"} = msg, %ClientState{nick: nick} = state) do + + def handle_data(%ExIRC.Message{nick: nick, cmd: "JOIN"} = msg, %ClientState{nick: nick} = state) do channel = msg.args |> List.first |> String.trim if state.debug?, do: debug "JOINED A CHANNEL #{channel}" channels = Channels.join(state.channels, channel) @@ -576,7 +577,7 @@ defmodule ExIrc.Client do {:noreply, new_state} end # Called when another user joins a channel the client is in - def handle_data(%IrcMessage{nick: user_nick, cmd: "JOIN", host: host, user: user} = msg, state) do + def handle_data(%ExIRC.Message{nick: user_nick, cmd: "JOIN", host: host, user: user} = msg, state) do sender = %SenderInfo{nick: user_nick, host: host, user: user} channel = msg.args |> List.first |> String.trim if state.debug?, do: debug "ANOTHER USER JOINED A CHANNEL: #{channel} - #{user_nick}" @@ -591,7 +592,7 @@ defmodule ExIrc.Client do # Message with a single argument is not RFC compliant, but is present # to handle poorly written IRC servers which send RPL_TOPIC with an empty # topic (such as Slack's IRC bridge), when they should be sending RPL_NOTOPIC - def handle_data(%IrcMessage{cmd: @rpl_topic} = msg, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_topic} = msg, state) do {channel, topic} = case msg.args do [_nick, channel, topic] -> {channel, topic} [channel, topic] -> {channel, topic} @@ -611,61 +612,69 @@ defmodule ExIrc.Client do ## WHOIS - def handle_data(%IrcMessage{cmd: @rpl_whoisuser, args: [_sender, nickname, username, hostname, _, realname]}, state) do + + def handle_data(%ExIRC.Message{cmd: @rpl_whoisuser, args: [_sender, nickname, username, hostname, _, realname]}, state) do + user = %{nickname: nickname, username: username, hostname: hostname, realname: realname} {:noreply, %ClientState{state|whois_buffers: Map.put(state.whois_buffers, nickname, user)}} end - def handle_data(%IrcMessage{cmd: @rpl_whoiscertfp, args: [_sender, nickname, "has client certificate fingerprint "<> fingerprint]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_whoiscertfp, args: [_sender, nickname, "has client certificate fingerprint "<> fingerprint]}, state) do {:noreply, %ClientState{state|whois_buffers: put_in(state.whois_buffers, [nickname, :certfp], fingerprint)}} end - def handle_data(%IrcMessage{cmd: @rpl_whoisregnick, args: [_sender, nickname, _message]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_whoisregnick, args: [_sender, nickname, _message]}, state) do {:noreply, %ClientState{state|whois_buffers: put_in(state.whois_buffers, [nickname, :registered_nick?], true)}} end - def handle_data(%IrcMessage{cmd: @rpl_whoishelpop, args: [_sender, nickname, _message]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_whoishelpop, args: [_sender, nickname, _message]}, state) do {:noreply, %ClientState{state|whois_buffers: put_in(state.whois_buffers, [nickname, :helpop?], true)}} end - def handle_data(%IrcMessage{cmd: @rpl_whoischannels, args: [_sender, nickname, channels]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_whoischannels, args: [_sender, nickname, channels]}, state) do + chans = String.split(channels, " ") {:noreply, %ClientState{state|whois_buffers: put_in(state.whois_buffers, [nickname, :channels], chans)}} end - def handle_data(%IrcMessage{cmd: @rpl_whoisserver, args: [_sender, nickname, server_addr, server_name]}, state) do + + def handle_data(%ExIRC.Message{cmd: @rpl_whoisserver, args: [_sender, nickname, server_addr, server_name]}, state) do + new_buffer = state.whois_buffers |> put_in([nickname, :server_name], server_name) |> put_in([nickname, :server_address], server_addr) {:noreply, %ClientState{state|whois_buffers: new_buffer}} end - def handle_data(%IrcMessage{cmd: @rpl_whoisoperator, args: [_sender, nickname, _message]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_whoisoperator, args: [_sender, nickname, _message]}, state) do {:noreply, %ClientState{state|whois_buffers: put_in(state.whois_buffers, [nickname, :ircop?], true)}} end - def handle_data(%IrcMessage{cmd: @rpl_whoisaccount, args: [_sender, nickname, account_name, _message]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_whoisaccount, args: [_sender, nickname, account_name, _message]}, state) do {:noreply, %ClientState{state|whois_buffers: put_in(state.whois_buffers, [nickname, :account_name], account_name)}} end - def handle_data(%IrcMessage{cmd: @rpl_whoissecure, args: [_sender, nickname, _message]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_whoissecure, args: [_sender, nickname, _message]}, state) do {:noreply, %ClientState{state|whois_buffers: put_in(state.whois_buffers, [nickname, :tls?], true)}} end - def handle_data(%IrcMessage{cmd: @rpl_whoisidle, args: [_sender, nickname, idling_time, signon_time, _message]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_whoisidle, args: [_sender, nickname, idling_time, signon_time, _message]}, state) do + new_buffer = state.whois_buffers |> put_in([nickname, :idling_time], idling_time) |> put_in([nickname, :signon_time], signon_time) {:noreply, %ClientState{state|whois_buffers: new_buffer}} end - def handle_data(%IrcMessage{cmd: @rpl_endofwhois, args: [_sender, nickname, _message]}, state) do - buffer = struct(Irc.Whois, state.whois_buffers[nickname]) + def handle_data(%ExIRC.Message{cmd: @rpl_endofwhois, args: [_sender, nickname, _message]}, state) do + buffer = struct(ExIRC.Whois, state.whois_buffers[nickname]) + send_event {:whois, buffer}, state {:noreply, %ClientState{state|whois_buffers: Map.delete(state.whois_buffers, nickname)}} end - def handle_data(%IrcMessage{cmd: @rpl_notopic, args: [channel]}, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_notopic, args: [channel]}, state) do + if state.debug? do debug "INITIAL TOPIC MSG" debug "1. NO TOPIC SET FOR #{channel}}" @@ -675,7 +684,7 @@ defmodule ExIrc.Client do {:noreply, new_state} end # Called when the topic changes while we're in the channel - def handle_data(%IrcMessage{cmd: "TOPIC", args: [channel, topic]}, state) do + def handle_data(%ExIRC.Message{cmd: "TOPIC", args: [channel, topic]}, state) do if state.debug?, do: debug "TOPIC CHANGED FOR #{channel} TO #{topic}" channels = Channels.set_topic(state.channels, channel, topic) new_state = %{state | channels: channels} @@ -683,7 +692,7 @@ defmodule ExIrc.Client do {:noreply, new_state} end # Called when joining a channel with the list of current users in that channel, or when the NAMES command is sent - def handle_data(%IrcMessage{cmd: @rpl_namereply} = msg, state) do + def handle_data(%ExIRC.Message{cmd: @rpl_namereply} = msg, state) do if state.debug?, do: debug "NAMES LIST RECEIVED" {_nick, channel_type, channel, names} = case msg.args do [nick, channel_type, channel, names] -> {nick, channel_type, channel, names} @@ -699,14 +708,14 @@ defmodule ExIrc.Client do {:noreply, %{state | channels: channels}} end # Called when our nick has succesfully changed - def handle_data(%IrcMessage{cmd: "NICK", nick: nick, args: [new_nick]}, %ClientState{nick: nick} = state) do + def handle_data(%ExIRC.Message{cmd: "NICK", nick: nick, args: [new_nick]}, %ClientState{nick: nick} = state) do if state.debug?, do: debug "NICK CHANGED FROM #{nick} TO #{new_nick}" new_state = %{state | nick: new_nick} send_event {:nick_changed, new_nick}, new_state {:noreply, new_state} end # Called when someone visible to us changes their nick - def handle_data(%IrcMessage{cmd: "NICK", nick: nick, args: [new_nick]}, state) do + def handle_data(%ExIRC.Message{cmd: "NICK", nick: nick, args: [new_nick]}, state) do if state.debug?, do: debug "#{nick} CHANGED THEIR NICK TO #{new_nick}" channels = Channels.user_rename(state.channels, nick, new_nick) new_state = %{state | channels: channels} @@ -714,13 +723,15 @@ defmodule ExIrc.Client do {:noreply, new_state} end # Called upon mode change - def handle_data(%IrcMessage{cmd: "MODE", args: [channel, op, user]}, state) do + def handle_data(%ExIRC.Message{cmd: "MODE", args: [channel, op, user]}, state) do if state.debug?, do: debug "MODE #{channel} #{op} #{user}" send_event {:mode, [channel, op, user]}, state {:noreply, state} end # Called when we leave a channel - def handle_data(%IrcMessage{cmd: "PART", nick: nick} = msg, %ClientState{nick: nick} = state) do + + def handle_data(%ExIRC.Message{cmd: "PART", nick: nick} = msg, %ClientState{nick: nick} = state) do + channel = msg.args |> List.first |> String.trim if state.debug?, do: debug "WE LEFT A CHANNEL: #{channel}" channels = Channels.part(state.channels, channel) @@ -729,7 +740,7 @@ defmodule ExIrc.Client do {:noreply, new_state} end # Called when someone else in our channel leaves - def handle_data(%IrcMessage{cmd: "PART", nick: from, host: host, user: user} = msg, state) do + def handle_data(%ExIRC.Message{cmd: "PART", nick: from, host: host, user: user} = msg, state) do sender = %SenderInfo{nick: from, host: host, user: user} channel = msg.args |> List.first |> String.trim if state.debug?, do: debug "#{from} LEFT A CHANNEL: #{channel}" @@ -738,7 +749,7 @@ defmodule ExIrc.Client do send_event {:parted, channel, sender}, new_state {:noreply, new_state} end - def handle_data(%IrcMessage{cmd: "QUIT", nick: from, host: host, user: user} = msg, state) do + def handle_data(%ExIRC.Message{cmd: "QUIT", nick: from, host: host, user: user} = msg, state) do sender = %SenderInfo{nick: from, host: host, user: user} reason = msg.args |> List.first if state.debug?, do: debug "#{from} QUIT" @@ -748,10 +759,10 @@ defmodule ExIrc.Client do {:noreply, new_state} end # Called when we receive a PING - def handle_data(%IrcMessage{cmd: "PING"} = msg, %ClientState{autoping: true} = state) do + def handle_data(%ExIRC.Message{cmd: "PING"} = msg, %ClientState{autoping: true} = state) do if state.debug?, do: debug "RECEIVED A PING!" case msg do - %IrcMessage{args: [from]} -> + %ExIRC.Message{args: [from]} -> if state.debug?, do: debug("SENT PONG2") Transport.send(state, pong2!(from, msg.server)) _ -> @@ -761,35 +772,39 @@ defmodule ExIrc.Client do {:noreply, state}; end # Called when we are invited to a channel - def handle_data(%IrcMessage{cmd: "INVITE", args: [nick, channel], nick: by, host: host, user: user} = msg, %ClientState{nick: nick} = state) do + def handle_data(%ExIRC.Message{cmd: "INVITE", args: [nick, channel], nick: by, host: host, user: user} = msg, %ClientState{nick: nick} = state) do sender = %SenderInfo{nick: by, host: host, user: user} if state.debug?, do: debug "RECEIVED AN INVITE: #{msg.args |> Enum.join(" ")}" send_event {:invited, sender, channel}, state {:noreply, state} end # Called when we are kicked from a channel - def handle_data(%IrcMessage{cmd: "KICK", args: [channel, nick, reason], nick: by, host: host, user: user} = _msg, %ClientState{nick: nick} = state) do + + def handle_data(%ExIRC.Message{cmd: "KICK", args: [channel, nick, reason], nick: by, host: host, user: user} = _msg, %ClientState{nick: nick} = state) do + sender = %SenderInfo{nick: by, host: host, user: user} if state.debug?, do: debug "WE WERE KICKED FROM #{channel} BY #{by}" send_event {:kicked, sender, channel, reason}, state {:noreply, state} end # Called when someone else was kicked from a channel - def handle_data(%IrcMessage{cmd: "KICK", args: [channel, nick, reason], nick: by, host: host, user: user} = _msg, state) do + + def handle_data(%ExIRC.Message{cmd: "KICK", args: [channel, nick, reason], nick: by, host: host, user: user} = _msg, state) do + sender = %SenderInfo{nick: by, host: host, user: user} if state.debug?, do: debug "#{nick} WAS KICKED FROM #{channel} BY #{by}" send_event {:kicked, nick, sender, channel, reason}, state {:noreply, state} end # Called when someone sends us a message - def handle_data(%IrcMessage{nick: from, cmd: "PRIVMSG", args: [nick, message], host: host, user: user} = _msg, %ClientState{nick: nick} = state) do + def handle_data(%ExIRC.Message{nick: from, cmd: "PRIVMSG", args: [nick, message], host: host, user: user} = _msg, %ClientState{nick: nick} = state) do sender = %SenderInfo{nick: from, host: host, user: user} if state.debug?, do: debug "#{from} SENT US #{message}" send_event {:received, message, sender}, state {:noreply, state} end # Called when someone sends a message to a channel we're in, or a list of users - def handle_data(%IrcMessage{nick: from, cmd: "PRIVMSG", args: [to, message], host: host, user: user} = _msg, %ClientState{nick: nick} = state) do + def handle_data(%ExIRC.Message{nick: from, cmd: "PRIVMSG", args: [to, message], host: host, user: user} = _msg, %ClientState{nick: nick} = state) do sender = %SenderInfo{nick: from, host: host, user: user} if state.debug?, do: debug "#{from} SENT #{message} TO #{to}" send_event {:received, message, sender, to}, state @@ -798,14 +813,16 @@ defmodule ExIrc.Client do {:noreply, state} end # Called when someone uses ACTION, i.e. `/me dies` - def handle_data(%IrcMessage{nick: from, cmd: "ACTION", args: [channel, message], host: host, user: user} = _msg, state) do + def handle_data(%ExIRC.Message{nick: from, cmd: "ACTION", args: [channel, message], host: host, user: user} = _msg, state) do sender = %SenderInfo{nick: from, host: host, user: user} if state.debug?, do: debug "* #{from} #{message} in #{channel}" send_event {:me, message, sender, channel}, state {:noreply, state} end + # Called when a NOTICE is received by the client. - def handle_data(%IrcMessage{nick: from, cmd: "NOTICE", args: [_target, message], host: host, user: user} = _msg, state) do + def handle_data(%ExIRC.Message{nick: from, cmd: "NOTICE", args: [_target, message], host: host, user: user} = _msg, state) do + sender = %SenderInfo{nick: from, host: host, user: user} |