diff --git a/CMakeLists.txt b/CMakeLists.txt index df2f5297..75e9d506 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,9 @@ find_package(cppunit) set(sqlite3_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") find_package(sqlite3) +set(mysql_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +find_package(mysql) + set(purple_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") find_package(purple) @@ -44,13 +47,22 @@ message(" Supported features") message("-----------------------") if (SQLITE3_FOUND) ADD_DEFINITIONS(-DWITH_SQLITE) - include_directories(SQLITE3_INCLUDE_DIR) + include_directories(${SQLITE3_INCLUDE_DIR}) message("SQLite3 : yes") else (SQLITE3_FOUND) set(SQLITE3_LIBRARIES "") message("SQLite3 : no") endif (SQLITE3_FOUND) +if (MYSQL_FOUND) + ADD_DEFINITIONS(-DWITH_MYSQL) + include_directories(${MYSQL_INCLUDE_DIR}) + message("MySQL : yes") +else (MYSQL_FOUND) + set(MYSQL_LIBRARIES "") + message("MySQL : no (install mysql-devel)") +endif (MYSQL_FOUND) + if (PROTOBUF_FOUND) ADD_DEFINITIONS(-DWITH_PROTOBUF) include_directories(${PROTOBUF_INCLUDE_DIRS}) diff --git a/cmake_modules/mysqlConfig.cmake b/cmake_modules/mysqlConfig.cmake new file mode 100644 index 00000000..a7cb27c4 --- /dev/null +++ b/cmake_modules/mysqlConfig.cmake @@ -0,0 +1,35 @@ +# - Find mysqlclient +# Find the native MySQL includes and library +# +# MYSQL_INCLUDE_DIR - where to find mysql.h, etc. +# MYSQL_LIBRARIES - List of libraries when using MySQL. +# MYSQL_FOUND - True if MySQL found. +# +# Based on: http://www.itk.org/Wiki/CMakeUserFindMySQL + +find_path( MYSQL_INCLUDE_DIR "mysql.h" + PATH_SUFFIXES "mysql" ) + +set( MYSQL_NAMES mysqlclient mysqlclient_r ) +find_library( MYSQL_LIBRARY + NAMES ${MYSQL_NAMES} + PATH_SUFFIXES "mysql" ) +mark_as_advanced( MYSQL_LIBRARY MYSQL_INCLUDE_DIR ) + +if( MYSQL_INCLUDE_DIR AND EXISTS "${MYSQL_INCLUDE_DIR}/mysql_version.h" ) + file( STRINGS "${MYSQL_INCLUDE_DIR}/mysql_version.h" MYSQL_VERSION_H REGEX "^#define[ \t]+MYSQL_SERVER_VERSION[ \t]+\"[^\"]+\".*$" ) + string( REGEX REPLACE "^.*MYSQL_SERVER_VERSION[ \t]+\"([^\"]+)\".*$" "\\1" MYSQL_VERSION_STRING "${MYSQL_VERSION_H}" ) +endif() + +# handle the QUIETLY and REQUIRED arguments and set MYSQL_FOUND to TRUE if +# all listed variables are TRUE +include( FindPackageHandleStandardArgs ) +FIND_PACKAGE_HANDLE_STANDARD_ARGS( MYSQL + REQUIRED_VARS MYSQL_LIBRARY MYSQL_INCLUDE_DIR + VERSION_VAR MYSQL_VERSION_STRING ) + +if( MYSQL_FOUND ) + set( MYSQL_LIBRARIES ${MYSQL_LIBRARY} ) + set( MYSQL_INCLUDE_DIRS ${PCRE_INCLUDE_DIR} ) + message( STATUS "Found MySQL: ${MYSQL_LIBRARY}, ${MYSQL_INCLUDE_DIR}") +endif() diff --git a/include/transport/mysqlbackend.h b/include/transport/mysqlbackend.h new file mode 100644 index 00000000..a6fdf7b2 --- /dev/null +++ b/include/transport/mysqlbackend.h @@ -0,0 +1,117 @@ +/** + * libtransport -- C++ library for easy XMPP Transports development + * + * Copyright (C) 2011, Jan Kaluza + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#pragma once + +#include +#include +#include "Swiften/Swiften.h" +#include "transport/storagebackend.h" +#include "transport/config.h" +#include "mysql.h" + +namespace Transport { + +/// Used to store transport data into SQLite3 database. +class MySQLBackend : public StorageBackend +{ + public: + /// Creates new MySQLBackend instance. + /// \param config cofiguration, this class uses following Config values: + /// - database.database - path to SQLite3 database file, database file is created automatically + /// - service.prefix - prefix for tables created by createDatabase method + MySQLBackend(Config *config); + + /// Destructor. + ~MySQLBackend(); + + /// Connects to the database and creates it if it's needed. This method call createDatabase() function + /// automatically. + /// \return true if database is opened successfully. + bool connect(); + + /// Creates database structure. + /// \see connect() + /// \return true if database structure has been created successfully. Note that it returns True also if database structure + /// already exists. + bool createDatabase(); + + /// Stores user into database. + /// \param user user struct containing all information about user which have to be stored + void setUser(const UserInfo &user); + + /// Gets user data from database and stores them into user reference. + /// \param barejid barejid of user + /// \param user UserInfo object where user data will be stored + /// \return true if user has been found in database + bool getUser(const std::string &barejid, UserInfo &user); + + /// Changes users online state variable in database. + /// \param id id of user - UserInfo.id + /// \param online online state + void setUserOnline(long id, bool online); + + /// Removes user and all connected data from database. + /// \param id id of user - UserInfo.id + /// \return true if user has been found in database and removed + bool removeUser(long id); + + /// Returns JIDs of all buddies in user's roster. + /// \param id id of user - UserInfo.id + /// \param roster string list used to store user's roster + /// \return true if user has been found in database and roster has been fetched + bool getBuddies(long id, std::list &roster); + + long addBuddy(long userId, const BuddyInfo &buddyInfo); + + void updateBuddy(long userId, const BuddyInfo &buddyInfo); + void removeBuddy(long id) {} + + void getUserSetting(long userId, const std::string &variable, int &type, std::string &value); + void updateUserSetting(long userId, const std::string &variable, const std::string &value); + + void beginTransaction(); + void commitTransaction(); + + private: + bool exec(const std::string &query); + + MYSQL *m_conn; + Config *m_config; + std::string m_prefix; + + // statements +// sqlite3_stmt *m_setUser; +// sqlite3_stmt *m_getUser; +// sqlite3_stmt *m_getUserSetting; +// sqlite3_stmt *m_setUserSetting; +// sqlite3_stmt *m_updateUserSetting; +// sqlite3_stmt *m_removeUser; +// sqlite3_stmt *m_removeUserBuddies; +// sqlite3_stmt *m_removeUserSettings; +// sqlite3_stmt *m_removeUserBuddiesSettings; +// sqlite3_stmt *m_addBuddy; +// sqlite3_stmt *m_updateBuddy; +// sqlite3_stmt *m_updateBuddySetting; +// sqlite3_stmt *m_getBuddies; +// sqlite3_stmt *m_getBuddiesSettings; +}; + +} diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index 52c082f5..613971b4 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -3,6 +3,7 @@ #include "transport/usermanager.h" #include "transport/logger.h" #include "transport/sqlite3backend.h" +#include "transport/mysqlbackend.h" #include "transport/userregistration.h" #include "transport/networkpluginserver.h" #include "transport/admininterface.h" @@ -83,7 +84,12 @@ int main(int argc, char **argv) if (CONFIG_STRING(&config, "database.type") == "sqlite3") { storageBackend = new SQLite3Backend(&config); -// logger.setStorageBackend(storageBackend); + if (!storageBackend->connect()) { + std::cerr << "Can't connect to database.\n"; + } + } + else if (CONFIG_STRING(&config, "database.type") == "mysql") { + storageBackend = new MySQLBackend(&config); if (!storageBackend->connect()) { std::cerr << "Can't connect to database.\n"; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index afddee24..45b23418 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,7 +12,7 @@ endif() ADD_LIBRARY(transport SHARED ${HEADERS} ${SRC} ${SWIFTEN_SRC} ${PROTOBUF_SRC} ${PROTOBUF_HDRS}) ADD_DEFINITIONS(-fPIC) -TARGET_LINK_LIBRARIES(transport ${Boost_LIBRARIES} ${SQLITE3_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES} -lpopt) +TARGET_LINK_LIBRARIES(transport ${Boost_LIBRARIES} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES} -lpopt) SET_TARGET_PROPERTIES(transport PROPERTIES VERSION ${TRANSPORT_VERSION} SOVERSION ${TRANSPORT_VERSION} diff --git a/src/config.cpp b/src/config.cpp index 7a772b5d..b0a66c2e 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -59,6 +59,10 @@ bool Config::load(const std::string &configfile, boost::program_options::options ("registration.encoding", value()->default_value("en"), "Default encoding in registration form") ("database.type", value()->default_value("none"), "Database type.") ("database.database", value()->default_value(""), "Database used to store data") + ("database.server", value()->default_value("localhost"), "Database server.") + ("database.user", value()->default_value(""), "Database user.") + ("database.password", value()->default_value(""), "Database Password.") + ("database.port", value()->default_value(0), "Database port.") ("database.prefix", value()->default_value(""), "Prefix of tables in database") ("logging.config", value()->default_value(""), "Path to log4cxx config file which is used for Spectrum 2 instance") ("logging.backend_config", value()->default_value(""), "Path to log4cxx config file which is used for backends") diff --git a/src/mysqlbackend.cpp b/src/mysqlbackend.cpp new file mode 100644 index 00000000..ae21071b --- /dev/null +++ b/src/mysqlbackend.cpp @@ -0,0 +1,145 @@ +/** + * libtransport -- C++ library for easy XMPP Transports development + * + * Copyright (C) 2011, Jan Kaluza + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "transport/mysqlbackend.h" +#include +#include "log4cxx/logger.h" + +using namespace log4cxx; + +#define SQLITE_DB_VERSION 3 +#define CHECK_DB_RESPONSE(stmt) \ + if(stmt) { \ + sqlite3_exec(m_db, "ROLLBACK;", NULL, NULL, NULL); \ + return 0; \ + } + +// Prepare the SQL statement +#define PREP_STMT(sql, str) \ + if(sqlite3_prepare_v2(m_db, std::string(str).c_str(), -1, &sql, NULL)) { \ + LOG4CXX_ERROR(logger, str<< (sqlite3_errmsg(m_db) == NULL ? "" : sqlite3_errmsg(m_db))); \ + return false; \ + } + +// Finalize the prepared statement +#define FINALIZE_STMT(prep) \ + if(prep != NULL) { \ + sqlite3_finalize(prep); \ + } + +#define BEGIN(STATEMENT) sqlite3_reset(STATEMENT);\ + int STATEMENT##_id = 1;\ + int STATEMENT##_id_get = 0;\ + (void)STATEMENT##_id_get; + +#define BIND_INT(STATEMENT, VARIABLE) sqlite3_bind_int(STATEMENT, STATEMENT##_id++, VARIABLE) +#define BIND_STR(STATEMENT, VARIABLE) sqlite3_bind_text(STATEMENT, STATEMENT##_id++, VARIABLE.c_str(), -1, SQLITE_STATIC) +#define RESET_GET_COUNTER(STATEMENT) STATEMENT##_id_get = 0; +#define GET_INT(STATEMENT) sqlite3_column_int(STATEMENT, STATEMENT##_id_get++) +#define GET_STR(STATEMENT) (const char *) sqlite3_column_text(STATEMENT, STATEMENT##_id_get++) +#define EXECUTE_STATEMENT(STATEMENT, NAME) if(sqlite3_step(STATEMENT) != SQLITE_DONE) {\ + LOG4CXX_ERROR(logger, NAME<< (sqlite3_errmsg(m_db) == NULL ? "" : sqlite3_errmsg(m_db)));\ + } + +using namespace boost; + +namespace Transport { + +static LoggerPtr logger = Logger::getLogger("MySQLBackend"); + +MySQLBackend::MySQLBackend(Config *config) { + m_config = config; + m_conn = NULL; + m_prefix = CONFIG_STRING(m_config, "database.prefix"); +} + +MySQLBackend::~MySQLBackend(){ + if (m_conn) { + mysql_close(m_conn); + } +} + +bool MySQLBackend::connect() { + LOG4CXX_INFO(logger, "Connecting database " << CONFIG_STRING(m_config, "database.database")); + if (!mysql_real_connect(m_conn, CONFIG_STRING(m_config, "database.server").c_str(), + CONFIG_STRING(m_config, "database.user").c_str(), + CONFIG_STRING(m_config, "database.password").c_str(), + CONFIG_STRING(m_config, "database.database").c_str(), + CONFIG_INT(m_config, "database.port"), NULL, 0)) { + LOG4CXX_ERROR(logger, "Can't connect database: " << mysql_error(m_conn)); + return false; + } + + return true; +} + +bool MySQLBackend::createDatabase() { + return true; +} + +bool MySQLBackend::exec(const std::string &query) { + return true; +} + +void MySQLBackend::setUser(const UserInfo &user) { +} + +bool MySQLBackend::getUser(const std::string &barejid, UserInfo &user) { + return false; +} + +void MySQLBackend::setUserOnline(long id, bool online) { + +} + +long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { + return 1; +} + +void MySQLBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { +} + +bool MySQLBackend::getBuddies(long id, std::list &roster) { + + return true; +} + +bool MySQLBackend::removeUser(long id) { + + return true; +} + +void MySQLBackend::getUserSetting(long id, const std::string &variable, int &type, std::string &value) { + +} + +void MySQLBackend::updateUserSetting(long id, const std::string &variable, const std::string &value) { + +} + +void MySQLBackend::beginTransaction() { +// exec("BEGIN TRANSACTION;"); +} + +void MySQLBackend::commitTransaction() { +// exec("COMMIT TRANSACTION;"); +} + +}