2013-12-22 01:03:18 +01:00
# Import some necessary libraries.
import socket
import time
2014-01-11 02:19:10 +01:00
import csv
2014-01-12 01:29:39 +01:00
import string
2013-12-22 02:53:58 +01:00
import Queue
2013-12-22 04:31:39 +01:00
import random
2013-12-22 02:53:58 +01:00
from threading import Thread
2014-03-10 02:01:05 +01:00
from re import search
2013-12-22 01:03:18 +01:00
# Some basic variables used to configure the bot
2014-01-11 02:19:10 +01:00
server = " irc.freenode.net "
channel = " #openhatch "
botnick = " WelcomeBot "
2014-01-11 16:30:43 +01:00
waitTime = 60 # Amount of time after joining before bot replies to someone
2013-12-22 02:53:58 +01:00
# Classes
2013-12-22 01:03:18 +01:00
class newcomer ( object ) : # Newcomer class created when someone joins the room
2014-01-11 02:19:10 +01:00
def __init__ ( self , nick ) :
self . nick = nick
self . born = time . time ( )
self . status = 0
2013-12-22 01:03:18 +01:00
2014-01-11 06:50:13 +01:00
def updateStatus ( self ) :
self . status = 1
2013-12-22 01:03:18 +01:00
2014-01-11 02:19:10 +01:00
def aroundFor ( self ) :
2014-01-11 06:50:13 +01:00
return int ( time . time ( ) - self . born )
# Functions!
def joinchan ( chan ) : # Joins channels
2014-01-30 21:20:41 +01:00
ircsock . send ( " JOIN " + chan + " \n " )
2014-01-11 06:50:13 +01:00
def getIRC ( ) : # Creates separate thread for reading messages from the server
while True :
ircmsg = ircsock . recv ( 2048 ) # receive data from the server
ircmsg = ircmsg . strip ( ' \n \r ' ) # removing any unnecessary linebreaks.
q . put ( ircmsg ) # Put in queue for main loop to read
print ( ircmsg )
2013-12-22 02:53:58 +01:00
def ping ( ) : # Responds to server Pings.
2014-01-11 02:19:10 +01:00
ircsock . send ( " PONG :pingis \n " )
2013-12-22 01:03:18 +01:00
2014-01-30 21:20:41 +01:00
def hello ( actor , greeting , chan = channel ) : # This function responds to a user that inputs "Hello Mybot"
ircsock . send ( " PRIVMSG " + chan + " : " + greeting + " " + actor + " \n " )
2013-12-22 01:03:18 +01:00
2014-01-26 23:32:33 +01:00
def help ( actor , chan = channel ) : # This function explains what the bot is when queried.
2014-04-23 16:47:32 +02:00
ircsock . send ( " PRIVMSG " + chan + " :I ' m a bot! I ' m from here: <https://github.com/shaunagm/oh-irc-bot>. You can change my behavior by submitting a pull request or by talking to shauna. \n " )
2013-12-22 04:31:39 +01:00
def welcome ( newcomer ) : # This welcomes a specific person.
2014-01-30 21:20:41 +01:00
ircsock . send ( " PRIVMSG " + channel + " :Welcome " + newcomer + " ! The channel ' s pretty quiet right now, so I thought I ' d say hello, and ping some people (like shauna, paulproteus, marktraceur) that you ' re here. If no one responds for a while, try emailing us at hello@openhatch.org or just coming back later. FYI, you ' re now on my list of known nicknames, so I won ' t bother you again. \n " )
2014-01-11 02:19:10 +01:00
def makeNickArray ( ) : # On startup, makes array of nicks from Nicks.txt. New info will be written to both array and txt file.
nickArray = [ ]
with open ( ' nicks.csv ' , ' rb ' ) as csvfile :
nicksData = csv . reader ( csvfile , delimiter = ' , ' , quotechar = ' | ' )
for row in nicksData :
nickArray . append ( row )
2014-01-11 06:50:13 +01:00
return nickArray
2014-01-11 02:19:10 +01:00
2014-01-11 06:50:13 +01:00
def addPerson ( person ) : # Adds newcomer to list of known nicks
2014-01-12 01:29:39 +01:00
person = person . replace ( " _ " , " " )
nickArray . append ( [ person ] )
2014-01-11 06:50:13 +01:00
with open ( ' nicks.csv ' , ' a ' ) as csvfile :
2014-01-11 02:19:10 +01:00
nickwriter = csv . writer ( csvfile , delimiter = ' , ' , quotechar = ' | ' , quoting = csv . QUOTE_MINIMAL )
nickwriter . writerow ( [ person ] )
2013-12-22 01:03:18 +01:00
2014-03-10 02:01:05 +01:00
def getWelcomeRegEx ( stringArray ) :
#make regex case-insenstive
pattern = r ' (?i) '
for s in stringArray :
pattern + = r ' (?:[ :] ' + s + r ' (?:[ \ .! \ ?, \ )]|$))| '
#delete trailing '|'
pattern = pattern [ : - 1 ]
return pattern
2014-01-11 06:50:13 +01:00
# Startup
ircsock = socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
ircsock . connect ( ( server , 6667 ) ) # Here we connect to the server using the port 6667
2014-01-30 21:20:41 +01:00
ircsock . send ( " USER " + botnick + " " + botnick + " " + botnick + " :This is http://openhatch.org/ ' s greeter bot. \n " ) # user authentication
ircsock . send ( " NICK " + botnick + " \n " ) # here we actually assign the nick to the bot
2014-01-11 06:50:13 +01:00
joinchan ( channel )
# Starts a separate thread to get messages from server
q = Queue . LifoQueue ( )
t = Thread ( target = getIRC ) # calls getIRC() (defined above) in a separate thread
t . daemon = True
t . start ( )
nickArray = makeNickArray ( )
2013-12-22 01:03:18 +01:00
2014-01-11 02:19:10 +01:00
newList = [ ] # This is the array of newcomer objects that people who join the room are added to.
2014-03-10 02:01:05 +01:00
helloArray = [ r ' hello ' , r ' hi ' , r ' hey ' , r ' yo ' , r ' sup ' ]
helpArray = [ r ' help ' , r ' info ' , r ' faq ' , r ' explain yourself ' ]
helloPattern = getWelcomeRegEx ( helloArray )
helpPattern = getWelcomeRegEx ( helpArray )
2013-12-22 01:03:18 +01:00
2014-01-11 06:50:13 +01:00
while 1 : # Loop forever
2013-12-22 01:03:18 +01:00
2014-01-11 06:50:13 +01:00
for i in newList :
if i . status == 0 and i . aroundFor ( ) > waitTime :
2014-01-11 02:19:10 +01:00
welcome ( i . nick )
2014-01-11 06:50:13 +01:00
i . updateStatus ( )
addPerson ( i . nick )
2014-01-11 16:30:43 +01:00
newList . remove ( i )
2014-01-11 06:50:13 +01:00
if q . empty ( ) == 0 :
ircmsg = q . get ( )
actor = ircmsg . split ( " : " ) [ 1 ] . split ( " ! " ) [ 0 ]
# Welcome functions
2014-01-30 21:20:41 +01:00
if ircmsg . find ( " PRIVMSG " + channel ) != - 1 : # If someone has spoken into the channel
2014-01-11 06:50:13 +01:00
for i in newList :
if actor != i . nick : # Don't turn off response if the person speaking is the person who joined.
i . updateStatus ( ) # Sets status to 1
addPerson ( i . nick )
2014-01-11 16:30:43 +01:00
newList . remove ( i )
2014-01-11 06:50:13 +01:00
## Else: Do we want to do something extra if the person who joined the chat says something with no response?
2014-01-30 21:20:41 +01:00
if ircmsg . find ( " JOIN " + channel ) != - 1 : # If someone joins #channel
2014-01-11 06:50:13 +01:00
if actor != botnick : # Remove the case where the bot gets a message that the bot has joined.
2014-01-12 01:29:39 +01:00
if [ actor . replace ( " _ " , " " ) ] not in nickArray :
2014-01-11 16:30:43 +01:00
if actor not in ( i . nick for i in newList ) :
newList . append ( newcomer ( actor ) )
2014-01-11 06:50:13 +01:00
2014-01-30 21:20:41 +01:00
if ircmsg . find ( " PART " + channel ) != - 1 or ircmsg . find ( " QUIT " ) != - 1 : # If someone parts or quits the #channel
for i in newList : # And that person is on the newlist (has entered channel within last 60 seconds)
if actor == i . nick :
newList . remove ( i ) # Remove them from the list
2014-01-11 06:50:13 +01:00
# Unwelcome functions
2014-01-26 23:32:33 +01:00
if ircmsg . find ( botnick ) != - 1 and ircmsg . find ( " PRIVMSG " ) != - 1 : # If someone talks to (or refers to) the bot
chan = channel
2014-03-10 02:01:05 +01:00
matchHello = search ( helloPattern , ircmsg )
matchHelp = search ( helpPattern , ircmsg )
2014-01-26 23:32:33 +01:00
if ircmsg . find ( " PRIVMSG " + botnick ) != - 1 :
chan = actor
2014-03-10 02:01:05 +01:00
if matchHello :
2014-01-26 23:32:33 +01:00
hello ( actor , random . choice ( helloArray ) , chan )
2014-03-10 02:01:05 +01:00
if matchHelp :
2014-01-26 23:32:33 +01:00
help ( actor , chan )
2014-01-11 06:50:13 +01:00
if ircmsg . find ( " PING : " ) != - 1 : # if the server pings us then we've got to respond!
ping ( )
2013-12-22 01:03:18 +01:00