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
2015-11-18 14:05:57 +01:00
# 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) \
2011-08-06 18:16:09 +02:00
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 ) { \
2011-08-06 18:16:09 +02:00
mysql_stmt_close ( prep ) ; \
2011-08-06 15:31:23 +02:00
}
2011-08-06 18:16:09 +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 ;
2011-08-06 18:16:09 +02:00
# 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++)
2011-08-06 18:16:09 +02:00
# 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 ) ;
}
2011-10-26 17:49:05 +02:00
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 ) ) ;
2011-10-26 17:49:05 +02:00
return mysql_stmt_errno ( m_stmt ) ;
2011-08-12 16:16:43 +02:00
}
2011-10-26 17:49:05 +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 ) ;
2011-10-19 19:58:56 +02:00
my_bool my_true = 1 ;
mysql_options ( & m_conn , MYSQL_OPT_RECONNECT , & my_true ) ;
2011-08-06 15:31:23 +02:00
}
MySQLBackend : : ~ MySQLBackend ( ) {
2011-10-26 17:49:05 +02:00
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 ;
2012-08-07 14:16:27 +02:00
delete m_removeBuddy ;
delete m_removeBuddySettings ;
2011-09-08 08:52:12 +02:00
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 ;
2012-08-07 14:16:27 +02:00
delete m_getBuddySetting ;
2011-09-11 12:09:07 +02:00
delete m_setUserOnline ;
2011-12-07 10:30:39 +01:00
delete m_getOnlineUsers ;
2015-11-24 12:26:26 +01:00
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
}
2011-08-11 12:46:20 +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-06 18:16:09 +02:00
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-06 18:16:09 +02:00
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 (?, ?, ?, ?, ?, ?) " ) ;
2012-08-07 14:16:27 +02:00
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=? " ) ;
2011-09-08 08:52:12 +02:00
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=? " ) ;
2012-08-07 14:16:27 +02:00
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-08-06 18:16:09 +02:00
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=? " ) ;
2011-08-06 18:16:09 +02:00
2011-09-11 12:09:07 +02:00
m_setUserOnline = new Statement ( & m_conn , " bi " , " UPDATE " + m_prefix + " users SET online=?, last_login=NOW() WHERE id=? " ) ;
2011-12-07 10:30:39 +01:00
m_getOnlineUsers = new Statement ( & m_conn , " |s " , " SELECT jid FROM " + m_prefix + " users WHERE online=1 " ) ;
2015-11-24 12:26:26 +01:00
m_getUsers = new Statement ( & m_conn , " |s " , " SELECT jid FROM " + m_prefix + " users " ) ;
2011-09-11 12:09:07 +02:00
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; " ) ;
2016-05-27 23:48:51 +03:00
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 ) {
2011-11-01 22:13:35 +01:00
std : : string encrypted = user . password ;
if ( ! CONFIG_STRING ( m_config , " database.encryption_key " ) . empty ( ) ) {
2012-10-31 09:12:33 +01:00
encrypted = StorageBackend : : encryptPassword ( encrypted , CONFIG_STRING ( m_config , " database.encryption_key " ) ) ;
2011-11-01 22:13:35 +01:00
}
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 ;
2011-11-01 22:13:35 +01:00
if ( ! CONFIG_STRING ( m_config , " database.encryption_key " ) . empty ( ) ) {
2012-10-31 09:12:33 +01:00
user . password = StorageBackend : : decryptPassword ( user . password , CONFIG_STRING ( m_config , " database.encryption_key " ) ) ;
2011-11-01 22:13:35 +01:00
}
2011-08-13 17:52:04 +02:00
}
2011-08-13 01:48:13 +02:00
2012-11-13 12:37:42 +01: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 ) ;
2012-11-13 12:37:42 +01:00
LOG4CXX_INFO ( logger , " Executing ' " < < query < < " ' to find out if user " < < barejid < < " is VIP " ) ;
if ( exec ( query ) ) {
MYSQL_RES * result = mysql_store_result ( & m_conn ) ;
2012-11-13 17:38:07 +01:00
if ( result & & mysql_num_rows ( result ) > 0 ) {
2012-11-13 12:37:42 +01:00
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 ) {
2011-09-11 12:09:07 +02:00
* 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
}
2011-12-07 10:30:39 +01: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 ;
}
2015-11-24 12:26:26 +01:00
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 (?, ?, ?, ?, ?, ?)"
2012-10-31 09:12:33 +01:00
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 ( ) ) {
2011-09-08 08:52:12 +02:00
* 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-09-08 08:52:12 +02:00
}
2011-08-13 17:26:56 +02:00
return id ;
2011-08-06 15:31:23 +02:00
}
2012-08-07 14:16:27 +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 ) {
2011-09-08 08:52:12 +02:00
// "UPDATE " + m_prefix + "buddies SET groups=?, nickname=?, flags=?, subscription=? WHERE user_id=? AND uin=?"
2012-10-31 09:12:33 +01:00
std : : string groups = StorageBackend : : serializeGroups ( buddyInfo . groups ) ;
2011-11-30 21:43:12 +01:00
* m_updateBuddy < < groups ;
2011-09-08 08:52:12 +02:00
* 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 ) {
2011-09-08 08:52:12 +02:00
// 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 )
2011-09-08 08:52:12 +02:00
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 ( ) ) {
2012-10-31 09:12:33 +01:00
b . groups = StorageBackend : : deserializeGroups ( group ) ;
2011-11-30 21:43:12 +01:00
}
2011-09-08 08:52:12 +02:00
roster . push_back ( b ) ;
}
2011-10-26 22:28:05 +02:00
EXEC ( m_getBuddiesSettings , getBuddies ( id , roster ) ) ;
if ( ! exec_ok )
2011-09-08 08:52:12 +02:00
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";
2011-09-08 08:52:12 +02:00
b . settings [ key ] = var ;
buddy_id = - 1 ;
}
2011-08-06 15:31:23 +02:00
2011-09-08 08:52:12 +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";
2011-09-08 08:52:12 +02:00
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-09-08 08:52:12 +02:00
}
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 ( ) {
2012-07-29 05:59:55 +02:00
exec ( " START TRANSACTION; " ) ;
2011-08-06 15:31:23 +02:00
}
void MySQLBackend : : commitTransaction ( ) {
2012-07-29 05:59:55 +02:00
exec ( " COMMIT; " ) ;
2011-08-06 15:31:23 +02:00
}
}
2011-09-07 14:19:10 +02:00
# endif