rotbot.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #! /usr/bin/env python
  2. import sys, random, string, ssl
  3. import irc.bot#, irc.strings
  4. from irc.client import ip_numstr_to_quad#, ip_quad_to_numstr
  5. from postgres import Postgres
  6. import commands.public, commands.admin, commands.games, commands.statistics
  7. import events.on_join, events.on_kick, events.on_pubmsg
  8. from common.networkservices import NickServ
  9. from common import log
  10. bold = "\x02"
  11. italic = "\x1D"
  12. underline = "\x1F"
  13. reverse = "\x16" # swap background and foreground colors ("reverse video")
  14. reset = "\x0F"
  15. blue = "\x0302"
  16. green = "\x0303"
  17. red = "\x0304"
  18. grey = "\x0314"
  19. class PyRot(irc.bot.SingleServerIRCBot):
  20. def __init__(self, network, db, homechannel, nickname, username, password, host, port=6667, usessl=False, cmdchar="!", helpchar="@"):
  21. self.network = network
  22. self.db = db
  23. self.homechannel = homechannel
  24. self.password = password
  25. self.cmdchar = cmdchar
  26. self.helpchar = helpchar
  27. if usessl:
  28. factory = irc.connection.Factory(wrapper=ssl.wrap_socket)
  29. else:
  30. factory = irc.connection.Factory()
  31. print("Starting pyRot, the third RotBot by tBkwtWS.")
  32. log.info("Connecting to " + host + ":" + str(port) + "/" + self.homechannel)
  33. try:
  34. irc.bot.SingleServerIRCBot.__init__(self, [(host, port)], nickname, username, connect_factory=factory)
  35. except irc.client.ServerConnectionError:
  36. sys.stderr.write(sys.exc_info()[1])
  37. # Events.
  38. def on_nicknameinuse(self, connection, event):
  39. log.info("Nickname in use, attempting to recover: " + connection.nickname)
  40. connection.nick(connection.nickname + ''.join(random.choice(string.digits) for _ in range(3))) # Take temporary nick. Without this recovering via NickServ won't work.
  41. NickServ.recover_nick(connection, self.password)
  42. def on_welcome(self, connection, event):
  43. log.info(event) # Handy for debugging. Keep this.
  44. if self.password: # Id with NickServ
  45. connection.privmsg("NickServ", "identify " + connection.nickname + " " + self.password) # Identify with NickServ.
  46. channels = self.db.all("SELECT name FROM channels WHERE network='" + self.network + "' AND autojoin=True")
  47. connection.join(self.homechannel)
  48. for channel in channels: # Join channels with autojoin function.
  49. connection.join(channel)
  50. connection.join(self.homechannel)
  51. def on_error(self, connection, event):
  52. log.notice(event)
  53. connection.privmsg(self.homechannel, "ERROR: " + event)
  54. def on_nick(self, connection, event):
  55. if event.source.nick == connection.nickname: # If the nick boing changes is the bots prefered nickname.
  56. log.info("Assuming original nick.")
  57. NickServ.recover_nick(connection, self.password)
  58. def on_join(self, connection, event):
  59. log.info(event)
  60. events.on_join.process_event(self, connection, event)
  61. def on_kick(self, connection, event):
  62. log.info(event)
  63. events.on_kick.process_event(self, connection, event)
  64. def on_mode(self, connection, event):
  65. log.info(event)
  66. def on_part(self, connection, event):
  67. log.info(event)
  68. def on_quit(self, connection, event):
  69. log.info(event)
  70. def on_invite(self, connection, event):
  71. log.info(event)
  72. def on_topic(self, connection, event):
  73. log.info(event)
  74. def on_pubmsg(self, connection, event):
  75. commands.public.do_command(self, connection, event)
  76. commands.admin.do_command(self, connection, event)
  77. commands.statistics.do_command(self, connection, event)
  78. try:
  79. games = self.db.one("SELECT games FROM channels WHERE name='" + event.target + "' AND network='" + self.network + "'")
  80. except:
  81. pass
  82. if games:
  83. commands.games.do_command(self, connection, event)
  84. events.on_pubmsg.process_event(self, connection, event)
  85. def on_pubnotice(self, connection, event):
  86. log.info(event)
  87. def on_privmsg(self, connection, event):
  88. log.info(event)
  89. commands.public.do_command(self, connection, event)
  90. commands.admin.do_command(self, connection, event)
  91. commands.statistics.do_command(self, connection, event)
  92. commands.games.do_command(self, connection, event)
  93. def on_privnotice(self, connection, event):
  94. log.info(event)
  95. commands.public.do_command(self, connection, event)
  96. commands.admin.do_command(self, connection, event)
  97. commands.statistics.do_command(self, connection, event)
  98. commands.games.do_command(self, connection, event)
  99. if event.source.nick == NickServ and event.arguments[0].startswith("This nickname is registered"):
  100. connection.privmsg("NickServ", "identify " + connection.nickname + " " + connection.password) # Identify with NickServ.
  101. def on_action(self, connection, event):
  102. log.info(event)
  103. # DCC stuff from originalexample file.
  104. def on_dccmsg(self, c, e):
  105. log.info(e)
  106. # non-chat DCC messages are raw bytes; decode as text
  107. text = e.arguments[0].decode('utf-8')
  108. c.privmsg("You said: " + text)
  109. def on_dccchat(self, c, e):
  110. log.info(e)
  111. if len(e.arguments) != 2:
  112. return
  113. args = e.arguments[1].split()
  114. if len(args) == 4:
  115. try:
  116. address = ip_numstr_to_quad(args[2])
  117. port = int(args[3])
  118. except ValueError:
  119. return
  120. self.dcc_connect(address, port)
  121. def main():
  122. # Check system arguments.
  123. if len(sys.argv) != 2:
  124. print(sys.argv)
  125. print("Usage: rotbot <server ID from database>")
  126. sys.exit(1)
  127. instance = sys.argv[1] # Instance is the database network id.
  128. # Database.
  129. db = Postgres("postgres://pyRot:4h8q(.@localhost/pyRot")
  130. # Get network from database.
  131. try:
  132. network = db.one("SELECT * FROM networks WHERE id=" + str(instance))
  133. except:
  134. print("Invalid network ID.")
  135. sys.exit(1)
  136. if not network:
  137. print("Invalid network ID.")
  138. sys.exit(1)
  139. bot = PyRot(network.name, db, network.home_channel, network.nickname, network.username, network.password, network.host, network.port, network.use_ssl, network.command_character, network.help_character)
  140. bot.start()
  141. if __name__ == "__main__":
  142. try:
  143. main()
  144. except KeyboardInterrupt:
  145. log.info('Interrupted by keyboard.')
  146. sys.exit(0)