summaryrefslogtreecommitdiffstats
path: root/src/modules/UserDBBackendMysql
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/UserDBBackendMysql')
-rw-r--r--src/modules/UserDBBackendMysql/CMakeLists.txt8
-rw-r--r--src/modules/UserDBBackendMysql/Module.cpp28
-rw-r--r--src/modules/UserDBBackendMysql/Module.h52
-rw-r--r--src/modules/UserDBBackendMysql/UserDBBackendMysql.cpp652
-rw-r--r--src/modules/UserDBBackendMysql/UserDBBackendMysql.h159
5 files changed, 899 insertions, 0 deletions
diff --git a/src/modules/UserDBBackendMysql/CMakeLists.txt b/src/modules/UserDBBackendMysql/CMakeLists.txt
new file mode 100644
index 0000000..8c4f079
--- /dev/null
+++ b/src/modules/UserDBBackendMysql/CMakeLists.txt
@@ -0,0 +1,8 @@
+include_directories(${INCLUDES} ${MYSQL_INCLUDE_DIR})
+
+mad_module(UserDBBackendMysql
+ Module.cpp Module.h
+ UserDBBackendMysql.cpp UserDBBackendMysql.h
+)
+
+mad_module_libraries(UserDBBackendMysql ${MYSQL_LIBRARIES}) \ No newline at end of file
diff --git a/src/modules/UserDBBackendMysql/Module.cpp b/src/modules/UserDBBackendMysql/Module.cpp
new file mode 100644
index 0000000..a4b51c4
--- /dev/null
+++ b/src/modules/UserDBBackendMysql/Module.cpp
@@ -0,0 +1,28 @@
+/*
+ * Module.cpp
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Module.h"
+
+extern "C" {
+
+Mad::Common::Module* UserDBBackendMysql_create(Mad::Common::Application *application) {
+ return new Mad::Modules::UserDBBackendMysql::Module(application);
+}
+
+}
diff --git a/src/modules/UserDBBackendMysql/Module.h b/src/modules/UserDBBackendMysql/Module.h
new file mode 100644
index 0000000..ee04409
--- /dev/null
+++ b/src/modules/UserDBBackendMysql/Module.h
@@ -0,0 +1,52 @@
+/*
+ * Module.h
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_MODULES_USERDBBACKENDMYSQL_MODULE_H_
+#define MAD_MODULES_USERDBBACKENDMYSQL_MODULE_H_
+
+#include "UserDBBackendMysql.h"
+
+#include <Common/Module.h>
+#include <Common/UserManager.h>
+
+namespace Mad {
+namespace Modules {
+namespace UserDBBackendMysql {
+
+class Module : public Common::Module {
+ private:
+ Common::Application *application;
+
+ boost::shared_ptr<UserDBBackendMysql> backend;
+
+ public:
+ Module(Common::Application *application0) : application(application0), backend(new UserDBBackendMysql(application)) {
+ application->getUserManager()->registerBackend(backend);
+ }
+
+ virtual ~Module() {
+ application->getUserManager()->unregisterBackend(backend);
+ }
+};
+
+}
+}
+}
+
+#endif /* MAD_MODULES_USERDBBACKENDMYSQL_MODULE_H_ */
diff --git a/src/modules/UserDBBackendMysql/UserDBBackendMysql.cpp b/src/modules/UserDBBackendMysql/UserDBBackendMysql.cpp
new file mode 100644
index 0000000..7ca3db2
--- /dev/null
+++ b/src/modules/UserDBBackendMysql/UserDBBackendMysql.cpp
@@ -0,0 +1,652 @@
+/*
+ * UserDBBackendMysql.cpp
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "UserDBBackendMysql.h"
+#include <Core/ConfigEntry.h>
+#include <Core/ConfigManager.h>
+#include <Core/ThreadManager.h>
+
+#include <sstream>
+
+#include <boost/bind.hpp>
+#include <boost/regex.hpp>
+#include <boost/thread/locks.hpp>
+
+#include <mysql/mysqld_error.h>
+
+namespace Mad {
+namespace Modules {
+namespace UserDBBackendMysql {
+
+const std::string UserDBBackendMysql::name("UserDBBackendMysql");
+
+bool UserDBBackendMysql::handleConfigEntry(const Core::ConfigEntry &entry, bool /*handled*/) {
+ if(!entry[0].getKey().matches("UserManager"))
+ return false;
+
+ if(entry[1].empty())
+ return true;
+
+ if(!entry[1].getKey().matches("Mysql"))
+ return false;
+
+ if(entry[2].getKey().matches("Host")) {
+ if(entry[3].empty())
+ host = entry[2][0];
+ }
+ else if(entry[2].getKey().matches("Username")) {
+ if(entry[3].empty())
+ username = entry[2][0];
+ }
+ else if(entry[2].getKey().matches("Password")) {
+ if(entry[3].empty())
+ passwd = entry[2][0];
+ }
+ else if(entry[2].getKey().matches("Database")) {
+ if(entry[3].empty())
+ db = entry[2][0];
+ }
+ else if(entry[2].getKey().matches("Port")) {
+ if(entry[3].empty()) {
+ char *endptr;
+ long val;
+
+ val = strtol(entry[2][0].c_str(), &endptr, 10);
+
+ if(endptr != 0 || val < 0 || val > 65535)
+ application->log(Core::LoggerBase::WARNING, "UserDBBackendMysql: Invalid port");
+ else
+ port = val;
+ }
+ }
+ else if(entry[2].getKey().matches("UnixSocket")) {
+ if(entry[3].empty())
+ unixSocket = entry[2][0];
+ }
+ else if(entry[2].getKey().matches("Queries")) {
+ if(entry[3].getKey().matches("ListUsers")) {
+ if(entry[4].empty())
+ queryListUsers = entry[3][0];
+ }
+ else if(entry[3].getKey().matches("ListGroups")) {
+ if(entry[4].empty())
+ queryListGroups = entry[3][0];
+ }
+ else if(entry[3].getKey().matches("ListUserGroups")) {
+ if(entry[4].empty())
+ queryListUserGroups = entry[3][0];
+ }
+ else if(entry[3].getKey().matches("ListGroupUsers")) {
+ if(entry[4].empty())
+ queryListGroupUsers = entry[3][0];
+ }
+ else if(entry[3].getKey().matches("UserById")) {
+ if(entry[4].empty())
+ queryUserById = entry[3][0];
+ }
+ else if(entry[3].getKey().matches("UserByName")) {
+ if(entry[4].empty())
+ queryUserByName = entry[3][0];
+ }
+ else if(entry[3].getKey().matches("GroupById")) {
+ if(entry[4].empty())
+ queryGroupById = entry[3][0];
+ }
+ else if(entry[3].getKey().matches("GroupByName")) {
+ if(entry[4].empty())
+ queryGroupByName = entry[3][0];
+ }
+ else if(entry[3].getKey().matches("UserGroupTable")) {
+ if(entry[4].empty())
+ queryUserGroupTable = entry[3][0];
+ }
+ else if(entry[3].getKey().matches("AddUser")) {
+ if(entry[4].empty())
+ queryAddUser = entry[3][0];
+ }
+ else if(entry[3].getKey().matches("UpdateUser")) {
+ if(entry[4].empty())
+ queryUpdateUser = entry[3][0];
+ }
+ else if(entry[3].getKey().matches("DeleteUser")) {
+ if(entry[4].empty())
+ queryDeleteUser = entry[3][0];
+ }
+ else if(entry[3].getKey().matches("AddGroup")) {
+ if(entry[4].empty())
+ queryAddGroup = entry[3][0];
+ }
+ else if(entry[3].getKey().matches("UpdateGroup")) {
+ if(entry[4].empty())
+ queryUpdateGroup = entry[3][0];
+ }
+ else if(entry[3].getKey().matches("DeleteGroup")) {
+ if(entry[4].empty())
+ queryDeleteGroup = entry[3][0];
+ }
+ else if(entry[3].getKey().matches("AddUserToGroup")) {
+ if(entry[4].empty())
+ queryAddUserToGroup = entry[3][0];
+ }
+ else if(entry[3].getKey().matches("DeleteUserFromGroup")) {
+ if(entry[4].empty())
+ queryDeleteUserFromGroup = entry[3][0];
+ }
+ else if(!entry[3].empty())
+ return false;
+ }
+ else if(!entry[2].empty())
+ return false;
+
+ return true;
+}
+
+void UserDBBackendMysql::configFinished() {
+ if(db.empty()) {
+ application->log(Core::LoggerBase::ERROR, "UserDBBackendMysql: No database name given");
+ return;
+ }
+
+ boost::lock_guard<boost::mutex> lock(mutex);
+ mysql = mysql_init(0);
+ mysql_real_connect(mysql, host.c_str(), username.c_str(), passwd.c_str(), db.c_str(), port, unixSocket.empty() ? 0 : unixSocket.c_str(), 0);
+}
+
+
+UserDBBackendMysql::Result UserDBBackendMysql::query(const std::string &query, const ArgumentMap &args) throw(Core::Exception) {
+ if(!mysql || mysql_ping(mysql))
+ throw Core::Exception(Core::Exception::NOT_AVAILABLE);
+
+ if(args.empty()) {
+ mysql_real_query(mysql, query.c_str(), query.length());
+ }
+ else {
+ std::string queryStr = query;
+
+ for(ArgumentMap::const_iterator arg = args.begin(); arg != args.end(); ++arg) {
+ std::string argStr;
+
+ try {
+ argStr = boost::get<std::string>(arg->second);
+ }
+ catch(...) {
+ std::ostringstream stream;
+ stream << arg->second;
+ argStr = stream.str();
+ }
+
+ boost::scoped_array<char> escaped(new char[argStr.length()*2+1]);
+ mysql_real_escape_string(mysql, escaped.get(), argStr.c_str(), argStr.length());
+
+ queryStr = boost::regex_replace(queryStr, boost::regex("\\{" + arg->first + "\\}"), "\"" + std::string(escaped.get()) + "\"", boost::match_default);
+ }
+
+ mysql_real_query(mysql, queryStr.c_str(), queryStr.length());
+ }
+
+ return Result(mysql);
+}
+
+
+boost::shared_ptr<const std::map<unsigned long, Common::UserInfo> > UserDBBackendMysql::getUserList(boost::posix_time::ptime *timestamp) throw(Core::Exception) {
+ application->getThreadManager()->detach();
+
+ boost::unique_lock<boost::mutex> lock(mutex);
+
+ if(timestamp) {
+ if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate)
+ *timestamp = lastUpdate;
+ else
+ return boost::shared_ptr<const std::map<unsigned long, Common::UserInfo> >();
+ }
+
+ Result result = query(queryListUsers);
+
+ lock.unlock();
+
+ 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 = result.getNextRow()) {
+ Common::UserInfo user(strtoul(row[0], 0, 10), row[2]);
+
+ user.setGid(strtoul(row[1], 0, 10));
+ user.setFullName(row[3]);
+
+ users->insert(std::make_pair(user.getUid(), user));
+ }
+
+ return users;
+}
+
+boost::shared_ptr<const Common::UserInfo> UserDBBackendMysql::getUserInfo(unsigned long uid, boost::posix_time::ptime *timestamp) throw(Core::Exception) {
+ application->getThreadManager()->detach();
+
+ boost::unique_lock<boost::mutex> lock(mutex);
+
+ if(timestamp) {
+ if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate)
+ *timestamp = lastUpdate;
+ else
+ return boost::shared_ptr<const Common::UserInfo>();
+ }
+
+ ArgumentMap args;
+ args.insert(std::make_pair("UID", uid));
+
+ Result result = query(queryUserById, args);
+
+ lock.unlock();
+
+ if(!result || result.getErrno() || result.getFieldNumber() < 4)
+ throw Core::Exception(Core::Exception::NOT_AVAILABLE);
+
+ MYSQL_ROW row = result.getNextRow();
+
+ if(row) {
+ boost::shared_ptr<Common::UserInfo> user(new Common::UserInfo(strtoul(row[0], 0, 10), row[2]));
+
+ user->setGid(strtoul(row[1], 0, 10));
+ user->setFullName(row[3]);
+
+ return user;
+ }
+
+ throw Core::Exception(Core::Exception::NOT_FOUND);
+}
+
+boost::shared_ptr<const Common::UserInfo> UserDBBackendMysql::getUserInfoByName(const std::string &name, boost::posix_time::ptime *timestamp) throw(Core::Exception) {
+ application->getThreadManager()->detach();
+
+ boost::unique_lock<boost::mutex> lock(mutex);
+
+ if(timestamp) {
+ if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate)
+ *timestamp = lastUpdate;
+ else
+ return boost::shared_ptr<const Common::UserInfo>();
+ }
+
+ ArgumentMap args;
+ args.insert(std::make_pair("USER", name));
+
+ Result result = query(queryUserByName, args);
+
+ lock.unlock();
+
+ if(!result || result.getErrno() || result.getFieldNumber() < 4)
+ throw Core::Exception(Core::Exception::NOT_AVAILABLE);
+
+ MYSQL_ROW row = result.getNextRow();
+
+ if(row) {
+ boost::shared_ptr<Common::UserInfo> user(new Common::UserInfo(strtoul(row[0], 0, 10), row[2]));
+
+ user->setGid(strtoul(row[1], 0, 10));
+ user->setFullName(row[3]);
+
+ return user;
+ }
+
+ throw Core::Exception(Core::Exception::NOT_FOUND);
+}
+
+boost::shared_ptr<const std::set<unsigned long> > UserDBBackendMysql::getUserGroupList(unsigned long uid, boost::posix_time::ptime *timestamp) throw(Core::Exception) {
+ application->getThreadManager()->detach();
+
+ boost::unique_lock<boost::mutex> lock(mutex);
+
+ if(timestamp) {
+ if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate)
+ *timestamp = lastUpdate;
+ else
+ return boost::shared_ptr<const std::set<unsigned long> >();
+ }
+
+ ArgumentMap args;
+ args.insert(std::make_pair("UID", uid));
+
+ Result result = query(queryListUserGroups, args);
+
+ lock.unlock();
+
+ 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 = result.getNextRow())
+ groups->insert(strtoul(row[0], 0, 10));
+
+ return groups;
+}
+
+
+boost::shared_ptr<const std::map<unsigned long, Common::GroupInfo> > UserDBBackendMysql::getGroupList(boost::posix_time::ptime *timestamp) throw(Core::Exception) {
+ application->getThreadManager()->detach();
+
+ boost::unique_lock<boost::mutex> lock(mutex);
+
+ if(timestamp) {
+ if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate)
+ *timestamp = lastUpdate;
+ else
+ return boost::shared_ptr<const std::map<unsigned long, Common::GroupInfo> >();
+ }
+
+ Result result = query(queryListGroups);
+
+ lock.unlock();
+
+ 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 = result.getNextRow()) {
+ Common::GroupInfo group(strtoul(row[0], 0, 10), row[1]);
+
+ groups->insert(std::make_pair(group.getGid(), group));
+ }
+
+ return groups;
+}
+
+boost::shared_ptr<const Common::GroupInfo> UserDBBackendMysql::getGroupInfo(unsigned long gid, boost::posix_time::ptime *timestamp) throw(Core::Exception) {
+ application->getThreadManager()->detach();
+
+ boost::unique_lock<boost::mutex> lock(mutex);
+
+ if(timestamp) {
+ if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate)
+ *timestamp = lastUpdate;
+ else
+ return boost::shared_ptr<const Common::GroupInfo>();
+ }
+
+ ArgumentMap args;
+ args.insert(std::make_pair("GID", gid));
+
+ Result result = query(queryGroupById, args);
+
+ lock.unlock();
+
+ if(!result || result.getErrno() || result.getFieldNumber() < 2)
+ throw Core::Exception(Core::Exception::NOT_AVAILABLE);
+
+ MYSQL_ROW row = result.getNextRow();
+
+ if(row)
+ return boost::shared_ptr<Common::GroupInfo>(new Common::GroupInfo(strtoul(row[0], 0, 10), row[1]));
+
+ throw Core::Exception(Core::Exception::NOT_FOUND);
+}
+
+boost::shared_ptr<const Common::GroupInfo> UserDBBackendMysql::getGroupInfoByName(const std::string &name, boost::posix_time::ptime *timestamp) throw(Core::Exception) {
+ application->getThreadManager()->detach();
+
+ boost::unique_lock<boost::mutex> lock(mutex);
+
+ if(timestamp) {
+ if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate)
+ *timestamp = lastUpdate;
+ else
+ return boost::shared_ptr<const Common::GroupInfo>();
+ }
+
+ ArgumentMap args;
+ args.insert(std::make_pair("GROUP", name));
+
+ Result result = query(queryGroupByName, args);
+
+ lock.unlock();
+
+ if(!result || result.getErrno() || result.getFieldNumber() < 2)
+ throw Core::Exception(Core::Exception::NOT_AVAILABLE);
+
+ MYSQL_ROW row = result.getNextRow();
+
+ if(row)
+ return boost::shared_ptr<Common::GroupInfo>(new Common::GroupInfo(strtoul(row[0], 0, 10), row[1]));
+
+ throw Core::Exception(Core::Exception::NOT_FOUND);
+}
+
+boost::shared_ptr<const std::set<unsigned long> > UserDBBackendMysql::getGroupUserList(unsigned long gid, boost::posix_time::ptime *timestamp) throw(Core::Exception) {
+ application->getThreadManager()->detach();
+
+ boost::unique_lock<boost::mutex> lock(mutex);
+
+ if(timestamp) {
+ if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate)
+ *timestamp = lastUpdate;
+ else
+ return boost::shared_ptr<const std::set<unsigned long> >();
+ }
+
+ ArgumentMap args;
+ args.insert(std::make_pair("GID", gid));
+
+ Result result = query(queryListGroupUsers, args);
+
+ lock.unlock();
+
+ 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 = result.getNextRow())
+ users->insert(strtoul(row[0], 0, 10));
+
+ return users;
+}
+
+boost::shared_ptr<const std::multimap<unsigned long, unsigned long> > UserDBBackendMysql::getFullUserGroupList(boost::posix_time::ptime *timestamp) throw(Core::Exception) {
+ application->getThreadManager()->detach();
+
+ boost::unique_lock<boost::mutex> lock(mutex);
+
+ if(timestamp) {
+ if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate)
+ *timestamp = lastUpdate;
+ else
+ return boost::shared_ptr<const std::multimap<unsigned long, unsigned long> >();
+ }
+
+ Result result = query(queryUserGroupTable);
+
+ lock.unlock();
+
+ 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 = result.getNextRow())
+ usergroups->insert(std::make_pair(strtoul(row[0], 0, 10), strtoul(row[1], 0, 10)));
+
+ return usergroups;
+}
+
+void UserDBBackendMysql::addUser(const Common::UserInfo &userInfo) throw(Core::Exception) {
+ application->getThreadManager()->detach();
+
+ boost::lock_guard<boost::mutex> lock(mutex);
+
+ ArgumentMap args;
+ args.insert(std::make_pair("UID", userInfo.getUid()));
+ args.insert(std::make_pair("GID", userInfo.getGid()));
+ args.insert(std::make_pair("USER", userInfo.getUsername()));
+ args.insert(std::make_pair("FULL_NAME", userInfo.getFullName()));
+
+ Result result = query(queryAddUser, args);
+
+ 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();
+}
+
+void UserDBBackendMysql::updateUser(unsigned long uid, const Common::UserInfo &userInfo) throw(Core::Exception) {
+ application->getThreadManager()->detach();
+
+ boost::lock_guard<boost::mutex> lock(mutex);
+
+ ArgumentMap args;
+ args.insert(std::make_pair("ORIG_UID", uid));
+ args.insert(std::make_pair("UID", userInfo.getUid()));
+ args.insert(std::make_pair("GID", userInfo.getGid()));
+ args.insert(std::make_pair("USER", userInfo.getUsername()));
+ args.insert(std::make_pair("FULL_NAME", userInfo.getFullName()));
+
+ Result result = query(queryUpdateUser, args);
+
+ 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();
+}
+
+void UserDBBackendMysql::deleteUser(unsigned long uid) throw(Core::Exception) {
+ application->getThreadManager()->detach();
+
+ boost::lock_guard<boost::mutex> lock(mutex);
+
+ ArgumentMap args;
+ args.insert(std::make_pair("UID", uid));
+
+ Result result = query(queryDeleteUser, args);
+
+ if(result.getErrno())
+ throw Core::Exception(Core::Exception::NOT_AVAILABLE);
+
+ lastUpdate = boost::posix_time::microsec_clock::universal_time();
+}
+
+void UserDBBackendMysql::addGroup(const Common::GroupInfo &groupInfo) throw(Core::Exception) {
+ application->getThreadManager()->detach();
+
+ boost::lock_guard<boost::mutex> lock(mutex);
+
+ ArgumentMap args;
+ args.insert(std::make_pair("GID", groupInfo.getGid()));
+ args.insert(std::make_pair("GROUP", groupInfo.getName()));
+
+ Result result = query(queryAddGroup, args);
+
+ 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();
+}
+
+void UserDBBackendMysql::updateGroup(unsigned long gid, const Common::GroupInfo &groupInfo) throw(Core::Exception) {
+ application->getThreadManager()->detach();
+
+ boost::lock_guard<boost::mutex> lock(mutex);
+
+ ArgumentMap args;
+ args.insert(std::make_pair("ORIG_GID", gid));
+ args.insert(std::make_pair("GID", groupInfo.getGid()));
+ args.insert(std::make_pair("GROUP", groupInfo.getName()));
+
+ Result result = query(queryUpdateGroup, args);
+
+ 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();
+}
+
+void UserDBBackendMysql::deleteGroup(unsigned long gid) throw(Core::Exception) {
+ application->getThreadManager()->detach();
+
+ boost::lock_guard<boost::mutex> lock(mutex);
+
+ ArgumentMap args;
+ args.insert(std::make_pair("GID", gid));
+
+ Result result = query(queryDeleteGroup, args);
+
+ if(result.getErrno())
+ throw Core::Exception(Core::Exception::NOT_AVAILABLE);
+
+ lastUpdate = boost::posix_time::microsec_clock::universal_time();
+}
+
+void UserDBBackendMysql::addUserToGroup(unsigned long uid, unsigned long gid) throw(Core::Exception) {
+ application->getThreadManager()->detach();
+
+ boost::lock_guard<boost::mutex> lock(mutex);
+
+ ArgumentMap args;
+ args.insert(std::make_pair("UID", uid));
+ args.insert(std::make_pair("GID", gid));
+
+ Result result = query(queryAddUserToGroup, args);
+
+ if(result.getErrno()) {
+ if(result.getErrno() == ER_DUP_ENTRY)
+ return;
+ else
+ throw Core::Exception(Core::Exception::NOT_AVAILABLE);
+ }
+
+ lastUpdate = boost::posix_time::microsec_clock::universal_time();
+}
+
+void UserDBBackendMysql::deleteUserFromGroup(unsigned long uid, unsigned long gid) throw(Core::Exception) {
+ application->getThreadManager()->detach();
+
+ boost::lock_guard<boost::mutex> lock(mutex);
+
+ ArgumentMap args;
+ args.insert(std::make_pair("UID", uid));
+ args.insert(std::make_pair("GID", gid));
+
+ Result result = query(queryDeleteUserFromGroup, args);
+
+ if(result.getErrno())
+ throw Core::Exception(Core::Exception::NOT_AVAILABLE);
+
+ lastUpdate = boost::posix_time::microsec_clock::universal_time();
+}
+
+}
+}
+}
diff --git a/src/modules/UserDBBackendMysql/UserDBBackendMysql.h b/src/modules/UserDBBackendMysql/UserDBBackendMysql.h
new file mode 100644
index 0000000..959e133
--- /dev/null
+++ b/src/modules/UserDBBackendMysql/UserDBBackendMysql.h
@@ -0,0 +1,159 @@
+/*
+ * UserDBBackendMysql.h
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_MODULES_USERDBBACKENDMYSQL_USERDBBACKENDMYSQL_H_
+#define MAD_MODULES_USERDBBACKENDMYSQL_USERDBBACKENDMYSQL_H_
+
+#include <Common/UserDBBackend.h>
+#include <Common/Application.h>
+
+#include <Core/Configurable.h>
+#include <Core/ConfigManager.h>
+
+#include <mysql/mysql.h>
+
+#include <boost/thread/mutex.hpp>
+#include <boost/variant.hpp>
+
+namespace Mad {
+namespace Modules {
+namespace UserDBBackendMysql {
+
+class UserDBBackendMysql : public Common::UserDBBackend, private Core::Configurable, private boost::noncopyable {
+ private:
+ typedef std::map<std::string, boost::variant<std::string, unsigned long> > ArgumentMap;
+
+ class Result;
+ Result query(const std::string &query, const ArgumentMap &args = ArgumentMap()) throw(Core::Exception);
+
+ class Result {
+ private:
+ friend Result UserDBBackendMysql::query(const std::string &query, const ArgumentMap &args) throw(Core::Exception);
+
+ boost::shared_ptr<MYSQL_RES> result;
+
+ unsigned int mysqlErrno;
+ const char *error;
+
+ Result(MYSQL *mysql) {
+ result = boost::shared_ptr<MYSQL_RES>(mysql_store_result(mysql), mysql_free_result);
+
+ mysqlErrno = mysql_errno(mysql);
+ error = mysql_error(mysql);
+ }
+
+ public:
+ 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.get());
+ }
+
+ my_ulonglong getRowNumber() const {
+ return mysql_num_rows(result.get());
+ }
+
+ MYSQL_ROW getNextRow() {
+ return mysql_fetch_row(result.get());
+ }
+ };
+
+ static const std::string name;
+
+ Common::Application *application;
+
+ std::string host, username, passwd, db, unixSocket;
+ uint16_t port;
+
+ std::string queryListUsers, queryListGroups;
+ std::string queryListUserGroups, queryListGroupUsers;
+ std::string queryUserById, queryUserByName;
+ std::string queryGroupById, queryGroupByName;
+ std::string queryUserGroupTable;
+ std::string queryAddUser, queryUpdateUser, queryDeleteUser;
+ std::string queryAddGroup, queryUpdateGroup, queryDeleteGroup;
+ std::string queryAddUserToGroup, queryDeleteUserFromGroup;
+
+ MYSQL *mysql;
+
+ boost::posix_time::ptime lastUpdate;
+
+ boost::mutex mutex;
+
+ protected:
+ virtual bool handleConfigEntry(const Core::ConfigEntry &entry, bool handled);
+ virtual void configFinished();
+
+ virtual boost::shared_ptr<const std::map<unsigned long, Common::UserInfo> > getUserList(boost::posix_time::ptime *timestamp) throw(Core::Exception);
+ virtual boost::shared_ptr<const Common::UserInfo> getUserInfo(unsigned long uid, boost::posix_time::ptime *timestamp) throw(Core::Exception);
+ virtual boost::shared_ptr<const Common::UserInfo> getUserInfoByName(const std::string &name, boost::posix_time::ptime *timestamp) throw(Core::Exception);
+ virtual boost::shared_ptr<const std::set<unsigned long> > getUserGroupList(unsigned long uid, boost::posix_time::ptime *timestamp) throw(Core::Exception);
+
+ virtual boost::shared_ptr<const std::map<unsigned long, Common::GroupInfo> > getGroupList(boost::posix_time::ptime *timestamp) throw(Core::Exception);
+ virtual boost::shared_ptr<const Common::GroupInfo> getGroupInfo(unsigned long gid, boost::posix_time::ptime *timestamp) throw(Core::Exception);
+ virtual boost::shared_ptr<const Common::GroupInfo> getGroupInfoByName(const std::string &name, boost::posix_time::ptime *timestamp) throw(Core::Exception);
+ virtual boost::shared_ptr<const std::set<unsigned long> > getGroupUserList(unsigned long gid, boost::posix_time::ptime *timestamp) throw(Core::Exception);
+
+ 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);
+ virtual void updateUser(unsigned long uid, const Common::UserInfo &userInfo) throw(Core::Exception);
+ virtual void deleteUser(unsigned long uid) throw(Core::Exception);
+
+ virtual void addGroup(const Common::GroupInfo &groupInfo) throw(Core::Exception);
+ virtual void updateGroup(unsigned long gid, const Common::GroupInfo &groupInfo) throw(Core::Exception);
+ virtual void deleteGroup(unsigned long gid) throw(Core::Exception);
+
+ virtual void addUserToGroup(unsigned long uid, unsigned long gid) throw(Core::Exception);
+ virtual void deleteUserFromGroup(unsigned long uid, unsigned long gid) throw(Core::Exception);
+
+ public:
+ UserDBBackendMysql(Common::Application *application0) : application(application0), port(0), mysql(0), lastUpdate(boost::posix_time::microsec_clock::universal_time()) {
+ application->getConfigManager()->registerConfigurable(this);
+ }
+
+ virtual ~UserDBBackendMysql() {
+ application->getConfigManager()->unregisterConfigurable(this);
+
+ if(mysql) {
+ mysql_close(mysql);
+ mysql = 0;
+ }
+ }
+
+ virtual const std::string& getName() {
+ return name;
+ }
+};
+
+}
+}
+}
+
+#endif /* MAD_MODULES_USERDBBACKENDMYSQL_USERBACKENDMYSQL_H_ */