From c3c24fd8fb8f91696b4e38e0f212a35a8e1fe137 Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Sun, 22 Jul 2012 18:13:24 +0100
Subject: Allow nick changing and restart for Swiftob bots


diff --git a/Swiftob/Commands.cpp b/Swiftob/Commands.cpp
index 18f9fb0..38e5f57 100644
--- a/Swiftob/Commands.cpp
+++ b/Swiftob/Commands.cpp
@@ -9,6 +9,7 @@
 #include <Swiften/Base/foreach.h>
 #include <iostream>
 #include <boost/bind.hpp>
+#include <boost/algorithm/string.hpp>
 
 #include <Swiften/Client/Client.h>
 
@@ -22,16 +23,28 @@ Commands::Commands(Users* users, Swift::Client* client, Storage* storage, MUCs*
 	resetCommands();
 }
 
-void Commands::resetCommands() {
+Commands::~Commands() {
+	clearCommands();
+}
+
+void Commands::clearCommands() {
 	foreach (NamedCommand command, commands_) {
 		delete command.second;
 	}
 	commands_.clear();
+
+}
+
+void Commands::resetCommands() {
+	clearCommands();
 	registerCommand("quit", Owner, "Quit the bot", boost::bind(&Commands::handleQuitCommand, this, _1, _2, _3));
 	registerCommand("help", Anyone, "Get help", boost::bind(&Commands::handleHelpCommand, this, _1, _2, _3));
 	registerCommand("join", Owner, "Join a MUC", boost::bind(&Commands::handleJoinCommand, this, _1, _2, _3));
 	registerCommand("part", Owner, "Leave a MUC", boost::bind(&Commands::handlePartCommand, this, _1, _2, _3));
 	registerCommand("rehash", Owner, "Reload scripts", boost::bind(&Commands::handleRehashCommand, this, _1, _2, _3));
+	registerCommand("restart", Owner, "Restart bot", boost::bind(&Commands::handleRestartCommand, this, _1, _2, _3));
+	registerCommand("nick", Owner, "Change nick (requires restart)", boost::bind(&Commands::handleChangeNick, this, _1, _2, _3));
+	//registerCommand("owner", Owner, "Change owner settinsg", boost::bind(&Commands::handleChangeOwner, this, _1, _2, _3));
 	onReset();
 }
 
@@ -76,6 +89,27 @@ bool Commands::roleIn(const Users::User::Role userRole, RoleList roleList) {
 	return false;
 }
 
+void Commands::handleChangeNick(const std::string& /*command*/, const std::string& params, Swift::Message::ref message) {
+	std::string nick(params);
+	boost::algorithm::trim(nick);
+	if (nick.empty()) {
+		replyTo(message, "Current nick is '" + mucs_->getDefaultNick() + "'. Run the command with a new nick to change it.");
+	}
+	else {
+		if (mucs_->setDefaultNick(params)) {
+			replyTo(message, "Default nick now set to '" + nick + "' - restart the bot for this to take effect.");
+		}
+		else {
+			replyTo(message, "Can't set invalid nick '" + nick + "'.");
+		}
+	}
+}
+
+void Commands::handleChangeOwner(const std::string& /*command*/, const std::string& /*params*/, Swift::Message::ref /*message*/) {
+	/* Oh, right. I don't have user persistence coded yet.
+	 * Probably not worth doing this until I have.*/
+}
+
 void Commands::handleQuitCommand(const std::string& /*command*/, const std::string& /*params*/, Swift::Message::ref message) {
 	replyTo(message, "Shutting down");
 	std::cout << "Quitting at the behest of " << message->getFrom().toString() << std::endl;
@@ -102,6 +136,13 @@ void Commands::handleRehashCommand(const std::string& /*command*/, const std::st
 	}
 }
 
+void Commands::handleRestartCommand(const std::string& /*command*/, const std::string& /*params*/, Swift::Message::ref message) {
+	rehashError_ = "";
+	replyTo(message, "Restarting now.");
+	std::cout << "Restarting at the behest of " << message->getFrom().toString() << std::endl;
+	onRestartRequested();
+}
+
 void Commands::handleJoinCommand(const std::string& /*command*/, const std::string& params, Swift::Message::ref message) {
 	Swift::JID room(params);
 	if (!room.isValid() || !room.getResource().empty() || room.getNode().empty()) {
diff --git a/Swiftob/Commands.h b/Swiftob/Commands.h
index 5c55f39..d5aac2c 100644
--- a/Swiftob/Commands.h
+++ b/Swiftob/Commands.h
@@ -42,6 +42,7 @@ class Commands {
 
 	public:
 		Commands(Users* users, Swift::Client* client, Storage* storage, MUCs* mucs);
+		~Commands();
 		bool hasCommand(const std::string&);
 		bool runCommand(const std::string& command, const std::string& params, Swift::Message::ref message);
 		void runListeners(Swift::Message::ref message);
@@ -53,7 +54,9 @@ class Commands {
 
 	public:
 		boost::signal<void ()> onReset;
+		boost::signal<void ()> onRestartRequested;
 	private:
+		void clearCommands();
 		bool roleIn(const Users::User::Role userRole, RoleList roles);
 		void handleQuitCommand(const std::string& command, const std::string& params, Swift::Message::ref message);
 		void handleHelpCommand(const std::string& command, const std::string& params, Swift::Message::ref message);
@@ -62,6 +65,9 @@ class Commands {
 		void handleJoinCommandFailure(const Swift::JID& room, const std::string& error, Swift::Message::ref message);
 		void handlePartCommand(const std::string& /*command*/, const std::string& params, Swift::Message::ref message);
 		void handleRehashCommand(const std::string& command, const std::string& params, Swift::Message::ref message);
+		void handleRestartCommand(const std::string& command, const std::string& params, Swift::Message::ref message);
+		void handleChangeNick(const std::string& command, const std::string& params, Swift::Message::ref message);
+		void handleChangeOwner(const std::string& command, const std::string& params, Swift::Message::ref message);
 	private:
 		std::map<std::string, Command*> commands_;
 		std::vector<ListenerCallback> listeners_;
diff --git a/Swiftob/MUCs.cpp b/Swiftob/MUCs.cpp
index 695cbd9..5bad3a1 100644
--- a/Swiftob/MUCs.cpp
+++ b/Swiftob/MUCs.cpp
@@ -18,12 +18,17 @@
 #include <Swiftob/Storage.h>
 
 #define MUC_LIST_SETTING "muc_list"
+#define NICK "default_nick"
 
 typedef std::pair<JID, MUC::ref> JIDMUCPair;
 
 MUCs::MUCs(Client* client, Storage* storage) : defaultNick_("Kanchil+") {
 	client_ = client;
 	storage_ = storage;
+	std::string storedNick = storage_->getSetting(NICK);
+	if (!storedNick.empty()) {
+		defaultNick_ = storedNick;
+	}
 	client_->onConnected.connect(boost::bind(&MUCs::handleConnected, this));
 }
 
@@ -118,3 +123,13 @@ void MUCs::save() {
 MUC::ref MUCs::getMUC(const JID& room) {
 	return (mucs_.find(room) != mucs_.end()) ? mucs_[room] : MUC::ref();
 }
+
+bool MUCs::setDefaultNick(const std::string& nick) {
+	JID testJID("alice", "wonderland.lit", nick);
+	if (testJID.isValid()) {
+		defaultNick_ = testJID.getResource();
+		storage_->saveSetting(NICK, defaultNick_);
+		return true;
+	}
+	return false;
+}
diff --git a/Swiftob/MUCs.h b/Swiftob/MUCs.h
index e727ec2..8f56182 100644
--- a/Swiftob/MUCs.h
+++ b/Swiftob/MUCs.h
@@ -30,6 +30,8 @@ class MUCs {
 		void part(const JID& room);
 		bool contains(const JID& room);
 		MUC::ref getMUC(const JID& room);
+		const std::string& getDefaultNick() const {return defaultNick_;}
+		bool setDefaultNick(const std::string& nick);
 	private:
 		void handleConnected();
 		void handleJoinFailed(const JID& room, ErrorPayload::ref error, boost::function<void(const std::string& /*reason*/)> failureCallback);
diff --git a/Swiftob/Swiftob.cpp b/Swiftob/Swiftob.cpp
index 6f36b3d..1578e34 100644
--- a/Swiftob/Swiftob.cpp
+++ b/Swiftob/Swiftob.cpp
@@ -32,14 +32,14 @@ po::options_description Swiftob::getOptionsDescription() {
 }
 
 Swiftob::Swiftob(const po::variables_map& options) : options_(options), networkFactories_(&eventLoop_), quitting_(false) {
-	std::string path;
-	path = options["path"].as<std::string>();
+	path_ = options["path"].as<std::string>();
 	client_ = new Swift::Client(Swift::JID(options["jid"].as<std::string>()), options["password"].as<std::string>(), &networkFactories_);
-	storage_ = new Storage(boost::filesystem::path(path) / "settings.txt");
-	mucs_ = new MUCs(client_, storage_);
-	users_ = new Users(client_, mucs_);
-	commands_ = new Commands(users_, client_, storage_, mucs_);
-	lua_ = new LuaCommands(commands_, path, client_, networkFactories_.getTimerFactory(), mucs_);
+	storage_ = new Storage(boost::filesystem::path(path_) / "settings.txt");
+	mucs_ = NULL;
+	users_ = NULL;
+	commands_ = NULL;
+	lua_ = NULL;
+	init();
 	client_->onConnected.connect(boost::bind(&Swiftob::handleConnected, this));
 	client_->onDisconnected.connect(boost::bind(&Swiftob::handleDisconnected, this, _1));
 	client_->onMessageReceived.connect(boost::bind(&Swiftob::handleMessageReceived, this, _1));
@@ -54,6 +54,23 @@ Swiftob::Swiftob(const po::variables_map& options) : options_(options), networkF
 	eventLoop_.run();
 }
 
+void Swiftob::init() {
+	delete mucs_;
+	mucs_ = new MUCs(client_, storage_);
+	delete users_;
+	users_ = new Users(client_, mucs_);
+	delete commands_;
+	commands_ = new Commands(users_, client_, storage_, mucs_);
+	commands_->onRestartRequested.connect(boost::bind(&Swiftob::handleRestartRequested, this));
+	delete lua_;
+	lua_ = new LuaCommands(commands_, path_, client_, networkFactories_.getTimerFactory(), mucs_);
+}
+
+void Swiftob::handleRestartRequested() {
+	client_->disconnect();
+	init();
+}
+
 void Swiftob::handleConnected() {
 	std::cout << "Connected" << std::endl;
 	if (options_.count("init") > 0) {}{ /* FIXME: Not ready for persistence yet*/
diff --git a/Swiftob/Swiftob.h b/Swiftob/Swiftob.h
index ad4e9b8..36091e4 100644
--- a/Swiftob/Swiftob.h
+++ b/Swiftob/Swiftob.h
@@ -32,6 +32,8 @@ class Swiftob {
 		int exec();
 		~Swiftob();
 	private:
+		void init();
+		void handleRestartRequested();
 		void handleConnected();
 		void handleDisconnected(const boost::optional<Swift::ClientError>&);
 		void handleMessageReceived(Swift::Message::ref);
@@ -45,5 +47,6 @@ class Swiftob {
 		MUCs* mucs_;
 		bool quitting_;
 		Users* users_;
+		std::string path_;
 		Swift::Client* client_;
 };
-- 
cgit v0.10.2-6-g49f6