-
Notifications
You must be signed in to change notification settings - Fork 1
/
MrRoboto.rb
198 lines (122 loc) · 6.14 KB
/
MrRoboto.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
require 'socket'
require './commands.rb'
class MrRoboto
#This is just the connection info that gets passed when we create our new bot object
def initialize(server, port, nick, startchan)
@server = server
@port = port
@nick = nick
@startchan = startchan
end
#this method just does the connecting by sending raw IRC commands
def connect()
@stream = TCPSocket.open(@server, @port)
@stream.puts("NICK #{@nick}")
@stream.puts("USER #{@nick} 8 * :#{@nick}")
@stream.puts("JOIN #{@startchan}")
# Rescue if we can't connect to the irc server
rescue SystemCallError => e
puts "\nError: Cannot connect to server!"
puts
exit
end
def joinChannel(channel)
@stream.puts("JOIN #{channel}")
end
# After several revision i decided it would be much easier to have a method parse everything and then set instance
# variables accordingly
def parseStream(inputStream)
# First we take the input stream from the event handler and split it by : to remove the colons at the beginning
# and end of a raw irc string
parsedColon = inputStream.split(":") if inputStream.is_a?(String)
# Here as it turns out the last part of our parsed string is the acutal message inputted by the users. So we store
# This in an instance variable for the whole object to use
#@parsedMsg = parsedColon.last
# We also avoid issues with MOTD's having more than 1 : in them by checking to see if our message
# that is parsed contains 2 or more elemnts, if it does ignore the first 2 elements (0 and 1)
# and split on the 2nd element and then join the rest
# back into a single string, Otherwise just accept the last element that's parsed. I am using [2..-1] which
#basically says to select everything starting at the 2nd element up to the last element
@parsedMsg = parsedColon.size > 2 ? parsedColon[2..-1].join(":") : parsedColon.last
# Now we need to extract the first element which will be our bot command. Then we take anything after the command as
# bot command argument, so we split it based on the command itself (in this case the first word in the @parsedMsg
cmdParse = @parsedMsg.split
@botCmd = cmdParse[0]
# store the bot command temporarily and split it up by whitespace so we can sanitize input
# This checks to see if the first parsed letter is a ! and the next is a blank space , which really
# says "is this ONLY a ! " OR this checks that if the first char in the cmmand is ! and any other
# char's after the first matches a !
if (@botCmd[0,1] == "!" && @botCmd[1,1] == "") || (@botCmd[0,1] == "!" && @botCmd[1..-1] =~ /!/)
# Invalid command, set @botCmd to nothing
puts "Invalid Command"
@botCmd = ""
else
# looks like valid input, lets continue and parse the args out of the parsed message
botCmdArgsSplit = @parsedMsg.split(@parsedMsg.split.first)
@botCmdArgs = botCmdArgsSplit[1].strip
# This might be a bit odd, but we need to strip the ! out of it so we then later send a message to the commands class
@botCmdToSend = @botCmd.split("!").last
@botCmdToSend = @botCmdToSend.strip if @botCmdToSend.is_a?(String)
end
# The 2nd element in our parsing contians one long string of a nick!host Message Type Nick or Channel so we store it
# for parsing
nickHostMsgChan = parsedColon[1]
# Now that we have nickHostMsgChan in one string, we parse it by the space as this is the seperator for the majority of it
parsedSpace = nickHostMsgChan.split
# This only happens every so often, but we need to see if the first element is a PING message and if it is we set a flag
# Denoting it's a ping message and then store the :server portion for later PONG usage
if parsedColon[0].strip == "PING"
@isPing = true
@pongServ = ":#{parsedColon[1]}"
else
#We can store the message type here (if it's PRIVMSG , NOTICE, ..etc)
@isPing = false
@msgType = parsedSpace[1]
end
# This is neat because we can determine later if it's a channel (by the presence of a #) or if it's a nickname
@nickOrChan = parsedSpace[2]
# What's left now is the nick!host portion that we store for further parsing
hostNick = parsedSpace[0]
# To get the nick by itself, we need to parse at the exclamation point in the raw irc message
parsedEpt = hostNick.split("!")
# We now store the nick as a instance variable for the whole object to use
@streamNick = parsedEpt[0]
end # end of method
def eventHandler(s)
#Put output to screen
eventStream = s.gets
puts eventStream
# Here we call the parser above and prase out each line to see what it is, and we can then peform logic on the instance
# variables it sets later
parseStream(eventStream)
#create a new object for the bot commands and makes it dynamic. If the parsed secion (stored in @nickOrChan) is the same nick as the bot, then that means it's a private message to the bot, so create a new bot object accordingly to respond to the private message. Otherwise it's a channel stream so output stuff to the channel.
if @nickOrChan == @nick
botCommands = BotCommands.new(s, @streamNick, @streamNick)
else
botCommands = BotCommands.new(s, @nickOrChan, @streamNick)
end
# Is the ping flag set? that means we have a ping message, so let's reply accordingly
if @isPing == true
botCommands.send(:ping, @pongServ)
end
# This has a nasty bug when ! is the only char in the stream it dies
if @botCmd.include?("!")
# Test to see if our object responds to the parsed method name, if so send it!
if botCommands.respond_to?(@botCmdToSend)
botCommands.send(@botCmdToSend, @botCmdArgs)
else
# Make sure we send it to the correct destination (channel or private msg)
if @nickOrChan == @nick
@stream.puts("PRIVMSG #{@streamNick} :#{@botCmd} command not found.")
else
@stream.puts("PRIVMSG #{@nickOrChan} :#{@botCmd} command not found.")
end
end
end
end
def run()
while true
eventHandler(@stream)
end
end
end