#!/usr/bin/env python # Location Bot # # Douglas Thrift # # $Id$ from ConfigParser import NoOptionError, SafeConfigParser import geojson import getpass import ircbot import irclib import os import sys import threading import urllib, urllib2 import warnings class LocationBot(ircbot.SingleServerIRCBot): def __init__(self): config = SafeConfigParser({'hostname': ''}) config.read('locationbot.ini') try: nick = config.sections()[0] except IndexError: sys.exit('No nick configured') servers = [] try: for server in config.get(nick, 'servers').split(): server = server.split(':', 2) if len(server) == 1: servers.append((server[0], 6667)) else: host = server[0] port = int(server[1]) ssl = server[1].startswith('+') if len(server) == 3: servers.append((host, port, ssl, server[2])) else: servers.append((host, port, ssl)) self.__admins = config.get(nick, 'admins').split() self.__channels = config.get(nick, 'channels').split() self.__hostname = config.get(nick, 'hostname') except NoOptionError, error: sys.exit(error) self.__locations_lock = threading.Lock() self.__locations = [] ircbot.SingleServerIRCBot.__init__(self, servers, nick, 'Location Bot') def __admin(self, nick): if isinstance(nick, irclib.Event): nick = nick.source() for admin in self.__admins: if irclib.mask_matches(nick, admin): return True return False def __do_latitude(self): #with self.__locations_lock: # self.__locations.append(('douglaswth', 'Isla Vista, CA, USA')) #try: # url = 'http://www.google.com/latitude/apps/badge/api?' + urllib.urlencode({'user': 0, 'type': 'json'}) # response = urllib2.urlopen(url) # geo = geojson.load(response, object_hook = geojson.GeoJSON.to_instance) # print geo.features[0].properties['reverseGeocode'] #except urllib2.URLError, error: # print error self.__latitude = threading.Timer(5 * 60, self.__do_latitude) self.__latitude.start() def __help(self, connection, nick, admin, arguments): connection.privmsg(nick, 'Command Arguments Description') commands = [ ('help', '', 'show this help message'), ('login', 'user secret', 'login as user with secret'), ('register', 'user secret', 'register as user with secret'), ('status', '[user]', 'show where everybody or a user is'), ] if True: commands += [ ('latitude', '[id]', 'shortcut for !set latitude [id]'), ('set', '[key [value]]', 'display or set variables'), ('unset', 'key', 'unset a variable'), ] if admin: commands += [ ('restart', '', 'quit and join running more up to date code'), ('say', 'channel message', 'say message in channel'), ] commands.sort() for command in commands: connection.privmsg(nick, '!%-10s %-16s %s' % command) def __restart(self, connection): connection.disconnect('Restarting') os.execvp(sys.argv[0], sys.argv) def __say(self, connection, nick, arguments): try: channel, message = arguments.split(None, 1) connection.privmsg(channel, message) except ValueError: self.__help(connection, nick, True, 'say') def __unknown(self, connection, nick, command): connection.privmsg(nick, 'unknown command (%s); try "!help"' % command) def _connect(self): password = None if len(self.server_list[0]) != 2: ssl = self.server_list[0][2] if len(self.server_list[0]) == 4: password = self.server_list[0][3] try: with warnings.catch_warnings(): warnings.filterwarnings('ignore', r'socket\.ssl\(\) is deprecated\. Use ssl\.wrap_socket\(\) instead\.', DeprecationWarning) self.connect(self.server_list[0][0], self.server_list[0][1], self._nickname, password, getpass.getuser(), self._realname, localaddress = self.__hostname, ssl = ssl) except irclib.ServerConnectionError: pass def get_version(self): return 'locationbot ' + sys.platform def on_nicknameinuse(self, connection, event): connection.nick(connection.get_nickname() + '_') def on_privmsg(self, connection, event): nick = irclib.nm_to_n(event.source()) admin = self.__admin(event) if not admin: ok = False for channel in self.channels.values(): if channel.has_user(nick): ok = True break if not ok: return try: command, arguments = event.arguments()[0].split(None, 1) except ValueError: command = event.arguments()[0].strip() arguments = '' if command.startswith('!'): command = command[1:] if command == 'help': self.__help(connection, nick, admin, arguments) elif admin: if command == 'restart': self.__restart(connection) elif command == 'say': self.__say(connection, nick, arguments) else: self.__unknown(connection, nick, command) else: self.__unknown(connection, nick, command) elif event.eventtype() == 'privmsg': self.__unknown(connection, nick, command) def on_welcome(self, connection, event): for channel in self.__channels: connection.join(channel) def start(self): self.__latitude = threading.Thread(None, self.__do_latitude) self.__latitude.daemon = True self.__latitude.start() self._connect() while True: self.ircobj.process_once(0.2) if self.__locations_lock.acquire(False): if self.__locations and sorted(self.__channels) == sorted(self.channels.keys()): for user, location in self.__locations: for channel in self.__channels: self.connection.notice(channel, '%s is in %s' % (user, location)) self.__locations = [] self.__locations_lock.release() if __name__ == '__main__': locationbot = LocationBot() try: locationbot.start() except KeyboardInterrupt: locationbot.connection.disconnect('Oh no!')