1
0

bot.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. #! /usr/bin/env python
  2. import sys, ssl, random
  3. import irc.bot#, irc.strings #https://python-irc.readthedocs.io/en/latest/irc.html#
  4. #from irc.client import ip_numstr_to_quad#, ip_quad_to_numstr
  5. from jaraco.stream import buffer
  6. from postgres import Postgres # https://postgres-py.readthedocs.io/en/latest/
  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, events.on_part, events.on_quit, events.on_topic, events.on_privmsg, events.on_pubnotice, events.on_nicknameinuse, events.on_error, events.on_keyset, events.on_privnotice
  8. from common import log, font
  9. from events.common import Inform
  10. class PyRot(irc.bot.SingleServerIRCBot):
  11. def __init__(self, network, db, webgui):
  12. self.network = network
  13. self.db = db
  14. self.webgui = webgui
  15. # Pick a random host from the network.
  16. hosts = db.all("SELECT * FROM rotbot_host WHERE network_id=%(network)s", network=network.id)
  17. host = random.choice(hosts)
  18. connect_string = (host.address, host.port)
  19. irc.client.ServerConnection.buffer_class = buffer.LenientDecodingLineBuffer # Set buffer class.
  20. # self.protectees = {}
  21. # self.channelkeys = {}
  22. # Log and record to database.
  23. log.info('Connecting to %s:%s/%s' % (connect_string[0], connect_string[1], network.home_channel))
  24. db.run("UPDATE rotbot_host SET connection_attempts = connection_attempts + 1 WHERE id=%s", [network.id])
  25. # Create connect factory with correct scheme.
  26. if host.ssl:
  27. factory = irc.connection.Factory(wrapper=ssl.wrap_socket)
  28. else:
  29. factory = irc.connection.Factory()
  30. try:
  31. irc.bot.SingleServerIRCBot.__init__(self, [connect_string], network.nickname, network.username, connect_factory=factory) # Connect.
  32. except irc.client.ServerConnectionError: # Connection failure.
  33. sys.exit(sys.exc_info()[1]) # Exit.
  34. ## Events.
  35. def on_nicknameinuse(self, connection, event): # Bots nickname is already taken.
  36. events.on_nicknameinuse.process_event(self, connection, event)
  37. def on_welcome(self, connection, event): # IRC server welcomes bot after connecting.
  38. events.on_welcome.process_event(self, connection, event)
  39. #
  40. def on_error(self, connection, event):
  41. events.on_error.process_event(self, connection, event)
  42. def on_nick(self, connection, event): # User changes nickname.
  43. events.on_nick.process_event(self, connection, event)
  44. def on_join(self, connection, event): # User joins a channel.
  45. events.on_join.process_event(self, connection, event)
  46. def on_mode(self, connection, event): # Mode change.
  47. events.on_mode.process_event(self, connection, event)
  48. def on_kick(self, connection, event): # User kicks user from channel.
  49. events.on_kick.process_event(self, connection, event)
  50. def on_part(self, connection, event): # User parts channel.
  51. events.on_part.process_event(self, connection, event)
  52. def on_quit(self, connection, event): # User quit irc server.
  53. events.on_quit.process_event(self, connection, event)
  54. def on_invite(self, connection, event): # Channel invite
  55. events.on_invite.process_event(self, connection, event)
  56. def on_topic(self, connection, event): # Channel topic change.
  57. events.on_topic.process_event(self,connection, event)
  58. def on_pubmsg(self, connection, event): # Channel message
  59. events.on_pubmsg.process_event(self, connection, event)
  60. def on_action(self, connection, event): # Is this both channel and private actions?
  61. events.on_action.process_event(self, connection, event)
  62. def on_privmsg(self, connection, event): # Private message.
  63. events.on_privmsg.process_event(self, connection, event)
  64. def on_pubnotice(self, connection, event): # Channel notice
  65. events.on_pubnotice.process_event(self, connection, event)
  66. def on_privnotice(self, connection, event): # Private notice.
  67. events.on_privnotice.process_event(self, connection, event)
  68. def on_whoreply(self, connection, event):
  69. events.on_whoreply.process_event(self, connection, event)
  70. def on_keyset(self, connection, event):
  71. events.on_keyset.process_event(self, connection, event)
  72. def on_yourhost(self, connection, event):
  73. log.info(event)
  74. def on_yourebannedcreep(self, connection, event):
  75. Inform.operators(self, connection, "I am banned " + font.red + event.arguments[0] + reset.reset + " from " + font.red + event.source)
  76. log.warning(event)
  77. def on_youwillbebanned(self, connection, event):
  78. log.warning(event)
  79. Inform.operators(self, connection, "I will be banned " + font.red + event.arguments[0] + reset.reset + " from " + font.red + event.source)
  80. # DCC stuff from originalexample file.
  81. def on_dccmsg(self, c, e):
  82. log.info(c, e)
  83. # non-chat DCC messages are raw bytes; decode as text
  84. #text = e.arguments[0].decode('utf-8')
  85. #c.privmsg("You said: " + text)
  86. def on_dccchat(self, c, e):
  87. log.info(c, e)
  88. # if len(e.arguments) != 2:
  89. # return
  90. # args = e.arguments[1].split()
  91. # if len(args) == 4:
  92. # try:
  93. # address = ip_numstr_to_quad(args[2])
  94. # port = int(args[3])
  95. # except ValueError:
  96. # return
  97. # self.dcc_connect(address, port)
  98. def main():
  99. log.info('Starting RotBot: pyRot version.')
  100. # Validate system arguments and warn if needed..
  101. if len(sys.argv) != 2: # Not 2 arguments.
  102. sys.exit('To run type "python bot.py database_network_id", not: %s. Terminating program.' % (sys.argv)) # Terminate program.
  103. instance = sys.argv[1] # Instance is the database network id.
  104. ### SETTINGS
  105. webgui = {
  106. 'base_url': 'https://h0v1n8.nl/rotbot/', # The django rotbot app url.
  107. 'register_url': '',
  108. }
  109. # Database credentials
  110. username = 'pyrot'
  111. password = 'oGPnbiqh55QKLhmnKQgS92h74j0e9d6LE58cSsD1'
  112. ### End of SETTINGS
  113. db_connect_string = 'postgres://%s:%s@localhost/website' % (username, password)
  114. try:
  115. db = Postgres(db_connect_string) # Connect to database.
  116. except:
  117. sys.exit('Database connection %s failed: %s' % (db_connect_string, sys.exc_info())) # Exit.
  118. try:
  119. network = db.one("SELECT * FROM rotbot_network WHERE id=%(instance)s", instance=instance) # Get network from database.
  120. except:
  121. sys.exit('Could not retrieve network %s from database: %s' % (instance, sys.exc_info())) # Exit.
  122. if network == None: # No data returned.
  123. sys.exit('Network %s not found, terminating program.' % (instance)) # Exit.
  124. if network.enabled == False: # Network disabled in database.
  125. sys.exit('Network %s marked as disabled in database, use webgui to enable. Terminating program.' % (network.name)) # Exit
  126. bot = PyRot(network, db, webgui)
  127. bot.start()
  128. if __name__ == "__main__":
  129. try:
  130. main() # Run the program.
  131. except KeyboardInterrupt: # User presses CTRL+C
  132. sys.exit('Interrupted by keyboard.') # Exit.