rotbot.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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_welcome, events.on_join, events.on_kick, events.on_mode, events.on_pubmsg, events.on_action, events.on_whoreply, events.on_nick
  8. from common import log
  9. from common.networkservices import NickServ
  10. class PyRot(irc.bot.SingleServerIRCBot):
  11. def __init__(self, network, db, homechannel, nickname, username, password, host, port=6667, usessl=False, cmdchar="!", helpchar="@"):
  12. self.network = network
  13. self.db = db
  14. self.homechannel = homechannel
  15. self.password = password
  16. self.cmdchar = cmdchar
  17. self.helpchar = helpchar
  18. self.protectees = {}
  19. self.channelkeys = {}
  20. if usessl:
  21. factory = irc.connection.Factory(wrapper=ssl.wrap_socket)
  22. else:
  23. factory = irc.connection.Factory()
  24. print("Starting pyRot, the third RotBot by tBkwtWS.")
  25. log.info("Connecting to " + host + ":" + str(port) + "/" + self.homechannel)
  26. try:
  27. irc.bot.SingleServerIRCBot.__init__(self, [(host, port)], nickname, username, connect_factory=factory)
  28. except irc.client.ServerConnectionError:
  29. sys.stderr.write(sys.exc_info()[1])
  30. # Events.
  31. def on_nicknameinuse(self, connection, event):
  32. log.info("Nickname in use, attempting to recover: " + connection.nickname)
  33. connection.nick(connection.nickname + ''.join(random.choice(string.digits) for _ in range(3))) # Take temporary nick. Without this recovering via NickServ won't work.
  34. NickServ.recover_nick(connection, self.password)
  35. def on_welcome(self, connection, event):
  36. events.on_welcome.process_event(self, connection, event)
  37. def on_error(self, connection, event):
  38. log.notice(event)
  39. connection.privmsg(self.homechannel, "ERROR: " + event)
  40. def on_nick(self, connection, event):
  41. events.on_nick.process_event(self, connection, event)
  42. def on_join(self, connection, event):
  43. events.on_join.process_event(self, connection, event)
  44. def on_kick(self, connection, event):
  45. events.on_kick.process_event(self, connection, event)
  46. def on_mode(self, connection, event):
  47. events.on_mode.process_event(self, connection, event)
  48. def on_part(self, connection, event):
  49. # Update protectees
  50. if event.target == self.homechannel and event.source.nick in self.protectees: # Protectee parted home channel.
  51. del self.protectees[event.source.nick] # Delete from protectees.
  52. def on_quit(self, connection, event):
  53. # Update protectees
  54. if event.source.nick in self.protectees: # Protectee parted home channel.
  55. del self.protectees[event.source.nick] # Delete from protectees.
  56. def on_invite(self, connection, event):
  57. log.info(event)
  58. def on_topic(self, connection, event):
  59. log.info(event)
  60. def on_pubmsg(self, connection, event):
  61. commands.public.do_command(self, connection, event)
  62. commands.admin.do_command(self, connection, event)
  63. commands.statistics.do_command(self, connection, event)
  64. commands.games.do_command(self, connection, event)
  65. events.on_pubmsg.process_event(self, connection, event)
  66. def on_privmsg(self, connection, event):
  67. log.info(event)
  68. commands.public.do_command(self, connection, event)
  69. commands.admin.do_command(self, connection, event)
  70. commands.statistics.do_command(self, connection, event)
  71. commands.games.do_command(self, connection, event)
  72. def on_pubnotice(self, connection, event):
  73. log.info(event)
  74. def on_privnotice(self, connection, event):
  75. log.info(event)
  76. commands.public.do_command(self, connection, event)
  77. commands.admin.do_command(self, connection, event)
  78. commands.statistics.do_command(self, connection, event)
  79. commands.games.do_command(self, connection, event)
  80. if event.source.nick == "NickServ" and event.arguments[0].startswith("This nickname is registered"):
  81. connection.privmsg("NickServ", "identify " + connection.nickname + " " + self.password) # Identify with NickServ.
  82. if event.source.nick == "ChanServ" and event.arguments[0].startswith("Key for channel ") and len(event.arguments[0]) > 5: # Received channel key.
  83. connection.join(event.arguments[0].split(' ')[3], event.arguments[0].split(' ')[5][:-1])
  84. def on_action(self, connection, event):
  85. events.on_action.process_event(self, connection, event)
  86. def on_whoreply(self, connection, event):
  87. events.on_whoreply.process_event(self, connection, event)
  88. def on_userhost(self, connection, event):
  89. log.info(event)
  90. def on_yourhost(self, connection, event):
  91. log.info(event)
  92. def on_yourebannedcreep(self, connection, event):
  93. log.warning(event)
  94. def on_youwillbebanned(selfself, connection, event):
  95. log.warning(event)
  96. # DCC stuff from originalexample file.
  97. def on_dccmsg(self, c, e):
  98. log.info(e)
  99. # non-chat DCC messages are raw bytes; decode as text
  100. text = e.arguments[0].decode('utf-8')
  101. c.privmsg("You said: " + text)
  102. def on_dccchat(self, c, e):
  103. log.info(e)
  104. if len(e.arguments) != 2:
  105. return
  106. args = e.arguments[1].split()
  107. if len(args) == 4:
  108. try:
  109. address = ip_numstr_to_quad(args[2])
  110. port = int(args[3])
  111. except ValueError:
  112. return
  113. self.dcc_connect(address, port)
  114. def main():
  115. # Check system arguments.
  116. if len(sys.argv) != 2:
  117. print(sys.argv)
  118. print("Usage: rotbot <server ID from database>")
  119. sys.exit(1)
  120. instance = sys.argv[1] # Instance is the database network id.
  121. # Database.
  122. db = Postgres("postgres://pyRot:4h8q(.@localhost/pyRot")
  123. # Get network from database.
  124. try:
  125. network = db.one("SELECT * FROM networks WHERE id=" + str(instance))
  126. except:
  127. print("Invalid network ID.")
  128. sys.exit(1)
  129. if not network:
  130. print("Invalid network ID.")
  131. sys.exit(1)
  132. 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)
  133. bot.start()
  134. if __name__ == "__main__":
  135. try:
  136. main()
  137. except KeyboardInterrupt:
  138. log.info('Interrupted by keyboard.')
  139. sys.exit(0)