locationbot.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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 __restart(self, connection):
  67. connection.disconnect('Restarting')
  68. os.execvp(sys.argv[0], sys.argv)
  69. def __unknown(self, connection, nick, command):
  70. connection.privmsg(nick, 'unknown command (%s); try "!help"' % command)
  71. def _connect(self):
  72. password = None
  73. if len(self.server_list[0]) != 2:
  74. ssl = self.server_list[0][2]
  75. if len(self.server_list[0]) == 4:
  76. password = self.server_list[0][3]
  77. try:
  78. with warnings.catch_warnings():
  79. warnings.filterwarnings('ignore', r'socket\.ssl\(\) is deprecated\. Use ssl\.wrap_socket\(\) instead\.', DeprecationWarning)
  80. self.connect(self.server_list[0][0], self.server_list[0][1], self._nickname, password, getpass.getuser(), self._realname, localaddress = self.__hostname, ssl = ssl)
  81. except irclib.ServerConnectionError:
  82. pass
  83. def get_version(self):
  84. return 'locationbot ' + sys.platform
  85. def on_nicknameinuse(self, connection, event):
  86. connection.nick(connection.get_nickname() + '_')
  87. def on_privmsg(self, connection, event):
  88. nick = irclib.nm_to_n(event.source())
  89. admin = self.__admin(event)
  90. if not admin:
  91. ok = False
  92. for channel in self.channels.values():
  93. if channel.has_user(nick):
  94. ok = True
  95. break
  96. if not ok:
  97. return
  98. try:
  99. command, arguments = event.arguments()[0].split(None, 1)
  100. except ValueError:
  101. command = event.arguments()[0].strip()
  102. arguments = ''
  103. if command.startswith('!'):
  104. command = command[1:]
  105. if command == 'help':
  106. connection.privmsg(nick, 'Command Arguments Description')
  107. commands = [
  108. ('help', '', 'show this help message'),
  109. ('login', 'user secret', 'login as user with secret'),
  110. ('register', 'user secret', 'register as user with secret'),
  111. ('status', '[user]', 'show where everybody or a user is'),
  112. ]
  113. if True:
  114. commands += [
  115. ('latitude', '[id]', 'shortcut for !set latitude [id]'),
  116. ('set', '[key [value]]', 'display or set variables'),
  117. ('unset', 'key', 'unset a variable'),
  118. ]
  119. if admin:
  120. commands += [
  121. ('restart', '', 'quit and join running more up to date code'),
  122. ]
  123. commands.sort()
  124. for command in commands:
  125. connection.privmsg(nick, '!%-10s %-16s %s' % command)
  126. elif admin:
  127. if command == 'restart':
  128. self.__restart(connection)
  129. else:
  130. self.__unknown(connection, nick, command)
  131. else:
  132. self.__unknown(connection, nick, command)
  133. elif event.eventtype() == 'privmsg':
  134. self.__unknown(connection, nick, command)
  135. def on_welcome(self, connection, event):
  136. for channel in self.__channels:
  137. connection.join(channel)
  138. def start(self):
  139. self.__latitude = threading.Thread(None, self.__do_latitude)
  140. self.__latitude.daemon = True
  141. self.__latitude.start()
  142. self._connect()
  143. while True:
  144. self.ircobj.process_once(0.2)
  145. if self.__locations_lock.acquire(False):
  146. if self.__locations and sorted(self.__channels) == sorted(self.channels.keys()):
  147. for user, location in self.__locations:
  148. for channel in self.__channels:
  149. self.connection.notice(channel, '%s is in %s' % (user, location))
  150. self.__locations = []
  151. self.__locations_lock.release()
  152. if __name__ == '__main__':
  153. locationbot = LocationBot()
  154. try:
  155. locationbot.start()
  156. except KeyboardInterrupt:
  157. locationbot.connection.disconnect('Oh no!')