spectrum2/libtransport/MySQLBackend.cpp

691 lines
24 KiB
C++
Raw Permalink Normal View History

2011-08-06 15:31:23 +02:00
/**
* libtransport -- C++ library for easy XMPP Transports development
*
* Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
*
* 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
*/
2011-09-07 14:19:10 +02:00
#ifdef WITH_MYSQL
#include "transport/MySQLBackend.h"
#include "transport/Util.h"
#include "transport/Logging.h"
2011-08-06 15:31:23 +02:00
#include <boost/bind.hpp>
2011-08-09 15:02:28 +02:00
#define MYSQL_DB_VERSION 2
2011-08-06 15:31:23 +02:00
#define CHECK_DB_RESPONSE(stmt) \
if(stmt) { \
2011-10-26 22:28:05 +02:00
sqlite3_EXEC(m_db, "ROLLBACK;", NULL, NULL, NULL); \
2011-08-06 15:31:23 +02:00
return 0; \
}
// Prepare the SQL statement
#define PREP_STMT(sql, str) \
sql = mysql_stmt_init(&m_conn);\
if (mysql_stmt_prepare(sql, std::string(str).c_str(), std::string(str).size())) {\
LOG4CXX_ERROR(logger, str << " " << mysql_error(&m_conn)); \
2011-08-06 15:31:23 +02:00
return false; \
}
// Finalize the prepared statement
#define FINALIZE_STMT(prep) \
if(prep != NULL) { \
mysql_stmt_close(prep); \
2011-08-06 15:31:23 +02:00
}
#define BEGIN(STATEMENT, SIZE) MYSQL_BIND STATEMENT##_bind[SIZE]; \
memset(STATEMENT##_bind, 0, sizeof(STATEMENT##_bind)); \
2011-08-06 15:31:23 +02:00
int STATEMENT##_id = 1;\
int STATEMENT##_id_get = 0;\
(void)STATEMENT##_id_get;
#define BIND_INT(STATEMENT, VARIABLE) STATEMENT##_bind[STATEMENT##_id].buffer_type= MYSQL_TYPE_LONG;\
STATEMENT##_bind[STATEMENT##_id].buffer= (char *)&VARIABLE;\
STATEMENT##_bind[STATEMENT##_id].is_null= 0;\
STATEMENT##_bind[STATEMENT##_id++].length= 0;
#define BIND_STR(STATEMENT, VARIABLE) STATEMENT##_bind[STATEMENT##_id].buffer_type= MYSQL_TYPE_STRING;\
STATEMENT##_bind[STATEMENT##_id].buffer= VARIABLE.c_str();\
STATEMENT##_bind[STATEMENT##_id].buffer_length= STRING_SIZE;\
STATEMENT##_bind[STATEMENT##_id].is_null= 0;\
STATEMENT##_bind[STATEMENT##_id++].length= VARIABLE.size();
2011-08-06 15:31:23 +02:00
#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 (mysql_stmt_bind_param(STATEMENT, STATEMENT##_bind)) { \
LOG4CXX_ERROR(logger, NAME << " " << mysql_error(&m_conn)); \
} \
if (mysql_stmt_execute(STATEMENT)) { \
LOG4CXX_ERROR(logger, NAME << " " << mysql_error(&m_conn)); \
}
2011-08-06 15:31:23 +02:00
2011-10-26 22:28:05 +02:00
#define EXEC(STMT, METHOD) \
{\
int ret = STMT->execute(); \
if (ret == 0) \
exec_ok = true; \
else if (ret == 2013) { \
2011-10-26 22:29:55 +02:00
LOG4CXX_INFO(logger, "MySQL connection lost. Reconnecting...");\
2011-10-26 22:28:05 +02:00
disconnect(); \
connect(); \
return METHOD; \
} \
else \
exec_ok = false; \
}
2011-08-06 15:31:23 +02:00
namespace Transport {
2012-03-21 16:31:51 +01:00
DEFINE_LOGGER(logger, "MySQLBackend");
2011-10-26 22:28:05 +02:00
static bool exec_ok;
2011-08-06 15:31:23 +02:00
2011-08-12 16:16:43 +02:00
MySQLBackend::Statement::Statement(MYSQL *conn, const std::string &format, const std::string &statement) {
m_resultOffset = -1;
2011-08-12 18:32:53 +02:00
m_conn = conn;
2011-08-12 16:16:43 +02:00
m_offset = 0;
2011-08-12 18:32:53 +02:00
m_string = statement;
2011-08-12 16:16:43 +02:00
m_stmt = mysql_stmt_init(conn);
if (mysql_stmt_prepare(m_stmt, statement.c_str(), statement.size())) {
LOG4CXX_ERROR(logger, statement << " " << mysql_error(conn));
return;
}
2011-08-13 01:48:13 +02:00
for (int i = 0; i < format.length() && m_resultOffset == -1; i++) {
2011-08-12 16:16:43 +02:00
switch (format.at(i)) {
case 's':
m_params.resize(m_params.size() + 1);
memset(&m_params.back(), 0, sizeof(MYSQL_BIND));
m_params.back().buffer_type= MYSQL_TYPE_STRING;
m_params.back().buffer= (char *) malloc(sizeof(char) * 4096);
m_params.back().buffer_length= 4096;
m_params.back().is_null= 0;
m_params.back().length= (unsigned long *) malloc(sizeof(unsigned long));
break;
case 'i':
m_params.resize(m_params.size() + 1);
memset(&m_params.back(), 0, sizeof(MYSQL_BIND));
m_params.back().buffer_type= MYSQL_TYPE_LONG;
2011-08-13 17:26:56 +02:00
m_params.back().buffer= (int *) malloc(sizeof(int));
2011-08-12 16:16:43 +02:00
m_params.back().is_null= 0;
m_params.back().length= (unsigned long *) malloc(sizeof(unsigned long));
break;
case 'b':
m_params.resize(m_params.size() + 1);
memset(&m_params.back(), 0, sizeof(MYSQL_BIND));
m_params.back().buffer_type= MYSQL_TYPE_TINY;
2011-10-10 21:46:30 +02:00
m_params.back().buffer= (int *) malloc(sizeof(int));
2011-08-12 16:16:43 +02:00
m_params.back().is_null= 0;
m_params.back().length= (unsigned long *) malloc(sizeof(unsigned long));
break;
case '|':
m_resultOffset = i;
break;
}
}
2011-08-13 17:26:56 +02:00
for (int i = m_resultOffset; i >= 0 && i < format.length(); i++) {
2011-08-13 01:48:13 +02:00
switch (format.at(i)) {
case 's':
m_results.resize(m_results.size() + 1);
memset(&m_results.back(), 0, sizeof(MYSQL_BIND));
m_results.back().buffer_type= MYSQL_TYPE_STRING;
m_results.back().buffer= (char *) malloc(sizeof(char) * 4096);
m_results.back().buffer_length= 4096;
m_results.back().is_null= 0;
m_results.back().length= (unsigned long *) malloc(sizeof(unsigned long));
break;
case 'i':
m_results.resize(m_results.size() + 1);
memset(&m_results.back(), 0, sizeof(MYSQL_BIND));
m_results.back().buffer_type= MYSQL_TYPE_LONG;
2011-08-13 17:26:56 +02:00
m_results.back().buffer= (int *) malloc(sizeof(int));
2011-08-13 01:48:13 +02:00
m_results.back().is_null= 0;
m_results.back().length= (unsigned long *) malloc(sizeof(unsigned long));
break;
case 'b':
m_results.resize(m_results.size() + 1);
memset(&m_results.back(), 0, sizeof(MYSQL_BIND));
m_results.back().buffer_type= MYSQL_TYPE_TINY;
2011-10-10 21:46:30 +02:00
m_results.back().buffer= (int *) malloc(sizeof(int));
2011-08-13 01:48:13 +02:00
m_results.back().is_null= 0;
m_results.back().length= (unsigned long *) malloc(sizeof(unsigned long));
break;
}
}
2011-08-12 16:16:43 +02:00
if (mysql_stmt_bind_param(m_stmt, &m_params.front())) {
LOG4CXX_ERROR(logger, statement << " " << mysql_error(conn));
}
2011-08-13 01:48:13 +02:00
if (m_resultOffset < 0)
m_resultOffset = format.size();
else {
if (mysql_stmt_bind_result(m_stmt, &m_results.front())) {
LOG4CXX_ERROR(logger, statement << " " << mysql_error(conn));
}
}
m_resultOffset = 0;
2011-08-12 16:16:43 +02:00
}
MySQLBackend::Statement::~Statement() {
for (int i = 0; i < m_params.size(); i++) {
free(m_params[i].buffer);
free(m_params[i].length);
}
2011-08-13 14:40:58 +02:00
for (int i = 0; i < m_results.size(); i++) {
free(m_results[i].buffer);
free(m_results[i].length);
}
2011-08-12 16:16:43 +02:00
FINALIZE_STMT(m_stmt);
}
int MySQLBackend::Statement::execute() {
2011-08-12 16:16:43 +02:00
// If statement has some input and doesn't have any output, we have
// to clear the offset now, because operator>> will not be called.
2011-08-13 17:26:56 +02:00
m_offset = 0;
m_resultOffset = 0;
2011-08-13 17:52:04 +02:00
int ret;
if ((ret = mysql_stmt_execute(m_stmt)) != 0) {
LOG4CXX_ERROR(logger, m_string << " " << mysql_stmt_error(m_stmt) << "; " << mysql_error(m_conn));
return mysql_stmt_errno(m_stmt);
2011-08-12 16:16:43 +02:00
}
return 0;
2011-08-12 16:16:43 +02:00
}
2011-08-13 17:26:56 +02:00
int MySQLBackend::Statement::fetch() {
2011-08-13 01:48:13 +02:00
return mysql_stmt_fetch(m_stmt);
}
2011-08-12 16:16:43 +02:00
template <typename T>
MySQLBackend::Statement& MySQLBackend::Statement::operator << (const T& t) {
2011-08-13 14:40:58 +02:00
if (m_offset >= m_params.size())
2011-08-12 16:16:43 +02:00
return *this;
2011-10-10 21:46:30 +02:00
int *data = (int *) m_params[m_offset].buffer;
*data = (int) t;
2011-08-12 16:16:43 +02:00
2011-09-08 12:38:45 +02:00
// LOG4CXX_INFO(logger, "adding " << m_offset << ":" << (int) t);
2011-08-12 16:16:43 +02:00
m_offset++;
return *this;
}
MySQLBackend::Statement& MySQLBackend::Statement::operator << (const std::string& str) {
2011-08-13 14:40:58 +02:00
if (m_offset >= m_params.size())
2011-08-12 16:16:43 +02:00
return *this;
2011-09-08 12:38:45 +02:00
// LOG4CXX_INFO(logger, "adding " << m_offset << ":" << str << "(" << str.size() << ")");
2011-08-12 16:16:43 +02:00
strncpy((char*) m_params[m_offset].buffer, str.c_str(), 4096);
*m_params[m_offset].length = str.size();
m_offset++;
return *this;
}
template <typename T>
MySQLBackend::Statement& MySQLBackend::Statement::operator >> (T& t) {
2011-08-13 14:40:58 +02:00
if (m_resultOffset > m_results.size())
2011-08-12 16:16:43 +02:00
return *this;
2011-08-13 14:40:58 +02:00
if (!m_results[m_resultOffset].is_null) {
2011-10-10 21:46:30 +02:00
int *data = (int *) m_results[m_resultOffset].buffer;
t = (int) *data;
2011-09-08 12:38:45 +02:00
// std::cout << "getting " << m_resultOffset << " " << (int) t << "\n";
2011-08-13 01:48:13 +02:00
}
2011-08-13 14:40:58 +02:00
if (++m_resultOffset == m_results.size())
m_resultOffset = 0;
2011-08-13 01:48:13 +02:00
return *this;
}
MySQLBackend::Statement& MySQLBackend::Statement::operator >> (std::string& t) {
2011-09-08 12:38:45 +02:00
// std::cout << "getting " << m_resultOffset << "\n";
2011-08-13 14:40:58 +02:00
if (m_resultOffset > m_results.size())
2011-08-13 01:48:13 +02:00
return *this;
2011-08-13 14:40:58 +02:00
if (!m_results[m_resultOffset].is_null) {
t = (char *) m_results[m_resultOffset].buffer;
2011-08-13 01:48:13 +02:00
}
2011-08-13 14:40:58 +02:00
if (++m_resultOffset == m_results.size())
m_resultOffset = 0;
2011-08-12 16:16:43 +02:00
return *this;
}
2011-08-06 15:31:23 +02:00
MySQLBackend::MySQLBackend(Config *config) {
m_config = config;
2011-10-26 22:28:05 +02:00
m_prefix = CONFIG_STRING(m_config, "database.prefix");
2011-08-06 15:40:46 +02:00
mysql_init(&m_conn);
my_bool my_true = 1;
mysql_options(&m_conn, MYSQL_OPT_RECONNECT, &my_true);
2011-08-06 15:31:23 +02:00
}
MySQLBackend::~MySQLBackend(){
disconnect();
}
void MySQLBackend::disconnect() {
2011-10-26 22:28:05 +02:00
LOG4CXX_INFO(logger, "Disconnecting");
2011-08-12 16:16:43 +02:00
delete m_setUser;
2011-08-13 01:48:13 +02:00
delete m_getUser;
2011-08-13 17:26:56 +02:00
delete m_removeUser;
delete m_removeUserBuddies;
delete m_removeUserSettings;
delete m_removeUserBuddiesSettings;
delete m_addBuddy;
delete m_removeBuddy;
delete m_removeBuddySettings;
delete m_updateBuddy;
delete m_getBuddies;
delete m_getBuddiesSettings;
2011-09-08 10:13:42 +02:00
delete m_getUserSetting;
delete m_setUserSetting;
delete m_updateUserSetting;
2011-08-13 17:26:56 +02:00
delete m_updateBuddySetting;
delete m_getBuddySetting;
delete m_setUserOnline;
delete m_getOnlineUsers;
delete m_getUsers;
2011-08-06 15:40:46 +02:00
mysql_close(&m_conn);
2011-08-06 15:31:23 +02:00
}
bool MySQLBackend::connect() {
2011-08-06 15:40:46 +02:00
LOG4CXX_INFO(logger, "Connecting MySQL server " << CONFIG_STRING(m_config, "database.server") << ", user " <<
CONFIG_STRING(m_config, "database.user") << ", database " << CONFIG_STRING(m_config, "database.database") <<
", port " << CONFIG_INT(m_config, "database.port")
);
2011-10-26 22:28:05 +02:00
2011-08-06 15:40:46 +02:00
if (!mysql_real_connect(&m_conn, CONFIG_STRING(m_config, "database.server").c_str(),
2011-08-06 15:31:23 +02:00
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)) {
2011-08-06 15:40:46 +02:00
LOG4CXX_ERROR(logger, "Can't connect database: " << mysql_error(&m_conn));
2011-08-06 15:31:23 +02:00
return false;
}
2012-07-30 15:35:53 +02:00
if (!mysql_set_character_set(&m_conn, "utf8")) {
LOG4CXX_INFO(logger, "New client character set: " << mysql_character_set_name(&m_conn));
2012-07-30 14:51:03 +02:00
}
createDatabase();
2011-11-30 21:43:12 +01:00
m_setUser = new Statement(&m_conn, "sssssbss", "INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES (?, ?, ?, ?, ?, NOW(), ?) ON DUPLICATE KEY UPDATE uin=?, password=?");
2011-08-13 01:48:13 +02:00
m_getUser = new Statement(&m_conn, "s|isssssb", "SELECT id, jid, uin, password, encoding, language, vip FROM " + m_prefix + "users WHERE jid=?");
2011-08-13 17:26:56 +02:00
m_removeUser = new Statement(&m_conn, "i", "DELETE FROM " + m_prefix + "users WHERE id=?");
m_removeUserBuddies = new Statement(&m_conn, "i", "DELETE FROM " + m_prefix + "buddies WHERE user_id=?");
m_removeUserSettings = new Statement(&m_conn, "i", "DELETE FROM " + m_prefix + "users_settings WHERE user_id=?");
m_removeUserBuddiesSettings = new Statement(&m_conn, "i", "DELETE FROM " + m_prefix + "buddies_settings WHERE user_id=?");
2011-08-13 17:26:56 +02:00
m_addBuddy = new Statement(&m_conn, "issssi", "INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES (?, ?, ?, ?, ?, ?)");
m_removeBuddy = new Statement(&m_conn, "i", "DELETE FROM " + m_prefix + "buddies WHERE id=?");
m_removeBuddySettings = new Statement(&m_conn, "i", "DELETE FROM " + m_prefix + "buddies_settings WHERE buddy_id=?");
m_updateBuddy = new Statement(&m_conn, "ssisis", "UPDATE " + m_prefix + "buddies SET groups=?, nickname=?, flags=?, subscription=? WHERE user_id=? AND uin=?");
m_getBuddies = new Statement(&m_conn, "i|issssi", "SELECT id, uin, subscription, nickname, groups, flags FROM " + m_prefix + "buddies WHERE user_id=? ORDER BY id ASC");
m_getBuddiesSettings = new Statement(&m_conn, "i|iiss", "SELECT buddy_id, type, var, value FROM " + m_prefix + "buddies_settings WHERE user_id=? ORDER BY buddy_id ASC");
2011-08-13 17:26:56 +02:00
m_updateBuddySetting = new Statement(&m_conn, "iisiss", "INSERT INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE value=?");
m_getBuddySetting = new Statement(&m_conn, "is|is", "SELECT type, value FROM " + m_prefix + "buddies_settings WHERE user_id=? AND buddy_id=? AND var=?");
2011-09-08 10:13:42 +02:00
m_getUserSetting = new Statement(&m_conn, "is|is", "SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=? AND var=?");
m_setUserSetting = new Statement(&m_conn, "isis", "INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES (?,?,?,?)");
m_updateUserSetting = new Statement(&m_conn, "sis", "UPDATE " + m_prefix + "users_settings SET value=? WHERE user_id=? AND var=?");
m_setUserOnline = new Statement(&m_conn, "bi", "UPDATE " + m_prefix + "users SET online=?, last_login=NOW() WHERE id=?");
m_getOnlineUsers = new Statement(&m_conn, "|s", "SELECT jid FROM " + m_prefix + "users WHERE online=1");
m_getUsers = new Statement(&m_conn, "|s", "SELECT jid FROM " + m_prefix + "users");
2011-08-06 15:31:23 +02:00
return true;
}
bool MySQLBackend::createDatabase() {
2011-08-09 15:02:28 +02:00
int not_exist = exec("CREATE TABLE IF NOT EXISTS `" + m_prefix + "buddies` ("
"`id` int(10) unsigned NOT NULL auto_increment,"
"`user_id` int(10) unsigned NOT NULL,"
"`uin` varchar(255) collate utf8_bin NOT NULL,"
"`subscription` enum('to','from','both','ask','none') collate utf8_bin NOT NULL,"
"`nickname` varchar(255) collate utf8_bin NOT NULL,"
"`groups` varchar(255) collate utf8_bin NOT NULL,"
"`flags` smallint(4) NOT NULL DEFAULT '0',"
"PRIMARY KEY (`id`),"
"UNIQUE KEY `user_id` (`user_id`,`uin`)"
") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;");
if (not_exist) {
exec("CREATE TABLE IF NOT EXISTS `" + m_prefix + "buddies_settings` ("
"`user_id` int(10) unsigned NOT NULL,"
"`buddy_id` int(10) unsigned NOT NULL,"
"`var` varchar(50) collate utf8_bin NOT NULL,"
"`type` smallint(4) unsigned NOT NULL,"
"`value` varchar(255) collate utf8_bin NOT NULL,"
"PRIMARY KEY (`buddy_id`,`var`),"
"KEY `user_id` (`user_id`)"
") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;");
exec("CREATE TABLE IF NOT EXISTS `" + m_prefix + "users` ("
"`id` int(10) unsigned NOT NULL auto_increment,"
"`jid` varchar(255) collate utf8_bin NOT NULL,"
"`uin` varchar(4095) collate utf8_bin NOT NULL,"
"`password` varchar(255) collate utf8_bin NOT NULL,"
"`language` varchar(25) collate utf8_bin NOT NULL,"
"`encoding` varchar(50) collate utf8_bin NOT NULL default 'utf8',"
"`last_login` datetime,"
"`vip` tinyint(1) NOT NULL default '0',"
"`online` tinyint(1) NOT NULL default '0',"
"PRIMARY KEY (`id`),"
"UNIQUE KEY `jid` (`jid`)"
") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;");
exec("CREATE TABLE IF NOT EXISTS `" + m_prefix + "users_settings` ("
"`user_id` int(10) unsigned NOT NULL,"
"`var` varchar(50) collate utf8_bin NOT NULL,"
"`type` smallint(4) unsigned NOT NULL,"
"`value` varchar(255) collate utf8_bin NOT NULL,"
"PRIMARY KEY (`user_id`,`var`),"
"KEY `user_id` (`user_id`)"
") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;");
exec("CREATE TABLE IF NOT EXISTS `" + m_prefix + "db_version` ("
"`ver` int(10) unsigned NOT NULL default '1',"
"UNIQUE KEY `ver` (`ver`)"
") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;");
exec("INSERT IGNORE INTO `" + m_prefix + "db_version` (ver) VALUES ('2');");
2011-08-09 15:02:28 +02:00
}
2011-08-06 15:31:23 +02:00
return true;
}
bool MySQLBackend::exec(const std::string &query) {
2011-08-09 15:02:28 +02:00
if (mysql_query(&m_conn, query.c_str())) {
LOG4CXX_ERROR(logger, query << " " << mysql_error(&m_conn));
return false;
}
2011-08-06 15:31:23 +02:00
return true;
}
void MySQLBackend::setUser(const UserInfo &user) {
std::string encrypted = user.password;
if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) {
encrypted = StorageBackend::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key"));
}
2011-11-30 21:43:12 +01:00
*m_setUser << user.jid << user.uin << encrypted << user.language << user.encoding << user.vip << user.uin << encrypted;
2011-10-26 22:28:05 +02:00
EXEC(m_setUser, setUser(user));
2011-08-06 15:31:23 +02:00
}
bool MySQLBackend::getUser(const std::string &barejid, UserInfo &user) {
2011-08-13 01:48:13 +02:00
*m_getUser << barejid;
2011-10-26 22:28:05 +02:00
EXEC(m_getUser, getUser(barejid, user));
if (!exec_ok)
2011-08-13 01:48:13 +02:00
return false;
2011-08-13 17:52:04 +02:00
int ret = false;
while (m_getUser->fetch() == 0) {
ret = true;
*m_getUser >> user.id >> user.jid >> user.uin >> user.password >> user.encoding >> user.language >> user.vip;
if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) {
user.password = StorageBackend::decryptPassword(user.password, CONFIG_STRING(m_config, "database.encryption_key"));
}
2011-08-13 17:52:04 +02:00
}
2011-08-13 01:48:13 +02:00
if (!CONFIG_STRING(m_config, "database.vip_statement").empty()) {
std::string query = CONFIG_STRING(m_config, "database.vip_statement");
2012-11-13 17:31:47 +01:00
boost::replace_all(query, "$barejid", barejid);
LOG4CXX_INFO(logger, "Executing '" << query << "' to find out if user " << barejid << " is VIP");
if (exec(query)) {
MYSQL_RES *result = mysql_store_result(&m_conn);
if (result && mysql_num_rows(result) > 0) {
LOG4CXX_INFO(logger, "User " << barejid << " is VIP");
user.vip = 1;
}
else {
LOG4CXX_INFO(logger, "User " << barejid << " is not VIP");
user.vip = 0;
}
}
}
2011-08-13 17:52:04 +02:00
return ret;
2011-08-06 15:31:23 +02:00
}
void MySQLBackend::setUserOnline(long id, bool online) {
*m_setUserOnline << online << id;
2011-10-26 22:28:05 +02:00
EXEC(m_setUserOnline, setUserOnline(id, online));
2011-08-06 15:31:23 +02:00
}
bool MySQLBackend::getOnlineUsers(std::vector<std::string> &users) {
EXEC(m_getOnlineUsers, getOnlineUsers(users));
if (!exec_ok)
return false;
std::string jid;
while (m_getOnlineUsers->fetch() == 0) {
*m_getOnlineUsers >> jid;
users.push_back(jid);
}
return true;
}
bool MySQLBackend::getUsers(std::vector<std::string> &users) {
EXEC(m_getUsers, getUsers(users));
if (!exec_ok)
return false;
std::string jid;
while (m_getUsers->fetch() == 0) {
*m_getUsers >> jid;
users.push_back(jid);
}
return true;
}
2011-08-06 15:31:23 +02:00
long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) {
2011-08-13 17:26:56 +02:00
// "INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES (?, ?, ?, ?, ?, ?)"
std::string groups = StorageBackend::serializeGroups(buddyInfo.groups);
2011-08-13 17:26:56 +02:00
*m_addBuddy << userId << buddyInfo.legacyName << buddyInfo.subscription;
2011-11-30 21:43:12 +01:00
*m_addBuddy << groups;
2011-08-13 17:26:56 +02:00
*m_addBuddy << buddyInfo.alias << buddyInfo.flags;
2011-10-26 22:28:05 +02:00
EXEC(m_addBuddy, addBuddy(userId, buddyInfo));
2011-08-13 17:26:56 +02:00
long id = (long) mysql_insert_id(&m_conn);
// INSERT OR REPLACE INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES (?, ?, ?, ?, ?)
2012-02-15 22:31:08 +01:00
if (buddyInfo.settings.find("icon_hash") != buddyInfo.settings.end() && !buddyInfo.settings.find("icon_hash")->second.s.empty()) {
*m_updateBuddySetting << userId << id << buddyInfo.settings.find("icon_hash")->first << (int) TYPE_STRING << buddyInfo.settings.find("icon_hash")->second.s << buddyInfo.settings.find("icon_hash")->second.s;
2011-10-26 22:28:05 +02:00
EXEC(m_updateBuddySetting, addBuddy(userId, buddyInfo));
}
2011-08-13 17:26:56 +02:00
return id;
2011-08-06 15:31:23 +02:00
}
void MySQLBackend::updateBuddySetting(long userId, long buddyId, const std::string &variable, int type, const std::string &value) {
*m_updateBuddySetting << userId << buddyId << variable << type << value << value;
EXEC(m_updateBuddySetting, updateBuddySetting(userId, buddyId, variable, type, value));
}
void MySQLBackend::getBuddySetting(long userId, long buddyId, const std::string &variable, int &type, std::string &value) {
// "SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=? AND var=?"
*m_getBuddySetting << userId << buddyId << variable;
EXEC(m_getBuddySetting, getBuddySetting(userId, buddyId, variable, type, value));
if (m_getBuddySetting->fetch() == 0) {
*m_getBuddySetting >> type >> value;
}
while (m_getBuddySetting->fetch() == 0) {
}
}
void MySQLBackend::removeBuddy(long id) {
*m_removeBuddy << (int) id;
EXEC(m_removeBuddy, removeBuddy(id));
if (!exec_ok)
return;
*m_removeBuddySettings << (int) id;
EXEC(m_removeBuddySettings, removeBuddy(id));
if (!exec_ok)
return;
}
2011-08-06 15:31:23 +02:00
void MySQLBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) {
// "UPDATE " + m_prefix + "buddies SET groups=?, nickname=?, flags=?, subscription=? WHERE user_id=? AND uin=?"
std::string groups = StorageBackend::serializeGroups(buddyInfo.groups);
2011-11-30 21:43:12 +01:00
*m_updateBuddy << groups;
*m_updateBuddy << buddyInfo.alias << buddyInfo.flags << buddyInfo.subscription;
*m_updateBuddy << userId << buddyInfo.legacyName;
2011-10-26 22:28:05 +02:00
EXEC(m_updateBuddy, updateBuddy(userId, buddyInfo));
2011-08-06 15:31:23 +02:00
}
bool MySQLBackend::getBuddies(long id, std::list<BuddyInfo> &roster) {
// SELECT id, uin, subscription, nickname, groups, flags FROM " + m_prefix + "buddies WHERE user_id=? ORDER BY id ASC
*m_getBuddies << id;
// "SELECT buddy_id, type, var, value FROM " + m_prefix + "buddies_settings WHERE user_id=? ORDER BY buddy_id ASC"
*m_getBuddiesSettings << id;
SettingVariableInfo var;
long buddy_id = -1;
std::string key;
2011-10-26 22:28:05 +02:00
EXEC(m_getBuddies, getBuddies(id, roster));
if (!exec_ok)
return false;
while (m_getBuddies->fetch() == 0) {
BuddyInfo b;
std::string group;
*m_getBuddies >> b.id >> b.legacyName >> b.subscription >> b.alias >> group >> b.flags;
2011-11-30 21:43:12 +01:00
if (!group.empty()) {
b.groups = StorageBackend::deserializeGroups(group);
2011-11-30 21:43:12 +01:00
}
roster.push_back(b);
}
2011-10-26 22:28:05 +02:00
EXEC(m_getBuddiesSettings, getBuddies(id, roster));
if (!exec_ok)
return false;
BOOST_FOREACH(BuddyInfo &b, roster) {
if (buddy_id == b.id) {
2011-10-18 22:42:36 +02:00
// std::cout << "Adding buddy info setting " << key << "\n";
b.settings[key] = var;
buddy_id = -1;
}
2011-08-06 15:31:23 +02:00
while(buddy_id == -1 && m_getBuddiesSettings->fetch() == 0) {
std::string val;
*m_getBuddiesSettings >> buddy_id >> var.type >> key >> val;
switch (var.type) {
case TYPE_BOOLEAN:
var.b = atoi(val.c_str());
break;
case TYPE_STRING:
var.s = val;
break;
default:
if (buddy_id == b.id) {
buddy_id = -1;
}
continue;
break;
}
if (buddy_id == b.id) {
2011-10-18 22:42:36 +02:00
// std::cout << "Adding buddy info setting " << key << "=" << val << "\n";
b.settings[key] = var;
buddy_id = -1;
}
}
}
while(m_getBuddiesSettings->fetch() == 0) {
2011-09-08 10:13:42 +02:00
// TODO: probably remove those settings, because there's no buddy for them.
// It should not happend, but one never know...
}
2011-08-06 15:31:23 +02:00
return true;
}
bool MySQLBackend::removeUser(long id) {
2011-08-13 17:26:56 +02:00
*m_removeUser << (int) id;
2011-10-26 22:28:05 +02:00
EXEC(m_removeUser, removeUser(id));
if (!exec_ok)
2011-08-13 17:26:56 +02:00
return false;
*m_removeUserSettings << (int) id;
2011-10-26 22:28:05 +02:00
EXEC(m_removeUserSettings, removeUser(id));
if (!exec_ok)
2011-08-13 17:26:56 +02:00
return false;
*m_removeUserBuddies << (int) id;
2011-10-26 22:28:05 +02:00
EXEC(m_removeUserBuddies, removeUser(id));
if (!exec_ok)
2011-08-13 17:26:56 +02:00
return false;
*m_removeUserBuddiesSettings << (int) id;
2011-10-26 22:28:05 +02:00
EXEC(m_removeUserBuddiesSettings, removeUser(id));
if (!exec_ok)
2011-08-13 17:26:56 +02:00
return false;
2011-08-06 15:31:23 +02:00
return true;
}
void MySQLBackend::getUserSetting(long id, const std::string &variable, int &type, std::string &value) {
2011-09-08 10:13:42 +02:00
// "SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=? AND var=?"
*m_getUserSetting << id << variable;
2011-10-26 22:28:05 +02:00
EXEC(m_getUserSetting, getUserSetting(id, variable, type, value));
2011-09-08 10:13:42 +02:00
if (m_getUserSetting->fetch() != 0) {
// "INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES (?,?,?,?)"
*m_setUserSetting << id << variable << type << value;
2011-10-26 22:28:05 +02:00
EXEC(m_setUserSetting, getUserSetting(id, variable, type, value));
2011-09-08 10:13:42 +02:00
}
else {
*m_getUserSetting >> type >> value;
}
2012-02-15 22:31:08 +01:00
while (m_getUserSetting->fetch() == 0) {
}
2011-08-06 15:31:23 +02:00
}
void MySQLBackend::updateUserSetting(long id, const std::string &variable, const std::string &value) {
2011-09-08 10:13:42 +02:00
// "UPDATE " + m_prefix + "users_settings SET value=? WHERE user_id=? AND var=?"
*m_updateUserSetting << value << id << variable;
2011-10-26 22:28:05 +02:00
EXEC(m_updateUserSetting, updateUserSetting(id, variable, value));
2011-08-06 15:31:23 +02:00
}
void MySQLBackend::beginTransaction() {
exec("START TRANSACTION;");
2011-08-06 15:31:23 +02:00
}
void MySQLBackend::commitTransaction() {
exec("COMMIT;");
2011-08-06 15:31:23 +02:00
}
}
2011-09-07 14:19:10 +02:00
#endif