diff options
-rw-r--r-- | src/Client/CommandParser.cpp | 3 | ||||
-rw-r--r-- | src/Client/UserCommands.cpp | 43 | ||||
-rw-r--r-- | src/Client/UserCommands.h | 2 | ||||
-rw-r--r-- | src/Common/Backends/NetworkUserBackend.cpp | 28 | ||||
-rw-r--r-- | src/Common/Backends/NetworkUserBackend.h | 15 | ||||
-rw-r--r-- | src/Common/UserManager.cpp | 22 | ||||
-rw-r--r-- | src/Core/Exception.cpp | 2 | ||||
-rw-r--r-- | src/Core/Exception.h | 3 | ||||
-rw-r--r-- | src/Server/RequestHandlers/UserRequestHandlerGroup.cpp | 13 | ||||
-rw-r--r-- | src/Server/RequestHandlers/UserRequestHandlerGroup.h | 2 | ||||
-rw-r--r-- | src/mad-server.conf | 1 | ||||
-rw-r--r-- | src/mad-server.cpp | 1 | ||||
-rw-r--r-- | src/madc.cpp | 2 | ||||
-rw-r--r-- | src/modules/UserBackendMysql/UserBackendMysql.cpp | 111 | ||||
-rw-r--r-- | src/modules/UserBackendMysql/UserBackendMysql.h | 51 |
15 files changed, 245 insertions, 54 deletions
diff --git a/src/Client/CommandParser.cpp b/src/Client/CommandParser.cpp index 842be7f..92b1169 100644 --- a/src/Client/CommandParser.cpp +++ b/src/Client/CommandParser.cpp @@ -17,6 +17,8 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <config.h> + #include "CommandParser.h" #include "Application.h" #include "InformationManager.h" @@ -49,6 +51,7 @@ const CommandParser::Command CommandParser::commands[] = { {{"list_groups", "groups", 0}, "list_groups", "Show the user group database", "Show the user group database.", &UserCommands::listGroupsCommand}, {{"group_info", "group", 0}, "group_info gid|name", "Search for a group id", "Search for a group.", &UserCommands::groupInfoCommand}, {{"list_group_users", "group_users", 0}, "list_group_users gid", "List group's users", "List the users that are members of the group.", &UserCommands::listGroupUsersCommand}, + {{"add_user", 0}, "add_user uid gid username full_name", "Add a new user", "Adds a new user with the given info to the account database.", &UserCommands::addUserCommand}, {{"exit", "quit", 0}, "exit", "Close the connection and quit the client", "Close the connection and quit the client.", &CommandParser::exitCommand}, {{0}, 0, 0, 0, 0} }; diff --git a/src/Client/UserCommands.cpp b/src/Client/UserCommands.cpp index fec2a33..9fcaa36 100644 --- a/src/Client/UserCommands.cpp +++ b/src/Client/UserCommands.cpp @@ -17,6 +17,8 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <config.h> + #include "UserCommands.h" #include "Application.h" #include "CommandParser.h" @@ -221,5 +223,46 @@ void UserCommands::listGroupUsersCommand(CommandParser *commandParser, const std } } +void UserCommands::addUserCommand(CommandParser *commandParser, const std::vector<std::string> &args) { + if(args.size() < 5) { + std::cerr << args[0] << ": Too few arguments." << std::endl; + commandParser->printUsage("add_user"); + return; + } + if(args.size() > 5) { + std::cerr << args[0] << ": Too many arguments." << std::endl; + commandParser->printUsage("add_user"); + return; + } + + char *endptr; + unsigned long uid = std::strtoul(args[1].c_str(), &endptr, 10); + if(args[1].empty() || *endptr != '\0') { + std::cerr << args[0] << ": Unable to parse user id." << std::endl; + commandParser->printUsage("add_user"); + return; + } + + unsigned long gid = std::strtoul(args[2].c_str(), &endptr, 10); + if(args[2].empty() || *endptr != '\0') { + std::cerr << args[0] << ": Unable to parse group id." << std::endl; + commandParser->printUsage("add_user"); + return; + } + + try { + Common::UserInfo user(uid, args[3]); + user.setGid(gid); + user.setFullName(args[4]); + + commandParser->application->getUserManager()->addUser(user); + + std::cout << "User added." << std::endl; + } + catch(Core::Exception e) { + std::cerr << "An error occurred during your request: " << e.strerror() << "." << std::endl; + } +} + } } diff --git a/src/Client/UserCommands.h b/src/Client/UserCommands.h index 0f56a40..6e184b0 100644 --- a/src/Client/UserCommands.h +++ b/src/Client/UserCommands.h @@ -40,6 +40,8 @@ class UserCommands { static void listGroupsCommand(CommandParser *commandParser, const std::vector<std::string> &args); static void groupInfoCommand(CommandParser *commandParser, const std::vector<std::string> &args); static void listGroupUsersCommand(CommandParser *commandParser, const std::vector<std::string> &args); + + static void addUserCommand(CommandParser *commandParser, const std::vector<std::string> &args); }; } diff --git a/src/Common/Backends/NetworkUserBackend.cpp b/src/Common/Backends/NetworkUserBackend.cpp index 27f65f5..a1cf415 100644 --- a/src/Common/Backends/NetworkUserBackend.cpp +++ b/src/Common/Backends/NetworkUserBackend.cpp @@ -27,7 +27,7 @@ namespace Common { namespace Backends { void NetworkUserBackend::SimpleUserRequest::sendRequest() { - Common::XmlPacket packet; + XmlPacket packet; packet.setType(type); if(!timestamp.is_not_a_date_time()) @@ -37,7 +37,7 @@ void NetworkUserBackend::SimpleUserRequest::sendRequest() { } void NetworkUserBackend::IdUserRequest::sendRequest() { - Common::XmlPacket packet; + XmlPacket packet; packet.setType(type); packet.set(idType, id); @@ -48,7 +48,7 @@ void NetworkUserBackend::IdUserRequest::sendRequest() { } void NetworkUserBackend::NameUserRequest::sendRequest() { - Common::XmlPacket packet; + XmlPacket packet; packet.setType(type); packet.set("name", name); @@ -58,6 +58,18 @@ void NetworkUserBackend::NameUserRequest::sendRequest() { sendPacket(packet); } +void NetworkUserBackend::UserAddRequest::sendRequest() { + XmlPacket packet; + packet.setType("AddUser"); + + packet.set("uid", userInfo.getUid()); + packet.set("gid", userInfo.getGid()); + packet.set("username", userInfo.getUsername()); + packet.set("fullName", userInfo.getFullName()); + + sendPacket(packet); +} + boost::shared_ptr<const std::map<unsigned long, UserInfo> > NetworkUserBackend::getUserList(boost::posix_time::ptime *timestamp) throw(Core::Exception) { boost::shared_ptr<SimpleUserRequest> request(new SimpleUserRequest(application, "ListUsers", timestamp)); application->getRequestManager()->sendRequest(connection, request); @@ -327,9 +339,15 @@ boost::shared_ptr<const std::multimap<unsigned long, unsigned long> > NetworkUse }*/ -/*void NetworkUserBackend::addUser(const UserInfo &userInfo) throw(Core::Exception) { +void NetworkUserBackend::addUser(const UserInfo &userInfo) throw(Core::Exception) { + boost::shared_ptr<UserAddRequest> request(new UserAddRequest(application, userInfo)); + application->getRequestManager()->sendRequest(connection, request); + request->wait(); -}*/ + std::pair<boost::shared_ptr<const XmlPacket>, Core::Exception> result = request->getResult(); + if(!result.first || result.second) + throw result.second; +} } } diff --git a/src/Common/Backends/NetworkUserBackend.h b/src/Common/Backends/NetworkUserBackend.h index 8faa8e3..9518790 100644 --- a/src/Common/Backends/NetworkUserBackend.h +++ b/src/Common/Backends/NetworkUserBackend.h @@ -71,6 +71,18 @@ class NetworkUserBackend : public UserBackend { : Request(application), type(type0), name(name0), timestamp(timestamp0 ? *timestamp0 : boost::posix_time::not_a_date_time) {} }; + class UserAddRequest : public Request { + private: + UserInfo userInfo; + + protected: + virtual void sendRequest(); + + public: + UserAddRequest(Application *application, const UserInfo &userInfo0) + : Request(application), userInfo(userInfo0) {} + }; + Application *application; Connection *connection; @@ -88,7 +100,8 @@ class NetworkUserBackend : public UserBackend { virtual boost::shared_ptr<const std::multimap<unsigned long, unsigned long> > getFullUserGroupList(boost::posix_time::ptime *timestamp) throw(Core::Exception); //virtual void setPassword(unsigned long uid, const std::string &password) throw(Core::Exception); - //virtual void addUser(const UserInfo &userInfo) throw(Core::Exception); + + virtual void addUser(const UserInfo &userInfo) throw(Core::Exception); public: NetworkUserBackend(Application *application0, Connection *connection0) : application(application0), connection(connection0) {} diff --git a/src/Common/UserManager.cpp b/src/Common/UserManager.cpp index 4031140..0ccf314 100644 --- a/src/Common/UserManager.cpp +++ b/src/Common/UserManager.cpp @@ -208,39 +208,37 @@ boost::shared_ptr<const std::multimap<unsigned long, unsigned long> > UserManage } void UserManager::setPassword(unsigned long uid, const std::string &password) throw(Core::Exception) { - Core::Exception e(Core::Exception::NOT_IMPLEMENTED); - boost::lock_guard<boost::shared_mutex> lock(mutex); for(BackendMap::iterator backend = backends.begin(); backend != backends.end(); ++backend) { try { backend->second->setPassword(uid, password); + return; } - catch(Core::Exception e2) { - if(e.getErrorCode() == Core::Exception::NOT_IMPLEMENTED && e2.getErrorCode() != Core::Exception::NOT_IMPLEMENTED) - e = e2; + catch(Core::Exception e) { + if(e.getErrorCode() != Core::Exception::NOT_IMPLEMENTED) + throw e; } } - throw e; + throw Core::Exception(Core::Exception::NOT_IMPLEMENTED); } void UserManager::addUser(const UserInfo &userInfo) throw(Core::Exception) { - Core::Exception e(Core::Exception::NOT_IMPLEMENTED); - boost::lock_guard<boost::shared_mutex> lock(mutex); for(BackendMap::iterator backend = backends.begin(); backend != backends.end(); ++backend) { try { backend->second->addUser(userInfo); + return; } - catch(Core::Exception e2) { - if(e.getErrorCode() == Core::Exception::NOT_IMPLEMENTED && e2.getErrorCode() != Core::Exception::NOT_IMPLEMENTED) - e = e2; + catch(Core::Exception e) { + if(e.getErrorCode() != Core::Exception::NOT_IMPLEMENTED) + throw e; } } - throw e; + throw Core::Exception(Core::Exception::NOT_IMPLEMENTED); } } diff --git a/src/Core/Exception.cpp b/src/Core/Exception.cpp index 1a71ebd..0e086d5 100644 --- a/src/Core/Exception.cpp +++ b/src/Core/Exception.cpp @@ -53,6 +53,8 @@ std::string Exception::strerror() const { return ret + "The host is already identified"; case UNKNOWN_DAEMON: return ret + "The daemon is unknown"; + case DUPLICATE_ENTRY: + return ret + "Duplicate entry"; default: return ret + "Unknown error"; } diff --git a/src/Core/Exception.h b/src/Core/Exception.h index 4d58190..ffbb59c 100644 --- a/src/Core/Exception.h +++ b/src/Core/Exception.h @@ -32,7 +32,8 @@ class Exception { NOT_FOUND = 0x0006, INTERNAL_ERRNO = 0x0010, INVALID_ADDRESS = 0x0020, - ALREADY_IDENTIFIED = 0x0030, UNKNOWN_DAEMON = 0x0031 + ALREADY_IDENTIFIED = 0x0030, UNKNOWN_DAEMON = 0x0031, + DUPLICATE_ENTRY = 0x0040, }; private: diff --git a/src/Server/RequestHandlers/UserRequestHandlerGroup.cpp b/src/Server/RequestHandlers/UserRequestHandlerGroup.cpp index 292e887..584b3cc 100644 --- a/src/Server/RequestHandlers/UserRequestHandlerGroup.cpp +++ b/src/Server/RequestHandlers/UserRequestHandlerGroup.cpp @@ -247,6 +247,17 @@ void UserRequestHandlerGroup::handleFullUserGroupListRequest(boost::shared_ptr<c } } +void UserRequestHandlerGroup::handleUserAddRequest(boost::shared_ptr<const Common::XmlPacket> packet, Common::XmlPacket *ret, + Common::Connection *connection _UNUSED_PARAMETER_) { + Common::UserInfo userInfo(packet->get<unsigned long>("uid"), packet->get<const std::string&>("username")); + userInfo.setGid(packet->get<unsigned long>("gid")); + userInfo.setFullName(packet->get<const std::string&>("fullName")); + + application->getUserManager()->addUser(userInfo); + + ret->setType("OK"); +} + UserRequestHandlerGroup::UserRequestHandlerGroup(Application *application0) : application(application0) { registerHandler("ListUsers", boost::bind(&UserRequestHandlerGroup::handleUserListRequest, this, _1, _2, _3)); registerHandler("GetUserInfo", boost::bind(&UserRequestHandlerGroup::handleUserInfoRequest, this, _1, _2, _3)); @@ -257,6 +268,8 @@ UserRequestHandlerGroup::UserRequestHandlerGroup(Application *application0) : ap registerHandler("ListGroupUsers", boost::bind(&UserRequestHandlerGroup::handleGroupUserListRequest, this, _1, _2, _3)); registerHandler("GetFullUserGroupList", boost::bind(&UserRequestHandlerGroup::handleFullUserGroupListRequest, this, _1, _2, _3)); + + registerHandler("AddUser", boost::bind(&UserRequestHandlerGroup::handleUserAddRequest, this, _1, _2, _3)); } } diff --git a/src/Server/RequestHandlers/UserRequestHandlerGroup.h b/src/Server/RequestHandlers/UserRequestHandlerGroup.h index a55a34f..bc57234 100644 --- a/src/Server/RequestHandlers/UserRequestHandlerGroup.h +++ b/src/Server/RequestHandlers/UserRequestHandlerGroup.h @@ -43,6 +43,8 @@ class UserRequestHandlerGroup : public Common::RequestHandlers::SimpleRequestHan void handleFullUserGroupListRequest(boost::shared_ptr<const Common::XmlPacket> packet, Common::XmlPacket *ret, Common::Connection *connection); + void handleUserAddRequest(boost::shared_ptr<const Common::XmlPacket> packet, Common::XmlPacket *ret, Common::Connection *connection); + public: UserRequestHandlerGroup(Application *application0); }; diff --git a/src/mad-server.conf b/src/mad-server.conf index 8ab08cc..5c21bff 100644 --- a/src/mad-server.conf +++ b/src/mad-server.conf @@ -25,6 +25,7 @@ UserBackendMysql { GroupById "SELECT id, name FROM groups WHERE id = {GID}" GroupByName "SELECT id, name FROM groups WHERE name = {GROUP}" UserGroupTable "SELECT uid, gid FROM usergroups" + AddUser "INSERT INTO users (id, gid, username, fullname) VALUES ({UID}, {GID}, {USER}, {FULL_NAME})" } } diff --git a/src/mad-server.cpp b/src/mad-server.cpp index 59dca1c..ba42a89 100644 --- a/src/mad-server.cpp +++ b/src/mad-server.cpp @@ -19,7 +19,6 @@ #include "Core/ConfigManager.h" #include "Common/ModuleManager.h" -#include "Common/UserManager.h" #include "Server/Application.h" #include "Server/ConnectionManager.h" diff --git a/src/madc.cpp b/src/madc.cpp index ba9770e..d2ce300 100644 --- a/src/madc.cpp +++ b/src/madc.cpp @@ -34,8 +34,6 @@ #include <readline/readline.h> #include <readline/history.h> -#include <boost/thread/condition_variable.hpp> - using namespace Mad; diff --git a/src/modules/UserBackendMysql/UserBackendMysql.cpp b/src/modules/UserBackendMysql/UserBackendMysql.cpp index 82258e8..0619409 100644 --- a/src/modules/UserBackendMysql/UserBackendMysql.cpp +++ b/src/modules/UserBackendMysql/UserBackendMysql.cpp @@ -30,6 +30,8 @@ #include <boost/regex.hpp> #include <boost/thread/locks.hpp> +#include <mysql/mysqld_error.h> + namespace Mad { namespace Modules { namespace UserBackendMysql { @@ -110,6 +112,10 @@ bool UserBackendMysql::handleConfigEntry(const Core::ConfigEntry &entry, bool ha if(entry[3].empty()) queryUserGroupTable = entry[2][0]; } + else if(entry[2].getKey().matches("AddUser")) { + if(entry[3].empty()) + queryAddUser = entry[2][0]; + } else if(!entry[2].empty()) return false; } @@ -150,16 +156,16 @@ boost::shared_ptr<const std::map<unsigned long, Common::UserInfo> > UserBackendM throw Core::Exception(Core::Exception::NOT_AVAILABLE); mysql_real_query(mysql, queryListUsers.c_str(), queryListUsers.length()); - MYSQL_RES *result = mysql_store_result(mysql); + Result result(mysql); lock.unlock(); - if(!result || mysql_num_fields(result) < 4) + if(!result || result.getErrno() || result.getFieldNumber() < 4) throw Core::Exception(Core::Exception::NOT_AVAILABLE); boost::shared_ptr<std::map<unsigned long, Common::UserInfo> > users(new std::map<unsigned long, Common::UserInfo>()); - while(MYSQL_ROW row = mysql_fetch_row(result)) { + while(MYSQL_ROW row = result.getNextRow()) { Common::UserInfo user(strtoul(row[0], 0, 10), row[2]); user.setGid(strtoul(row[1], 0, 10)); @@ -196,14 +202,14 @@ boost::shared_ptr<const Common::UserInfo> UserBackendMysql::getUserInfo(unsigned query = boost::regex_replace(query, boost::regex("\\{UID\\}"), tmp.str(), boost::match_default); mysql_real_query(mysql, query.c_str(), query.length()); - MYSQL_RES *result = mysql_store_result(mysql); + Result result(mysql); lock.unlock(); - if(!result || mysql_num_fields(result) < 4) + if(!result || result.getErrno() || result.getFieldNumber() < 4) throw Core::Exception(Core::Exception::NOT_AVAILABLE); - MYSQL_ROW row = mysql_fetch_row(result); + MYSQL_ROW row = result.getNextRow(); if(row) { boost::shared_ptr<Common::UserInfo> user(new Common::UserInfo(strtoul(row[0], 0, 10), row[2])); @@ -211,8 +217,6 @@ boost::shared_ptr<const Common::UserInfo> UserBackendMysql::getUserInfo(unsigned user->setGid(strtoul(row[1], 0, 10)); user->setFullName(row[3]); - while((row = mysql_fetch_row(result)) != 0) {} - return user; } @@ -241,14 +245,14 @@ boost::shared_ptr<const Common::UserInfo> UserBackendMysql::getUserInfoByName(co std::string query = boost::regex_replace(queryUserByName, boost::regex("\\{USER\\}"), "\""+std::string(escapedName.get())+"\"", boost::match_default); mysql_real_query(mysql, query.c_str(), query.length()); - MYSQL_RES *result = mysql_store_result(mysql); + Result result(mysql); lock.unlock(); - if(!result || mysql_num_fields(result) < 4) + if(!result || result.getErrno() || result.getFieldNumber() < 4) throw Core::Exception(Core::Exception::NOT_AVAILABLE); - MYSQL_ROW row = mysql_fetch_row(result); + MYSQL_ROW row = result.getNextRow(); if(row) { boost::shared_ptr<Common::UserInfo> user(new Common::UserInfo(strtoul(row[0], 0, 10), row[2])); @@ -256,8 +260,6 @@ boost::shared_ptr<const Common::UserInfo> UserBackendMysql::getUserInfoByName(co user->setGid(strtoul(row[1], 0, 10)); user->setFullName(row[3]); - while((row = mysql_fetch_row(result)) != 0) {} - return user; } @@ -287,16 +289,16 @@ boost::shared_ptr<const std::set<unsigned long> > UserBackendMysql::getUserGroup std::string query = boost::regex_replace(queryListUserGroups, boost::regex("\\{UID\\}"), tmp.str(), boost::match_default); mysql_real_query(mysql, query.c_str(), query.length()); - MYSQL_RES *result = mysql_store_result(mysql); + Result result(mysql); lock.unlock(); - if(!result || mysql_num_fields(result) < 1) + if(!result || result.getErrno() || result.getFieldNumber() < 1) throw Core::Exception(Core::Exception::NOT_AVAILABLE); boost::shared_ptr<std::set<unsigned long> > groups(new std::set<unsigned long>); - while(MYSQL_ROW row = mysql_fetch_row(result)) + while(MYSQL_ROW row = result.getNextRow()) groups->insert(strtoul(row[0], 0, 10)); return groups; @@ -319,16 +321,16 @@ boost::shared_ptr<const std::map<unsigned long, Common::GroupInfo> > UserBackend throw Core::Exception(Core::Exception::NOT_AVAILABLE); mysql_real_query(mysql, queryListGroups.c_str(), queryListGroups.length()); - MYSQL_RES *result = mysql_store_result(mysql); + Result result(mysql); lock.unlock(); - if(!result || mysql_num_fields(result) < 2) + if(!result || result.getErrno() || result.getFieldNumber() < 2) throw Core::Exception(Core::Exception::NOT_AVAILABLE); boost::shared_ptr<std::map<unsigned long, Common::GroupInfo> > groups(new std::map<unsigned long, Common::GroupInfo>()); - while(MYSQL_ROW row = mysql_fetch_row(result)) { + while(MYSQL_ROW row = result.getNextRow()) { Common::GroupInfo group(strtoul(row[0], 0, 10), row[1]); groups->insert(std::make_pair(group.getGid(), group)); @@ -362,14 +364,14 @@ boost::shared_ptr<const Common::GroupInfo> UserBackendMysql::getGroupInfo(unsign query = boost::regex_replace(query, boost::regex("\\{GID\\}"), tmp.str(), boost::match_default); mysql_real_query(mysql, query.c_str(), query.length()); - MYSQL_RES *result = mysql_store_result(mysql); + Result result(mysql); lock.unlock(); - if(!result || mysql_num_fields(result) < 2) + if(!result || result.getErrno() || result.getFieldNumber() < 2) throw Core::Exception(Core::Exception::NOT_AVAILABLE); - MYSQL_ROW row = mysql_fetch_row(result); + MYSQL_ROW row = result.getNextRow(); if(row) return boost::shared_ptr<Common::GroupInfo>(new Common::GroupInfo(strtoul(row[0], 0, 10), row[1])); @@ -399,14 +401,14 @@ boost::shared_ptr<const Common::GroupInfo> UserBackendMysql::getGroupInfoByName( std::string query = boost::regex_replace(queryGroupByName, boost::regex("\\{GROUP\\}"), "\""+std::string(escapedName.get())+"\"", boost::match_default); mysql_real_query(mysql, query.c_str(), query.length()); - MYSQL_RES *result = mysql_store_result(mysql); + Result result(mysql); lock.unlock(); - if(!result || mysql_num_fields(result) < 2) + if(!result || result.getErrno() || result.getFieldNumber() < 2) throw Core::Exception(Core::Exception::NOT_AVAILABLE); - MYSQL_ROW row = mysql_fetch_row(result); + MYSQL_ROW row = result.getNextRow(); if(row) return boost::shared_ptr<Common::GroupInfo>(new Common::GroupInfo(strtoul(row[0], 0, 10), row[1])); @@ -437,16 +439,16 @@ boost::shared_ptr<const std::set<unsigned long> > UserBackendMysql::getGroupUser std::string query = boost::regex_replace(queryListGroupUsers, boost::regex("\\{GID\\}"), tmp.str(), boost::match_default); mysql_real_query(mysql, query.c_str(), query.length()); - MYSQL_RES *result = mysql_store_result(mysql); + Result result(mysql); lock.unlock(); - if(!result || mysql_num_fields(result) < 1) + if(!result || result.getErrno() || result.getFieldNumber() < 1) throw Core::Exception(Core::Exception::NOT_AVAILABLE); boost::shared_ptr<std::set<unsigned long> > users(new std::set<unsigned long>); - while(MYSQL_ROW row = mysql_fetch_row(result)) + while(MYSQL_ROW row = result.getNextRow()) users->insert(strtoul(row[0], 0, 10)); return users; @@ -468,21 +470,68 @@ boost::shared_ptr<const std::multimap<unsigned long, unsigned long> > UserBacken throw Core::Exception(Core::Exception::NOT_AVAILABLE); mysql_real_query(mysql, queryUserGroupTable.c_str(), queryUserGroupTable.length()); - MYSQL_RES *result = mysql_store_result(mysql); + Result result(mysql); lock.unlock(); - if(!result || mysql_num_fields(result) < 2) + if(!result || result.getErrno() || result.getFieldNumber() < 2) throw Core::Exception(Core::Exception::NOT_AVAILABLE); boost::shared_ptr<std::multimap<unsigned long, unsigned long> > usergroups(new std::multimap<unsigned long, unsigned long>); - while(MYSQL_ROW row = mysql_fetch_row(result)) + while(MYSQL_ROW row = result.getNextRow()) usergroups->insert(std::make_pair(strtoul(row[0], 0, 10), strtoul(row[1], 0, 10))); return usergroups; } +void UserBackendMysql::addUser(const Common::UserInfo &userInfo) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::lock_guard<boost::mutex> lock(mutex); + + if(!mysql || mysql_ping(mysql)) + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + + std::ostringstream tmp; + tmp << '"'; + tmp << userInfo.getUid(); + tmp << '"'; + + std::string query = boost::regex_replace(queryAddUser, boost::regex("\\{UID\\}"), tmp.str(), boost::match_default); + + tmp.str(std::string()); + tmp << '"'; + tmp << userInfo.getGid(); + tmp << '"'; + + query = boost::regex_replace(query, boost::regex("\\{GID\\}"), tmp.str(), boost::match_default); + + const std::string &username = userInfo.getUsername(); + boost::scoped_array<char> escapedUsername(new char[username.length()*2+1]); + mysql_real_escape_string(mysql, escapedUsername.get(), username.c_str(), username.length()); + + query = boost::regex_replace(query, boost::regex("\\{USER\\}"), "\"" + std::string(escapedUsername.get()) + "\"", boost::match_default); + + const std::string &fullName = userInfo.getFullName(); + boost::scoped_array<char> escapedFullName(new char[fullName.length()*2+1]); + mysql_real_escape_string(mysql, escapedFullName.get(), fullName.c_str(), fullName.length()); + + query = boost::regex_replace(query, boost::regex("\\{FULL_NAME\\}"), "\"" + std::string(escapedFullName.get()) + "\"", boost::match_default); + + mysql_real_query(mysql, query.c_str(), query.length()); + Result result(mysql); + + if(result.getErrno()) { + if(result.getErrno() == ER_DUP_ENTRY) + throw Core::Exception(Core::Exception::DUPLICATE_ENTRY); + else + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + } + + lastUpdate = boost::posix_time::microsec_clock::universal_time(); +} + } } } diff --git a/src/modules/UserBackendMysql/UserBackendMysql.h b/src/modules/UserBackendMysql/UserBackendMysql.h index 52a134a..25c3837 100644 --- a/src/modules/UserBackendMysql/UserBackendMysql.h +++ b/src/modules/UserBackendMysql/UserBackendMysql.h @@ -34,8 +34,54 @@ namespace Mad { namespace Modules { namespace UserBackendMysql { -class UserBackendMysql : public Common::UserBackend, private Core::Configurable { +class UserBackendMysql : public Common::UserBackend, private Core::Configurable, private boost::noncopyable { private: + class Result : private boost::noncopyable { + private: + MYSQL_RES *result; + + unsigned int mysqlErrno; + const char *error; + + public: + Result(MYSQL *mysql) { + result = mysql_store_result(mysql); + + mysqlErrno = mysql_errno(mysql); + error = mysql_error(mysql); + } + + ~Result() { + if(result) { + mysql_free_result(result); + } + } + + operator bool() const { + return result; + } + + unsigned int getErrno() const { + return mysqlErrno; + } + + const char* getError() const { + return error; + } + + unsigned int getFieldNumber() const { + return mysql_num_fields(result); + } + + my_ulonglong getRowNumber() const { + return mysql_num_rows(result); + } + + MYSQL_ROW getNextRow() { + return mysql_fetch_row(result); + } + }; + Common::Application *application; std::string host, username, passwd, db, unixSocket; @@ -46,6 +92,7 @@ class UserBackendMysql : public Common::UserBackend, private Core::Configurable std::string queryUserById, queryUserByName; std::string queryGroupById, queryGroupByName; std::string queryUserGroupTable; + std::string queryAddUser; MYSQL *mysql; @@ -69,6 +116,8 @@ class UserBackendMysql : public Common::UserBackend, private Core::Configurable virtual boost::shared_ptr<const std::multimap<unsigned long, unsigned long> > getFullUserGroupList(boost::posix_time::ptime *timestamp) throw(Core::Exception); + virtual void addUser(const Common::UserInfo &userInfo) throw(Core::Exception); + public: UserBackendMysql(Common::Application *application0) : application(application0), port(0), mysql(0), lastUpdate(boost::posix_time::microsec_clock::universal_time()) { application->getConfigManager()->registerConfigurable(this); |