Browse Source

Join/part/quit etc.

Douglas William Thrift 11 years ago
parent
commit
43d66ff1c7
2 changed files with 113 additions and 17 deletions
  1. 3 1
      .gitignore
  2. 110 16
      locationbot.py

+ 3 - 1
.gitignore

@@ -1,2 +1,4 @@
 *.py?
-locationbot.ini
+*.ini
+*.log
+*.pid

+ 110 - 16
locationbot.py

@@ -27,19 +27,19 @@ except ImportError:
 
 class LocationBot(ircbot.SingleServerIRCBot):
 	def __init__(self, bot = None):
-		config = SafeConfigParser({'hostname': ''})
+		self.__config = SafeConfigParser()
 
-		config.read('locationbot.ini')
+		self.__config.read('locationbot.ini')
 
 		try:
-			nick = config.sections()[0]
+			nick = self.__config.sections()[0]
 		except IndexError:
 			sys.exit('No nick configured')
 
 		servers = []
 
 		try:
-			for server in config.get(nick, 'servers').split():
+			for server in self.__config.get(nick, 'servers').split():
 				server = server.split(':', 2)
 
 				if len(server) == 1:
@@ -54,13 +54,17 @@ class LocationBot(ircbot.SingleServerIRCBot):
 					else:
 						servers.append((host, port, ssl))
 
-			self.__admins = config.get(nick, 'admins').split()
-			self.__channels = set(config.get(nick, 'channels').split())
-			self.__dsn = config.get(nick, 'dsn')
-			self.__hostname = config.get(nick, 'hostname')
+			self.__admins = self.__config.get(nick, 'admins').split()
+			self.__channels = set(self.__config.get(nick, 'channels').split())
+			self.__dsn = self.__config.get(nick, 'dsn')
 		except NoOptionError, error:
 			sys.exit(error)
 
+		try:
+			self.__hostname = self.__config.get(nick, 'hostname')
+		except NoOptionError:
+			self.__hostname = ''
+
 		ircbot.SingleServerIRCBot.__init__(self, servers, nick, 'Location Bot')
 
 		self.__latitude_timer_lock = threading.Lock()
@@ -70,6 +74,7 @@ class LocationBot(ircbot.SingleServerIRCBot):
 		if bot is None:
 			self.__locations = []
 			self.__logins = {}
+			self.__nick = None
 			self.__reloading = False
 		else:
 			irclibobj = self.ircobj.connections[0].irclibobj
@@ -79,8 +84,10 @@ class LocationBot(ircbot.SingleServerIRCBot):
 			self.connection = bot.connection
 			self.__locations = bot.__locations
 			self.__logins = bot.__logins
+			self.__nick = bot.__nick
 			self.__reloading = True
 
+		self.__quiting = False
 		self.__variables = frozenset(['nick', 'secret', 'masks', 'channels', 'timezone', 'location', 'latitude'])
 		self.__lists = self.__variables.intersection(['masks', 'channels'])
 		self.__unsetable = self.__variables.difference(['nick', 'secret'])
@@ -123,6 +130,9 @@ class LocationBot(ircbot.SingleServerIRCBot):
 
 		if admin:
 			commands.update({
+				'join': ('channel', 'join a channel'),
+				'part': ('channel [message]', 'part from a channel'),
+				'quit': ('[message]', 'quit and do not come back'),
 				'reload': ('', 'reload with more up to date code'),
 				'restart': ('', 'quit and join running more up to date code'),
 				'say': ('nick|channel message', 'say message to nick or channel'),
@@ -140,6 +150,18 @@ class LocationBot(ircbot.SingleServerIRCBot):
 			for command, (arguments, description) in sorted(commands.iteritems()):
 				help(command, arguments, description)
 
+	def __join(self, connection, nick, arguments):
+		try:
+			channel = arguments.split(None, 1)[0]
+		except IndexError:
+			return self.__help(connection, nick, True, False, 'join')
+
+		connection.join(channel)
+		self.__channels.add(channel)
+		self.__config.set(self._nickname, 'channels', ' '.join(self.__channels))
+		self.__write()
+		connection.privmsg(nick, 'successfully joined channel ("%s")' % channel)
+
 	def __latitude(self):
 		now = datetime.utcnow()
 
@@ -255,6 +277,33 @@ class LocationBot(ircbot.SingleServerIRCBot):
 	def __logout(self, connection, nick):
 		connection.privmsg(nick, 'logged out as "%s"' % self.__logins.pop(nick)[0])
 
+	def __part(self, connection, nick, arguments):
+		arguments = arguments.split(None, 1)
+
+		if len(arguments) == 2:
+			channel, message = arguments
+			message = ':' + message
+		elif len(arguments) == 1:
+			channel = arguments[0]
+			message = ''
+		else:
+			return self.__help(connection, nick, True, False, 'part')
+
+		if channel in self.__channels:
+			connection.part(channel, message)
+			self.__channels.remove(channel)
+			self.__config.set(self._nickname, 'channels', ' '.join(self.__channels))
+			self.__write()
+			connection.privmsg(nick, 'successfully parted channel ("%s")' % channel)
+		else:
+			connection.privmsg(nick, 'not in channel ("%s")' % channel)
+
+	def __quit(self, connection, nick):
+		self.__reloading = True
+		self.__quiting = True
+
+		connection.privmsg(nick, 'quiting')
+
 	def __register(self, connection, nick, arguments):
 		arguments = arguments.split(None, 1)
 
@@ -277,6 +326,7 @@ class LocationBot(ircbot.SingleServerIRCBot):
 		connection.privmsg(nick, 'nick ("%s") sucessfully registered' % login)
 
 	def __reload(self, connection, nick):
+		self.__nick = nick
 		self.__reloading = True
 
 		connection.privmsg(nick, 'reloading')
@@ -434,6 +484,10 @@ class LocationBot(ircbot.SingleServerIRCBot):
 		else:
 			connection.privmsg(nick, 'nobody logged in')
 
+	def __write(self):
+		with open('locationbot.ini', 'w') as config:
+			self.__config.write(config)
+
 	def _connect(self):
 		if len(self.server_list[0]) != 2:
 			ssl = self.server_list[0][2]
@@ -452,6 +506,14 @@ class LocationBot(ircbot.SingleServerIRCBot):
 		except irclib.ServerConnectionError:
 			pass
 
+	def disconnect(self, message = 'oh no!'):
+		ircbot.SingleServerIRCBot.disconnect(self, message)
+
+	def error(self, error):
+		print error
+
+		self.connection.privmsg(self.__nick, 'an error occured')
+
 	def get_version(self):
 		return 'locationbot ' + sys.platform
 
@@ -511,6 +573,12 @@ class LocationBot(ircbot.SingleServerIRCBot):
 				self.__set(connection, nickmask, nick, login, arguments)
 			elif login and command == 'unset':
 				self.__unset(connection, nick, login, arguments)
+			elif admin and command == 'join':
+				self.__join(connection, nick, arguments)
+			elif admin and command == 'part':
+				self.__part(connection, nick, arguments)
+			elif admin and command == 'quit':
+				self.__quit(connection, nick)
 			elif admin and command == 'reload':
 				self.__reload(connection, nick)
 			elif admin and command == 'restart':
@@ -544,8 +612,11 @@ class LocationBot(ircbot.SingleServerIRCBot):
 		else:
 			self.__reloading = False
 
-			for channel in self.__channels.difference(self.channels.keys()):
-				self.connection.join(channel)
+			for channel in self.__channels.symmetric_difference(self.channels.keys()):
+				if channel in self.__channels:
+					self.connection.join(channel)
+				else:
+					self.connection.part(channel)
 
 		while not self.__reloading:
 			if self.__locations_lock.acquire(False):
@@ -566,18 +637,41 @@ class LocationBot(ircbot.SingleServerIRCBot):
 				self.__latitude_timer.cancel()
 				self.__latitude_timer.join()
 
+		return not self.__quiting
+
+	def success(self):
+		self.connection.privmsg(self.__nick, 'successfully reloaded')
+
 def _or(function, values):
 	return reduce(lambda a, b: a or b, map(function, values) if values else [False])
 
 if __name__ == '__main__':
+	pid = os.fork()
+
+	if pid != 0:
+		with open('locationbot.pid', 'w') as _file:
+			_file.write('%u\n' % pid)
+
+		sys.exit(0)
+
+	sys.stdin = open('/dev/null')
+	sys.stdout = open('locationbot.log', 'a', 1)
+	sys.stderr = sys.stdout
+
 	import locationbot
 
-	bot = None
+	bot = locationbot.LocationBot()
 
 	try:
-		while True:
-			bot = reload(locationbot).LocationBot(bot)
-
-			bot.start()
+		while bot.start():
+			try:
+				bot = reload(locationbot).LocationBot(bot)
+			except (ImportError, SyntaxError), error:
+				bot.error(error)
+			else:
+				bot.success()
 	except KeyboardInterrupt:
-		bot.connection.disconnect('oh no!')
+		pass
+
+	bot.disconnect()
+	os.unlink('locationbot.pid')