locationbot.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #!/usr/bin/env python
  2. # Location Bot
  3. #
  4. # Douglas Thrift
  5. #
  6. # $Id$
  7. from ConfigParser import NoOptionError, SafeConfigParser
  8. import geojson
  9. import getpass
  10. import ircbot
  11. import irclib
  12. import os
  13. import sys
  14. import threading
  15. import urllib, urllib2
  16. import warnings
  17. class LocationBot(ircbot.SingleServerIRCBot):
  18. def __init__(self):
  19. config = SafeConfigParser({'hostname': ''})
  20. config.read('locationbot.ini')
  21. try:
  22. nick = config.sections()[0]
  23. except IndexError:
  24. sys.exit('No nick configured')
  25. servers = []
  26. try:
  27. for server in config.get(nick, 'servers').split():
  28. server = server.split(':', 2)
  29. if len(server) == 1:
  30. servers.append((server[0], 6667))
  31. else:
  32. host = server[0]
  33. port = int(server[1])
  34. ssl = server[1].startswith('+')
  35. if len(server) == 3:
  36. servers.append((host, port, ssl, server[2]))
  37. else:
  38. servers.append((host, port, ssl))
  39. self.__admins = config.get(nick, 'admins').split()
  40. self.__channels = config.get(nick, 'channels').split()
  41. self.__hostname = config.get(nick, 'hostname')
  42. except NoOptionError, error:
  43. sys.exit(error)
  44. self.__locations_lock = threading.Lock()
  45. self.__locations = []
  46. ircbot.SingleServerIRCBot.__init__(self, servers, nick, 'Location Bot')
  47. def __admin(self, nick):
  48. if isinstance(nick, irclib.Event):
  49. nick = nick.source()
  50. for admin in self.__admins:
  51. if irclib.mask_matches(nick, admin):
  52. return True
  53. return False
  54. def __do_latitude(self):
  55. #with self.__locations_lock:
  56. # self.__locations.append(('douglaswth', 'Isla Vista, CA, USA'))
  57. #try:
  58. # url = 'http://www.google.com/latitude/apps/badge/api?' + urllib.urlencode({'user': 0, 'type': 'json'})
  59. # response = urllib2.urlopen(url)
  60. # geo = geojson.load(response, object_hook = geojson.GeoJSON.to_instance)
  61. # print geo.features[0].properties['reverseGeocode']
  62. #except urllib2.URLError, error:
  63. # print error
  64. self.__latitude = threading.Timer(5 * 60, self.__do_latitude)
  65. self.__latitude.start()
  66. def __help(self, connection, nick, admin, arguments):
  67. connection.privmsg(nick, 'Command Arguments Description')
  68. commands = [
  69. ('help', '', 'show this help message'),
  70. ('login', 'user secret', 'login as user with secret'),
  71. ('register', 'user secret', 'register as user with secret'),
  72. ('status', '[user]', 'show where everybody or a user is'),
  73. ]
  74. if True:
  75. commands += [
  76. ('latitude', '[id]', 'shortcut for !set latitude [id]'),
  77. ('set', '[key [value]]', 'display or set variables'),
  78. ('unset', 'key', 'unset a variable'),
  79. ]
  80. if admin:
  81. commands += [
  82. ('restart', '', 'quit and join running more up to date code'),
  83. ('say', 'channel message', 'say message in channel'),
  84. ]
  85. commands.sort()
  86. for command in commands:
  87. connection.privmsg(nick, '!%-10s %-16s %s' % command)
  88. def __restart(self, connection):
  89. connection.disconnect('Restarting')
  90. os.execvp(sys.argv[0], sys.argv)
  91. def __say(self, connection, nick, arguments):
  92. try:
  93. channel, message = arguments.split(None, 1)
  94. connection.privmsg(channel, message)
  95. except ValueError:
  96. self.__help(connection, nick, True, 'say')
  97. def __unknown(self, connection, nick, command):
  98. connection.privmsg(nick, 'unknown command (%s); try "!help"' % command)
  99. def _connect(self):
  100. password = None
  101. if len(self.server_list[0]) != 2:
  102. ssl = self.server_list[0][2]
  103. if len(self.server_list[0]) == 4:
  104. password = self.server_list[0][3]
  105. try:
  106. with warnings.catch_warnings():
  107. warnings.filterwarnings('ignore', r'socket\.ssl\(\) is deprecated\. Use ssl\.wrap_socket\(\) instead\.', DeprecationWarning)
  108. self.connect(self.server_list[0][0], self.server_list[0][1], self._nickname, password, getpass.getuser(), self._realname, localaddress = self.__hostname, ssl = ssl)
  109. except irclib.ServerConnectionError:
  110. pass
  111. def get_version(self):
  112. return 'locationbot ' + sys.platform
  113. def on_nicknameinuse(self, connection, event):
  114. connection.nick(connection.get_nickname() + '_')
  115. def on_privmsg(self, connection, event):
  116. nick = irclib.nm_to_n(event.source())
  117. admin = self.__admin(event)
  118. if not admin:
  119. ok = False
  120. for channel in self.channels.values():
  121. if channel.has_user(nick):
  122. ok = True
  123. break
  124. if not ok:
  125. return
  126. try:
  127. command, arguments = event.arguments()[0].split(None, 1)
  128. except ValueError:
  129. command = event.arguments()[0].strip()
  130. arguments = ''
  131. if command.startswith('!'):
  132. command = command[1:]
  133. if command == 'help':
  134. self.__help(connection, nick, admin, arguments)
  135. elif admin:
  136. if command == 'restart':
  137. self.__restart(connection)
  138. elif command == 'say':
  139. self.__say(connection, nick, arguments)
  140. else:
  141. self.__unknown(connection, nick, command)
  142. else:
  143. self.__unknown(connection, nick, command)
  144. elif event.eventtype() == 'privmsg':
  145. self.__unknown(connection, nick, command)
  146. def on_welcome(self, connection, event):
  147. for channel in self.__channels:
  148. connection.join(channel)
  149. def start(self):
  150. self.__latitude = threading.Thread(None, self.__do_latitude)
  151. self.__latitude.daemon = True
  152. self.__latitude.start()
  153. self._connect()
  154. while True:
  155. self.ircobj.process_once(0.2)
  156. if self.__locations_lock.acquire(False):
  157. if self.__locations and sorted(self.__channels) == sorted(self.channels.keys()):
  158. for user, location in self.__locations:
  159. for channel in self.__channels:
  160. self.connection.notice(channel, '%s is in %s' % (user, location))
  161. self.__locations = []
  162. self.__locations_lock.release()
  163. if __name__ == '__main__':
  164. locationbot = LocationBot()
  165. try:
  166. locationbot.start()
  167. except KeyboardInterrupt:
  168. locationbot.connection.disconnect('Oh no!')