Browse Source

Merge branch 'us29-cli-batch-mode' into 'develop'

US29: CLI Batch Mode

See merge request tobias.wach/ccats!52
Serdyukov, Denys 4 năm trước cách đây
mục cha
commit
8bbc6644ae

+ 1 - 2
cli/CMakeLists.txt

@@ -4,8 +4,7 @@ cmake_minimum_required(VERSION 2.8)
 
 project(ccats-cli)
 
-# add_executable(ccats-cli src/main.cpp src/ioman.cpp src/machineioman.cpp src/userioman.cpp src/base64.cpp src/netman.cpp src/cmdman.cpp src/fileman.cpp)
-add_executable(ccats-cli src/main.cpp src/ioman.cpp src/machineioman.cpp src/userioman.cpp src/base64.cpp src/cmdman.cpp src/fileman.cpp)
+add_executable(ccats-cli src/main.cpp src/ioman.cpp src/machineioman.cpp src/userioman.cpp src/batchioman.cpp src/base64.cpp src/cmdman.cpp src/fileman.cpp)
 
 # use pkg-config to find readline as it doesnt provide cmake files
 find_package(PkgConfig REQUIRED)

+ 100 - 0
cli/include/batchioman.h

@@ -0,0 +1,100 @@
+#ifndef BATCHIOMAN_H
+#define BATCHIOMAN_H
+
+#include "ioman.h"
+#include <fstream>
+#include <vector>
+#include <string>
+
+/**
+ * @class BatchIoMan
+ *
+ * Provides specific implementations of IoMan outputs and prompts
+ * for unattended sessions
+ */
+class BatchIoMan : public IoMan {
+private:
+	/**
+	 * Map containing pointers to the appropriate member functions for printing
+	 * formatted json output
+	 */
+	map<string, std::string (BatchIoMan::*)(Json::Value)> printmap;
+
+	/**
+	 * Class-wide json functionality
+	 */
+	Json::CharReader *reader;
+	Json::StreamWriterBuilder wbuilder;
+	string jsonerror;
+
+
+	std::ofstream normalout;
+	std::ofstream errorout;
+	std::ofstream debugout;
+	std::ifstream batchin;
+
+	/**
+	 * Mutex for synchronized message output
+	 */
+	std::recursive_mutex msgmutex;
+
+	bool getnextline;
+	std::mutex linemutex;
+	std::condition_variable linecv;
+	
+	/**
+	 * Format and pretty print json for logfile output
+	 */
+	std::string printJson(Json::Value root);
+	
+	/**
+	 * Method prototypes for printing json output
+	 */
+	/* printing commands go here */
+	std::string printError(Json::Value root);
+	std::string printConnect(Json::Value root);
+	std::string printHelp(Json::Value root);
+	std::string printStatus(Json::Value root);
+	std::string printDisconnect(Json::Value root);
+	std::string printPut(Json::Value root);
+	std::string printGet(Json::Value root);
+	std::string printList(Json::Value root);
+	std::string printVersion(Json::Value root);
+	std::string printLogin(Json::Value root);
+	std::string printSignup(Json::Value root);
+	std::string printPutdata(Json::Value root);
+	std::string printGetdata(Json::Value root);
+	std::string printListdata(Json::Value root);
+	std::string printHead(Json::Value root);
+	std::string printDeletefile(Json::Value root);
+	std::string printDeleteme(Json::Value root);
+	std::string printKeyfile(Json::Value root);
+	std::string printClosekey(Json::Value root);
+
+public:
+	/**
+	 * Constructor and destructor
+	 */
+	BatchIoMan(char *ipcstring);
+	BatchIoMan(char *ipcstring, bool usessl, string batchpath);
+	~BatchIoMan();
+
+	bool init();
+	void run();
+
+protected:
+	/**
+	 * Specific implementations for printing messages
+	 */
+	void printMessage(std::string msg, OutMsgType type);
+	void printWelcomeMessage();
+	void handleInCmdResponse(CmdMan::CmdRet cmdret);
+	void handleOutCmdResponse(CmdMan::CmdRet cmdret, std::vector<std::string> &toput);
+
+	/**
+	 * Return the specific prompt strings for IoMan prompts
+	 */
+	std::string getCmdPrompt();
+};
+
+#endif

+ 36 - 34
cli/include/ioman.h

@@ -50,15 +50,39 @@ public:
 	std::vector<std::string> localinput;
 	std::condition_variable localcv;
 
+protected:
+	/**
+	 * Prompt messages for readline prompt
+	 */
+	virtual void printWelcomeMessage() = 0;
+	virtual std::string getCmdPrompt() = 0;
+
+	/**
+	 * Enum for internal login and version state
+	 * Variables for keeping said state
+	 * Matching mutex and condition variable
+	 */
+	enum Status { off, on, err };
+	Status loginstatus;
+	Status versionstatus;
+	std::mutex initmutex;
+	std::condition_variable initcv;
+	bool connected;
+	
+	virtual void handleInCmdResponse(CmdMan::CmdRet cmdret);
+	virtual void handleOutCmdResponse(CmdMan::CmdRet cmdret, vector<string> &toput);
+	
+	boost::system::error_code errcode;
+	tcp::socket *tcpsock;
+	boost::asio::ssl::stream<tcp::socket&> *sslsock;
+	bool usessl;
+	
 private:
 	/**
 	 * Internal state to provide class-wide asio networking functionality
 	 */
 	boost::asio::io_service ios;
 	boost::asio::streambuf recvbuf;
-	boost::system::error_code errcode;
-	tcp::socket *tcpsock;
-	boost::asio::ssl::stream<tcp::socket&> *sslsock;
 	boost::asio::ssl::context *sslctx;
 	/**
 	 * The IP and port to connect to
@@ -66,14 +90,19 @@ private:
 	 */
 	std::string ipstring;
 	unsigned short port;
-	bool connected;
-	bool usessl;
 	/**
 	 * Instances of CmdMan and FileMan to process user input and handle File I/O
 	 */
 	CmdMan cmdman;
 	FileMan fileman;
 
+	/**
+	 * Class-wide json functionality
+	 */
+	Json::CharReader *reader;
+	Json::StreamWriterBuilder wbuilder;
+	string jsonerror;
+
 	/**
 	 * Thread handles for processing local and network input as well as generating
 	 * responses to both Matching mutexes for the flags wether the threads should
@@ -95,23 +124,7 @@ private:
 	std::mutex netmutex;
 	std::condition_variable netcv;
 
-	/**
-	 * Class-wide json functionality
-	 */
-	Json::CharReader *reader;
-	Json::StreamWriterBuilder wbuilder;
-	string jsonerror;
 
-	/**
-	 * Enum for internal login and version state
-	 * Variables for keeping said state
-	 * Matching mutex and condition variable
-	 */
-	enum Status { off, on, err };
-	Status versionstatus;
-	Status loginstatus;
-	std::mutex initmutex;
-	std::condition_variable initcv;
 
 	/**
 	 * Tokenizes input based on space as seperator
@@ -120,17 +133,6 @@ private:
 	 */
 	std::vector<std::string> tokenizeInput(std::string in);
 
-protected:
-	/**
-	 * Prompt messages for readline prompt
-	 */
-	virtual void printWelcomeMessage() = 0;
-	virtual std::string getCmdPrompt() = 0;
-	// following prompts currently not in use because login happens by entering
-	// command
-	//~  virtual std::string getUserPrompt() = 0;
-	//~  virtual std::string getPassPrompt() = 0;
-
 public:
 	/**
 	 * Constructor and destructor
@@ -143,12 +145,12 @@ public:
 	 * Establish connection to server and perform vesion check
 	 * Return true if successful, false otherwise
 	 */
-	bool init();
+	virtual bool init();
 
 	/**
 	 * Main loop, call init first
 	 */
-	void run();
+	virtual void run();
 
 	/**
 	 * Establish connection to server

+ 0 - 2
cli/include/machineioman.h

@@ -24,8 +24,6 @@ protected:
 	 * Return the specific prompt strings for IoMan prompts
 	 */
 	std::string getCmdPrompt();
-	std::string getUserPrompt();
-	std::string getPassPrompt();
 };
 
 #endif

+ 0 - 2
cli/include/userioman.h

@@ -77,8 +77,6 @@ protected:
 	 * Return the specific prompt strings for IoMan prompts
 	 */
 	std::string getCmdPrompt();
-	std::string getUserPrompt();
-	std::string getPassPrompt();
 };
 
 #endif

+ 396 - 0
cli/src/batchioman.cpp

@@ -0,0 +1,396 @@
+#include "../include/batchioman.h"
+
+#include <iostream>
+#include <vector>
+#include <string>
+
+BatchIoMan::BatchIoMan(char *ipcstring) : IoMan(ipcstring) {};
+
+BatchIoMan::BatchIoMan(char *ipcstring, bool usessl, std::string batchpath) : IoMan(ipcstring, usessl) {
+	batchin.open(batchpath);
+	normalout.open(batchpath + ".out");
+	debugout.open(batchpath + ".debug");
+	errorout.open(batchpath + ".err");
+	
+	/* setup json stuff */
+	Json::CharReaderBuilder rbuilder;
+	wbuilder.settings_["indentation"] = "";
+	reader = rbuilder.newCharReader();
+
+	/* initialize print command map */
+	printmap["error"] = &BatchIoMan::printError;
+	printmap["connect"] = &BatchIoMan::printConnect;
+	printmap["help"] = &BatchIoMan::printHelp;
+	printmap["status"] = &BatchIoMan::printStatus;
+	printmap["disconnect"] = &BatchIoMan::printDisconnect;
+	printmap["put"] = &BatchIoMan::printPut;
+	printmap["get"] = &BatchIoMan::printGet;
+	printmap["list"] = &BatchIoMan::printList;
+	printmap["version"] = &BatchIoMan::printVersion;
+	printmap["login"] = &BatchIoMan::printLogin;
+	printmap["signup"] = &BatchIoMan::printSignup;
+	printmap["putdata"] = &BatchIoMan::printPutdata;
+	printmap["getdata"] = &BatchIoMan::printGetdata;
+	printmap["head"] = &BatchIoMan::printHead;
+	printmap["deletefile"] = &BatchIoMan::printDeletefile;
+	printmap["deleteme"] = &BatchIoMan::printDeleteme;
+	printmap["keyfile"] = &BatchIoMan::printKeyfile;
+	printmap["closekey"] = &BatchIoMan::printClosekey;
+	
+	getnextline = false;
+}
+
+bool BatchIoMan::init() {
+	if(!batchin.is_open() || !normalout.is_open() || !debugout.is_open() || !errorout.is_open()) return false;
+	return IoMan::init();
+}
+
+BatchIoMan::~BatchIoMan() {
+	batchin.close();
+	normalout.close();
+	debugout.close();
+	errorout.close();
+	delete reader;
+}
+
+void BatchIoMan::printMessage(std::string msg, OutMsgType type) {
+	Json::Value root;
+	msgmutex.lock();
+	switch (type) {
+	case normal: {
+		// this should never happen outside of development
+		if (!reader->parse(msg.c_str(), msg.c_str() + msg.size(), &root, &jsonerror)) {
+			printMessage(string(__PRETTY_FUNCTION__) + " couldnt parse json data: " + jsonerror, debug);
+		} else {
+			normalout << printJson(root) << std::endl;
+		}
+		break;
+	}
+	case error: {
+		// this should never happen outside of development
+		if (!reader->parse(msg.c_str(), msg.c_str() + msg.size(), &root, &jsonerror)) {
+			printMessage(string(__PRETTY_FUNCTION__) + " couldnt parse json data: " + jsonerror, debug);
+		} else {
+			errorout << printJson(root) << std::endl;
+		}
+		break;
+	}
+	case debug: {
+		debugout << msg << std::endl;
+		break;
+	}
+	}
+	msgmutex.unlock();
+}
+
+void BatchIoMan::printWelcomeMessage() {}
+
+std::string BatchIoMan::getCmdPrompt() { return ""; }
+
+/* modified handleInCmdResponse to abort on error */
+void BatchIoMan::handleInCmdResponse(CmdMan::CmdRet cmdret) {
+	// determine wether to send something and do so if required
+	if (cmdret.type & CmdMan::rettype::print) {
+		printMessage(Json::writeString(wbuilder, cmdret.msg), normal);
+		if(!(cmdret.type ^ CmdMan::rettype::print)) {
+			// xor here works because flag is set at this point
+			// if we only printed something get the next line
+			linemutex.lock();
+			printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug);
+			getnextline = true;
+			linemutex.unlock();
+			printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug);
+			linecv.notify_all();
+		}
+	}
+	if (cmdret.type & CmdMan::rettype::send) {
+		printMessage("IoMan::inputMain() sending json \"" + Json::writeString(wbuilder, cmdret.msg) + "\"", debug);
+		if(usessl) boost::asio::write(*sslsock, boost::asio::buffer(Json::writeString(wbuilder, cmdret.msg) + "\n"), errcode);
+		else boost::asio::write(*tcpsock, boost::asio::buffer(Json::writeString(wbuilder, cmdret.msg) + "\n"), errcode);
+		if (errcode) {
+			printMessage("IoMan::inputMain() couldnt send json data\n" + errcode.message() + "\n", error);
+			mainmutex.lock();
+			runmain = false;
+			mainmutex.unlock();
+			linemutex.lock();
+			printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug);
+			getnextline = true;
+			linemutex.unlock();
+			printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug);
+			linecv.notify_all();
+			return;
+		}
+	}
+	if (cmdret.type & CmdMan::rettype::error) {
+		printMessage(Json::writeString(wbuilder, cmdret.msg), error);
+		mainmutex.lock();
+		runmain = false;
+		mainmutex.unlock();
+		linemutex.lock();
+		printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug);
+		getnextline = true;
+		linemutex.unlock();
+		printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug);
+		linecv.notify_all();
+	}
+	if (cmdret.type & CmdMan::rettype::close) {
+		/* TODO i dunno */
+		mainmutex.lock();
+		runmain = false;
+		mainmutex.unlock();
+		linemutex.lock();
+		printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug);
+		getnextline = true;
+		linemutex.unlock();
+		printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug);
+		linecv.notify_all();
+	}
+}
+
+/* modified handleOutCmdResponse to fetch next command and abort on error */
+void BatchIoMan::handleOutCmdResponse(CmdMan::CmdRet cmdret, std::vector<std::string> &toput) {
+	if (cmdret.type & CmdMan::rettype::close) {
+		/* TODO i dunno */
+		mainmutex.lock();
+		runmain = false;
+		mainmutex.unlock();
+		linemutex.lock();
+		printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug);
+		getnextline = true;
+		linemutex.unlock();
+		printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug);
+		linecv.notify_all();
+		return;
+	}
+	if (cmdret.type & CmdMan::rettype::error) {
+		initmutex.lock();
+		if (versionstatus == off)
+			versionstatus = err;
+		else if (loginstatus == off)
+			loginstatus = err;
+		initmutex.unlock();
+		initcv.notify_all();
+		printMessage(Json::writeString(wbuilder, cmdret.msg), error);
+		mainmutex.lock();
+		runmain = false;
+		mainmutex.unlock();
+		linemutex.lock();
+		printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug);
+		getnextline = true;
+		linemutex.unlock();
+		printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug);
+		linecv.notify_all();
+		return;
+	}
+	if (cmdret.type & CmdMan::rettype::seton) {
+		initmutex.lock();
+		if (versionstatus == off)
+			versionstatus = on;
+		else
+			loginstatus = on;
+		initmutex.unlock();
+		initcv.notify_all();
+	}
+	if (cmdret.type & CmdMan::rettype::print) {
+		printMessage(Json::writeString(wbuilder, cmdret.msg), normal);
+	}
+	if (cmdret.type & CmdMan::rettype::send) {
+		printMessage(string(__PRETTY_FUNCTION__) + string(" send new cmd"), debug);
+		if (cmdret.nextcommand.size()) {
+			toput.push_back(cmdret.nextcommand);
+		}
+	}
+	if(versionstatus == on && !(cmdret.type & CmdMan::rettype::send)) {
+		// only fetch next line if we did not send a new command on our own
+		// if we managed to get here, get next command from file
+		linemutex.lock();
+		printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug);
+		getnextline = true;
+		linemutex.unlock();
+		printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug);
+		linecv.notify_all();
+	}
+}
+
+/* main user input loop */
+void BatchIoMan::run() {
+	std::string line;
+	printMessage(string(__PRETTY_FUNCTION__) + " begin", debug);
+	std::unique_lock<std::mutex> ulock;
+
+	runmain = true;
+	
+	mainmutex.lock();
+	while (runmain) {
+		mainmutex.unlock();
+		
+		line.erase();
+		ulock = std::unique_lock<std::mutex>(linemutex);
+		while (!getnextline && runmain) {
+			linecv.wait(ulock);
+		}
+		
+		if(!runmain) break;
+		printMessage(string(__PRETTY_FUNCTION__) + " fetch next line", debug);
+		while(!line.size()) {
+			// skip empty lines until either eof or non-empty line
+			if(batchin.eof()) {
+				line = "disconnect";
+			}
+			else std::getline(batchin, line);
+		}
+		
+		getnextline = false;
+		linemutex.unlock();
+		
+		localmutex.lock();
+		printMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex"), debug);
+		localinput.push_back(line);
+		localmutex.unlock();
+		printMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"), debug);
+		localcv.notify_all();
+		
+		if (!connected)
+			break;
+		if (loginstatus == err)
+			break;
+		
+		mainmutex.lock();
+	}
+	mainmutex.unlock();
+}
+
+
+std::string BatchIoMan::printJson(Json::Value root) {
+	map<string, std::string (BatchIoMan::*)(Json::Value)>::iterator it = printmap.find(root["command"].asString());
+	if (it == printmap.end()) {
+		// this should never happen outside of development
+		printMessage(string(__PRETTY_FUNCTION__) + " unknown command \"" + root["command"].asString() + "\".\nensure code is implemented.", debug);
+		return "";
+	}
+	return (this->*(printmap[root["command"].asString()]))(root);
+}
+
+std::string BatchIoMan::printError(Json::Value root) { return std::string("Error: ") + root["error"].asString(); }
+
+std::string BatchIoMan::printConnect(Json::Value root) {
+	if (!root["accept"].asBool()) {
+		return std::string("Couldnt connect to ") + root["address"].asString() + ":" + std::to_string(root["port"].asUInt()) + "\n"
+		          + "Reason: " + root["error"].asString();
+	}
+	return "";
+}
+
+std::string BatchIoMan::printHelp(Json::Value root) {
+	std::string ret = std::string("Available commands are: ") + "\n";
+	for (Json::Value i : root["names"])
+		ret += i.asString() + "\n";
+	return ret;
+}
+
+std::string BatchIoMan::printStatus(Json::Value root) { return std::string("Server reports status: ") + root["response"].asString(); }
+
+std::string BatchIoMan::printDisconnect(Json::Value root) {
+	if (!root["accept"].asBool()) {
+		return "Disconnect failed.";
+	} else {
+		return "Disconnect successful.";
+	}
+}
+
+std::string BatchIoMan::printPut(Json::Value root) {
+	if (!root["accept"].asBool()) {
+		if (root.isMember("file")) {
+			return std::string("Upload request for file ") + root["file"].asString() + " failed: " + root["error"].asString();
+		} else {
+			return std::string("Upload request failed: ") + root["error"].asString();
+		}
+	} else
+		return std::string("Begin uploading file ") + root["file"].asString();
+}
+
+std::string BatchIoMan::printGet(Json::Value root) {
+	if (!root["accept"].asBool()) {
+		if (root.isMember("file")) {
+			return std::string("Download request for file ") + root["file"].asString() + " failed: " + root["error"].asString();
+		} else {
+			return std::string("Download request failed: ") + root["error"].asString();
+		}
+	} else
+		return std::string("Begin downloading file ") + root["file"].asString();
+}
+
+std::string BatchIoMan::printList(Json::Value root) {
+	std::string ret;
+	if (!root["accept"].asBool()) {
+		ret = std::string("Listing files failed: ") + root["error"].asString();
+	} else {
+		ret = std::string("Listing files stored on server: ") + "\n";
+		for (Json::Value i : root["names"])
+			ret += i.asString() + "\n";
+		ret += "End of list.";
+	}
+	return ret;
+}
+
+std::string BatchIoMan::printVersion(Json::Value root) {
+	if (!root["accept"].asBool()) {
+		return std::string("Version check failed. Server reports ") + root["serverversion"].asString() + " but client is " + root["clientversion"].asString();
+	} else
+		return "Version check ok.";
+}
+
+std::string BatchIoMan::printLogin(Json::Value root) {
+	if (!root["accept"].asBool()) {
+		return std::string("Login failed: ") + root["error"].asString();
+	} else
+		return "Login ok.";
+}
+
+std::string BatchIoMan::printSignup(Json::Value root) {
+	if (!root["accept"].asBool()) {
+		return std::string("Signup failed: ") + root["error"].asString();
+	} else
+		return "Signup ok. You are now logged in.";
+}
+
+std::string BatchIoMan::printDeleteme(Json::Value root) {
+	if (!root["accept"].asBool()) {
+		return std::string("User deletion failed: ") + root["error"].asString();
+	} else
+		return "User deletion ok. You are now disconnected from the server.";
+}
+
+std::string BatchIoMan::printPutdata(Json::Value root) { return ""; }
+
+std::string BatchIoMan::printGetdata(Json::Value root) { return ""; }
+
+std::string BatchIoMan::printListdata(Json::Value root) { return ""; }
+
+std::string BatchIoMan::printHead(Json::Value root) {
+	if (!root["accept"].asBool())
+		return std::string("Request of the first four bytes failed. ") + root["error"].asString();
+	else
+		return std::string("First four bytes of file ") + root["file"].asString() + " are: " + root["data"].asString();
+}
+
+std::string BatchIoMan::printDeletefile(Json::Value root) {
+	if (!root["accept"].asBool())
+		return std::string("Deletion of file ") + root["file"].asString() + " failed. " + root["error"].asString();
+	else
+		return std::string("File ") + root["file"].asString() + " deleted succesfully";
+}
+
+std::string BatchIoMan::printKeyfile(Json::Value root) {
+	if (!root["accept"].asBool())
+		return std::string("Couldnt select keyfile ") + root["file"].asString() + ": " + root["error"].asString();
+	else
+		return std::string("Using keyfile ") + root["file"].asString();
+}
+
+std::string BatchIoMan::printClosekey(Json::Value root) {
+	if (!root["accept"].asBool())
+		return std::string("Failed to close key: ") + root["error"].asString();
+	else
+		return "Key closed.";
+}

+ 67 - 58
cli/src/ioman.cpp

@@ -86,7 +86,7 @@ IoMan::~IoMan() {
 
 	if(usessl) delete sslsock;
 	delete tcpsock;
-	delete sslctx;
+	if(usessl) delete sslctx;
 	delete reader;
 }
 
@@ -191,7 +191,8 @@ bool IoMan::connect() {
 
 void IoMan::disconnect() {
 	printMessage("IoMan::disconnect()", debug);
-	tcpsock->close();
+	tcpsock->shutdown(tcp::socket::shutdown_both, errcode);
+	if(errcode) printMessage(string(__PRETTY_FUNCTION__) + string("tcp shutdown says ") + errcode.message(), error);
 	connected = false;
 }
 
@@ -365,29 +366,8 @@ void IoMan::inputMain() {
 			command = args.front();
 			args.erase(args.begin());
 			cmdret = cmdman.execute(command, args);
-
-			// determine wether to send something and do so if required
-			if (cmdret.type & CmdMan::rettype::print) {
-				printMessage(Json::writeString(wbuilder, cmdret.msg), normal);
-			}
-			if (cmdret.type & CmdMan::rettype::send) {
-				printMessage("IoMan::inputMain() sending json \"" + Json::writeString(wbuilder, cmdret.msg) + "\"", debug);
-				if(usessl) boost::asio::write(*sslsock, buffer(Json::writeString(wbuilder, cmdret.msg) + "\n"), errcode);
-				else boost::asio::write(*tcpsock, buffer(Json::writeString(wbuilder, cmdret.msg) + "\n"), errcode);
-				if (errcode) {
-					printMessage("IoMan::inputMain() couldnt send json data\n" + errcode.message() + "\n", error);
-					continue;
-				}
-			}
-			if (cmdret.type & CmdMan::rettype::error) {
-				printMessage(Json::writeString(wbuilder, cmdret.msg), error);
-			}
-			if (cmdret.type & CmdMan::rettype::close) {
-				/* TODO i dunno */
-				mainmutex.lock();
-				runmain = false;
-				mainmutex.unlock();
-			}
+			
+			handleInCmdResponse(cmdret);
 		}
 
 		// clean up local stuff
@@ -396,6 +376,31 @@ void IoMan::inputMain() {
 	}
 }
 
+void IoMan::handleInCmdResponse(CmdMan::CmdRet cmdret) {
+	// determine wether to send something and do so if required
+	if (cmdret.type & CmdMan::rettype::print) {
+		printMessage(Json::writeString(wbuilder, cmdret.msg), normal);
+	}
+	if (cmdret.type & CmdMan::rettype::send) {
+		printMessage("IoMan::inputMain() sending json \"" + Json::writeString(wbuilder, cmdret.msg) + "\"", debug);
+		if(usessl) boost::asio::write(*sslsock, buffer(Json::writeString(wbuilder, cmdret.msg) + "\n"), errcode);
+		else boost::asio::write(*tcpsock, buffer(Json::writeString(wbuilder, cmdret.msg) + "\n"), errcode);
+		if (errcode) {
+			printMessage("IoMan::inputMain() couldnt send json data\n" + errcode.message() + "\n", error);
+			return;
+		}
+	}
+	if (cmdret.type & CmdMan::rettype::error) {
+		printMessage(Json::writeString(wbuilder, cmdret.msg), error);
+	}
+	if (cmdret.type & CmdMan::rettype::close) {
+		/* TODO i dunno */
+		mainmutex.lock();
+		runmain = false;
+		mainmutex.unlock();
+	}
+}
+
 /* loop to handle responses that have been fetched by netMain and possibly add
  * new commands to be handled by inputMain */
 void IoMan::responseMain() {
@@ -441,39 +446,7 @@ void IoMan::responseMain() {
 		// process jsons
 		for (Json::Value root : toprocess) {
 			cmdret = cmdman.handle(root);
-			if (cmdret.type & CmdMan::rettype::close) {
-				/* TODO i dunno */
-				mainmutex.lock();
-				runmain = false;
-				mainmutex.unlock();
-			}
-			if (cmdret.type & CmdMan::rettype::error) {
-				initmutex.lock();
-				if (versionstatus == off)
-					versionstatus = err;
-				else if (loginstatus == off)
-					loginstatus = err;
-				initmutex.unlock();
-				initcv.notify_all();
-				printMessage(Json::writeString(wbuilder, cmdret.msg), error);
-			}
-			if (cmdret.type & CmdMan::rettype::seton) {
-				initmutex.lock();
-				if (versionstatus == off)
-					versionstatus = on;
-				else
-					loginstatus = on;
-				initmutex.unlock();
-				initcv.notify_all();
-			}
-			if (cmdret.type & CmdMan::rettype::print) {
-				printMessage(Json::writeString(wbuilder, cmdret.msg), normal);
-			}
-			if (cmdret.type & CmdMan::rettype::send) {
-				if (cmdret.nextcommand.size()) {
-					toput.push_back(cmdret.nextcommand);
-				}
-			}
+			handleOutCmdResponse(cmdret, toput);
 		}
 
 		if (toput.size()) {
@@ -493,6 +466,42 @@ void IoMan::responseMain() {
 	}
 }
 
+void IoMan::handleOutCmdResponse(CmdMan::CmdRet cmdret, vector<string> &toput) {
+	if (cmdret.type & CmdMan::rettype::close) {
+		/* TODO i dunno */
+		mainmutex.lock();
+		runmain = false;
+		mainmutex.unlock();
+	}
+	if (cmdret.type & CmdMan::rettype::error) {
+		initmutex.lock();
+		if (versionstatus == off)
+			versionstatus = err;
+		else if (loginstatus == off)
+			loginstatus = err;
+		initmutex.unlock();
+		initcv.notify_all();
+		printMessage(Json::writeString(wbuilder, cmdret.msg), error);
+	}
+	if (cmdret.type & CmdMan::rettype::seton) {
+		initmutex.lock();
+		if (versionstatus == off)
+			versionstatus = on;
+		else
+			loginstatus = on;
+		initmutex.unlock();
+		initcv.notify_all();
+	}
+	if (cmdret.type & CmdMan::rettype::print) {
+		printMessage(Json::writeString(wbuilder, cmdret.msg), normal);
+	}
+	if (cmdret.type & CmdMan::rettype::send) {
+		if (cmdret.nextcommand.size()) {
+			toput.push_back(cmdret.nextcommand);
+		}
+	}
+}
+
 /* this is the handler that readlines alternative interface will use to process
  * user input */
 void ioman_readlineHandler(char *line) {

+ 0 - 7
cli/src/machineioman.cpp

@@ -1,15 +1,8 @@
 #include "../include/machineioman.h"
 
-#include <boost/algorithm/string.hpp>
-#include <fstream>
 #include <iostream>
-#include <limits>
 #include <vector>
 
-#include <readline/readline.h>
-
-using boost::asio::buffer;
-
 void MachineIoMan::printMessage(std::string msg, OutMsgType type) {
 	switch (type) {
 	case normal: {

+ 6 - 3
cli/src/main.cpp

@@ -1,5 +1,6 @@
 #include "../include/machineioman.h"
 #include "../include/userioman.h"
+#include "../include/batchioman.h"
 
 #include <boost/program_options.hpp>
 #include <iostream>
@@ -22,7 +23,7 @@ int main(int argc, char **argv) {
 	    "batch", bpo::value<std::string>(), "run operations from arg as batch file")("usessl", "enable ssl for connection to server");
 
 	bpo::variables_map vm;
-	bool machine = false, usessl = false;
+	bool machine = false, usessl = false, batch = false;
 	const char *file = NULL;
 	IoMan *ioman;
 
@@ -48,6 +49,7 @@ int main(int argc, char **argv) {
 		if (vm.count("batch")) {
 			// handle batch file mode
 			file = vm["batch"].as<std::string>().c_str();
+			batch = true;
 		}
 		if (vm.count("usessl")) {
 			usessl = true;
@@ -56,8 +58,9 @@ int main(int argc, char **argv) {
 		std::fprintf(stderr, "%s\n", ex.what());
 	}
 	std::printf("ip %s machine mode is %d file is %s enablessl is %d\n", argv[1], machine, file ? file : "", usessl);
-
-	if (machine) {
+	if(batch) {
+		ioman = new BatchIoMan(argv[1], usessl, file);
+	} else if (machine) {
 		ioman = new MachineIoMan(argv[1], usessl);
 	} else {
 		ioman = new UserIoMan(argv[1], usessl);

+ 0 - 7
cli/src/userioman.cpp

@@ -1,19 +1,12 @@
 #include "../include/userioman.h"
 
-#include <boost/algorithm/string.hpp>
-#include <fstream>
 #include <iostream>
 #include <vector>
-
-#include <readline/history.h>
 #include <readline/readline.h>
 
-using boost::asio::buffer;
-
 UserIoMan::UserIoMan(char *ipcstring) : IoMan(ipcstring) {};
 
 UserIoMan::UserIoMan(char *ipcstring, bool usessl) : IoMan(ipcstring, usessl) {
-
 	/* setup json stuff */
 	Json::CharReaderBuilder rbuilder;
 	wbuilder.settings_["indentation"] = "";