a XMPP logging bot, saving its log as html page
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

logbot.py 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # To run this bot:
  4. # $ python3 logbot.py
  5. # The output folder of this bot currently is: /var/www/logs/digital-autonomy
  6. import logging
  7. from getpass import getpass
  8. from argparse import ArgumentParser
  9. import slixmpp
  10. import ssl, os, requests, urllib
  11. class MUCBot(slixmpp.ClientXMPP):
  12. """
  13. A simple Slixmpp bot that will save images
  14. and messages that are marked with @bot to a folder.
  15. """
  16. def __init__(self, jid, password, room, nick, output):
  17. slixmpp.ClientXMPP.__init__(self, jid, password)
  18. self.room = room
  19. self.nick = nick
  20. self.output = output
  21. # The session_start event will be triggered when
  22. # the bot establishes its connection with the server
  23. # and the XML logs are ready for use. We want to
  24. # listen for this event so that we we can initialize
  25. # our roster.
  26. self.add_event_handler("session_start", self.start)
  27. # The groupchat_message event is triggered whenever a message
  28. # stanza is received from any chat room. If you also also
  29. # register a handler for the 'message' event, MUC messages
  30. # will be processed by both handlers.
  31. self.add_event_handler("groupchat_message", self.muc_message)
  32. def start(self, event):
  33. self.get_roster()
  34. self.send_presence()
  35. # https://xmpp.org/extensions/xep-0045.html
  36. self.plugin['xep_0045'].join_muc(self.room,
  37. self.nick,
  38. # If a room password is needed, use:
  39. # password=the_room_password,
  40. wait=True)
  41. # Send a message to the room
  42. self.send_message(mto=self.room, mbody='Hello! Logbot here. I\'m here to log all the images that are send to this group. You can also log text messages, by including @bot in your message. Happy logging! PS. you can access the logs at https://vvvvvvaria.org/logs/', mtype='groupchat')
  43. def muc_message(self, msg):
  44. # Some inspection commands
  45. #print('Message: {}'.format(msg))
  46. # Always check that a message is not the bot itself, otherwise you will create an infinite loop responding to your own messages.
  47. if msg['mucnick'] != self.nick:
  48. # Check if output folder exists
  49. if not os.path.exists(self.output):
  50. os.mkdir(self.output)
  51. # Check if an OOB URL is included in the stanza (which is how an image is sent)
  52. # (OOB object - https://xmpp.org/extensions/xep-0066.html#x-oob)
  53. if len(msg['oob']['url']) > 0:
  54. # Send a reply
  55. self.send_message(mto=self.room,
  56. mbody="Super, our log is growing. Your image is added!",
  57. mtype='groupchat')
  58. # Save the image to the output folder
  59. url = msg['oob']['url'] # grep the url in the message
  60. filename = os.path.basename(url) # grep the filename in the url
  61. output_path = os.path.join(self.output, filename)
  62. u = urllib.request.urlopen(url) # read the image data
  63. f = open(output_path, 'wb') # open the output file
  64. f.write(u.read()) # write image to file
  65. f.close() # close the output file
  66. # Add the image to the log
  67. img = '<img class="image" src="{}">'.format(filename)
  68. log = 'log.html'
  69. log_path = os.path.join(self.output, log)
  70. f = open(log_path, 'a+')
  71. f.write(img+'\n')
  72. f.close()
  73. # Include messages in the log (only when '@bot' is used in the message)
  74. if '@bot' in msg['body']:
  75. # reply from the bot
  76. self.send_message(mto=self.room,
  77. mbody="Noted! And added to the log. Thanks {}!".format(msg['mucnick']),
  78. mtype='groupchat')
  79. # Add the message to the log!
  80. message = '<p class="message">{}</p>'.format(msg['body'].replace('@bot',''))
  81. log = 'log.html'
  82. log_path = os.path.join(self.output, log)
  83. f = open(log_path, 'a+')
  84. f.write(message+'\n')
  85. f.close()
  86. if '/book' in msg['body']: # Check if this is a book ...
  87. self.send_message(mto=self.room,
  88. mbody="Oh a book, that's cool! Thanks {}!".format(msg['mucnick']),
  89. mtype='groupchat')
  90. # Start of book feature
  91. from bs4 import BeautifulSoup
  92. import re
  93. book = msg['body'].replace('@bot', '').replace('/book', '')
  94. book = re.sub(' +', ' ', book) # remove double spaces
  95. book = book.lstrip().rstrip() # remove spaces at the beginning and at the end
  96. book = book.replace(' ', '+').lower() # turn space into + and lowercase
  97. page_link = 'https://www.worldcat.org/search?q={}&qt=results_page'.format(book)
  98. page_response = requests.get(page_link, timeout=5)
  99. page_content = BeautifulSoup(page_response.content, "html.parser")
  100. try:
  101. book_title = page_content.findAll("div", {"class": "name"})[0].text
  102. book_author = page_content.findAll("div", {"class": "author"})[0].text
  103. book_publisher = page_content.findAll("div", {"class": "publisher"})[0].text
  104. response = '<b>BOOK</b>: ' + book_title + ' ' + book_author + ' ' + book_publisher
  105. book_found = True
  106. except IndexError:
  107. book_found = False
  108. if book_found:
  109. # Add message to log
  110. message = '<b>BOOK</b>: ' + book_title + ' ' + book_author + ' ' + book_publisher
  111. log = 'log.html'
  112. log_path = os.path.join(self.output, log)
  113. f = open(log_path, 'a+')
  114. f.write(message+'\n')
  115. f.close()
  116. self.send_message(mto=self.room, mbody='Hope this was the book you were looking for: ' + book_title + ' ' + book_author + ' ' + book_publisher, mtype='groupchat')
  117. else:
  118. self.send_message(mto=self.room, mbody='Sorry, no book found!', mtype='groupchat')
  119. if __name__ == '__main__':
  120. # Setup the command line arguments.
  121. parser = ArgumentParser()
  122. # output verbosity options.
  123. parser.add_argument("-q", "--quiet", help="set logging to ERROR",
  124. action="store_const", dest="loglevel",
  125. const=logging.ERROR, default=logging.INFO)
  126. parser.add_argument("-d", "--debug", help="set logging to DEBUG",
  127. action="store_const", dest="loglevel",
  128. const=logging.DEBUG, default=logging.INFO)
  129. # JID and password options.
  130. parser.add_argument("-j", "--jid", dest="jid",
  131. help="JID to use")
  132. parser.add_argument("-p", "--password", dest="password",
  133. help="password to use")
  134. parser.add_argument("-r", "--room", dest="room",
  135. help="MUC room to join")
  136. parser.add_argument("-n", "--nick", dest="nick",
  137. help="MUC nickname")
  138. # output folder for images
  139. parser.add_argument("-o", "--output", dest="output",
  140. help="output folder, this is where the files are stored",
  141. type=str)
  142. args = parser.parse_args()
  143. # Setup logging.
  144. logging.basicConfig(level=args.loglevel,
  145. format='%(levelname)-8s %(message)s')
  146. if args.jid is None:
  147. args.jid = input("XMPP address: ")
  148. if args.password is None:
  149. args.password = getpass("Password: ")
  150. if args.room is None:
  151. args.room = input("MUC room: ")
  152. if args.nick is None:
  153. args.nick = input("MUC nickname: ")
  154. if args.output is None:
  155. args.output = input("Output folder: ")
  156. # Setup the MUCBot and register plugins. Note that while plugins may
  157. # have interdependencies, the order in which you register them does
  158. # not matter.
  159. xmpp = MUCBot(args.jid, args.password, args.room, args.nick, args.output)
  160. xmpp.register_plugin('xep_0030') # Service Discovery
  161. xmpp.register_plugin('xep_0045') # Multi-User Chat
  162. xmpp.register_plugin('xep_0199') # XMPP Ping
  163. xmpp.register_plugin('xep_0066') # Process URI's (files, images)
  164. # Connect to the XMPP server and start processing XMPP stanzas.
  165. xmpp.connect()
  166. xmpp.process()