From: Marcus Eggenberger Date: Sat, 21 Feb 2009 15:47:18 +0000 (+0100) Subject: first version of postgres backend X-Git-Tag: 0.5-rc1~335 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=029c6d402af7b00b320dd5ce48f230783a88957a first version of postgres backend --- diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index e0e2044d..17137607 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -26,6 +26,7 @@ set(SOURCES coreusersettings.cpp ctcphandler.cpp ircserverhandler.cpp + postgresqlstorage.cpp sessionthread.cpp sqlitestorage.cpp storage.cpp @@ -49,6 +50,7 @@ set(MOC_HDRS coresession.h ctcphandler.h ircserverhandler.h + postgresqlstorage.h sqlitestorage.h storage.h sessionthread.h diff --git a/src/core/SQL/PostgreSQL/14/delete_backlog_by_uid.sql b/src/core/SQL/PostgreSQL/14/delete_backlog_by_uid.sql new file mode 100644 index 00000000..b5520ec1 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/delete_backlog_by_uid.sql @@ -0,0 +1,2 @@ +DELETE FROM backlog +WHERE bufferid IN (SELECT DISTINCT bufferid FROM buffer WHERE userid = :userid) diff --git a/src/core/SQL/PostgreSQL/14/delete_backlog_for_buffer.sql b/src/core/SQL/PostgreSQL/14/delete_backlog_for_buffer.sql new file mode 100644 index 00000000..38bf5643 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/delete_backlog_for_buffer.sql @@ -0,0 +1,2 @@ +DELETE FROM backlog +WHERE bufferid = :bufferid diff --git a/src/core/SQL/PostgreSQL/14/delete_backlog_for_network.sql b/src/core/SQL/PostgreSQL/14/delete_backlog_for_network.sql new file mode 100644 index 00000000..07a893fa --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/delete_backlog_for_network.sql @@ -0,0 +1,2 @@ +DELETE FROM backlog +WHERE bufferid IN (SELECT bufferid FROM buffer WHERE networkid = :networkid) diff --git a/src/core/SQL/PostgreSQL/14/delete_buffer_for_bufferid.sql b/src/core/SQL/PostgreSQL/14/delete_buffer_for_bufferid.sql new file mode 100644 index 00000000..91dfeb97 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/delete_buffer_for_bufferid.sql @@ -0,0 +1,2 @@ +DELETE FROM buffer +WHERE bufferid = :bufferid diff --git a/src/core/SQL/PostgreSQL/14/delete_buffers_by_uid.sql b/src/core/SQL/PostgreSQL/14/delete_buffers_by_uid.sql new file mode 100644 index 00000000..14f56ac8 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/delete_buffers_by_uid.sql @@ -0,0 +1,2 @@ +DELETE FROM buffer +WHERE userid = :userid diff --git a/src/core/SQL/PostgreSQL/14/delete_buffers_for_network.sql b/src/core/SQL/PostgreSQL/14/delete_buffers_for_network.sql new file mode 100644 index 00000000..9b9ccdb7 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/delete_buffers_for_network.sql @@ -0,0 +1,2 @@ +DELETE FROM buffer +WHERE networkid = :networkid diff --git a/src/core/SQL/PostgreSQL/14/delete_identity.sql b/src/core/SQL/PostgreSQL/14/delete_identity.sql new file mode 100644 index 00000000..7d25c0e8 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/delete_identity.sql @@ -0,0 +1,2 @@ +DELETE FROM identity +WHERE identityid = :identityid AND userid = :userid diff --git a/src/core/SQL/PostgreSQL/14/delete_ircservers_for_network.sql b/src/core/SQL/PostgreSQL/14/delete_ircservers_for_network.sql new file mode 100644 index 00000000..c74e5979 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/delete_ircservers_for_network.sql @@ -0,0 +1,2 @@ +DELETE FROM ircserver +WHERE networkid = :networkid diff --git a/src/core/SQL/PostgreSQL/14/delete_network.sql b/src/core/SQL/PostgreSQL/14/delete_network.sql new file mode 100644 index 00000000..7200ee4d --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/delete_network.sql @@ -0,0 +1,2 @@ +DELETE FROM network +WHERE networkid = :networkid diff --git a/src/core/SQL/PostgreSQL/14/delete_networks_by_uid.sql b/src/core/SQL/PostgreSQL/14/delete_networks_by_uid.sql new file mode 100644 index 00000000..0542d85a --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/delete_networks_by_uid.sql @@ -0,0 +1,2 @@ +DELETE FROM network +WHERE userid = :userid diff --git a/src/core/SQL/PostgreSQL/14/delete_nicks.sql b/src/core/SQL/PostgreSQL/14/delete_nicks.sql new file mode 100644 index 00000000..8aac5997 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/delete_nicks.sql @@ -0,0 +1,2 @@ +DELETE FROM identity_nick +WHERE identityid = :identityid; diff --git a/src/core/SQL/PostgreSQL/14/delete_quasseluser.sql b/src/core/SQL/PostgreSQL/14/delete_quasseluser.sql new file mode 100644 index 00000000..f9bc9ae5 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/delete_quasseluser.sql @@ -0,0 +1,2 @@ +DELETE FROM quasseluser +WHERE userid = :userid diff --git a/src/core/SQL/PostgreSQL/14/insert_buffer.sql b/src/core/SQL/PostgreSQL/14/insert_buffer.sql new file mode 100644 index 00000000..e3dd6aa0 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/insert_buffer.sql @@ -0,0 +1,3 @@ +INSERT INTO buffer (userid, networkid, buffername, buffercname, buffertype) +VALUES (:userid, :networkid, :buffername, :buffercname, :buffertype) +RETURNING bufferid diff --git a/src/core/SQL/PostgreSQL/14/insert_identity.sql b/src/core/SQL/PostgreSQL/14/insert_identity.sql new file mode 100644 index 00000000..63182689 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/insert_identity.sql @@ -0,0 +1,3 @@ +INSERT INTO identity (userid, identityname, realname, awaynick, awaynickenabled, awayreason, awayreasonenabled, autoawayenabled, autoawaytime, autoawayreason, autoawayreasonenabled, detachawayenabled, detachawayreason, detachawayreasonenabled, ident, kickreason, partreason, quitreason, sslcert, sslkey) +VALUES (:userid, :identityname, :realname, :awaynick, :awaynickenabled, :awayreason, :awayreasonenabled, :autoawayenabled, :autoawaytime, :autoawayreason, :autoawayreasonenabled, :detachawayenabled, :detachawayreason, :detachawayreasonenabled, :ident, :kickreason, :partreason, :quitreason, :sslcert, :sslkey) +RETURNING identityid diff --git a/src/core/SQL/PostgreSQL/14/insert_message.sql b/src/core/SQL/PostgreSQL/14/insert_message.sql new file mode 100644 index 00000000..867f066c --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/insert_message.sql @@ -0,0 +1,3 @@ +INSERT INTO backlog (time, bufferid, type, flags, senderid, message) +VALUES (:time, :bufferid, :type, :flags, (SELECT senderid FROM sender WHERE sender = :sender), :message) +RETURNING messageid diff --git a/src/core/SQL/PostgreSQL/14/insert_network.sql b/src/core/SQL/PostgreSQL/14/insert_network.sql new file mode 100644 index 00000000..4f94b434 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/insert_network.sql @@ -0,0 +1,3 @@ +INSERT INTO network (userid, networkname, identityid, servercodec, encodingcodec, decodingcodec, userandomserver, perform, useautoidentify, autoidentifyservice, autoidentifypassword, useautoreconnect, autoreconnectinterval, autoreconnectretries, unlimitedconnectretries, rejoinchannels) +VALUES (:userid, :networkname, :identityid, :servercodec, :encodingcodec, :decodingcodec, :userandomserver, :perform, :useautoidentify, :autoidentifyservice, :autoidentifypassword, :useautoreconnect, :autoreconnectinterval, :autoreconnectretries, :unlimitedconnectretries, :rejoinchannels) +RETURNING networkid diff --git a/src/core/SQL/PostgreSQL/14/insert_nick.sql b/src/core/SQL/PostgreSQL/14/insert_nick.sql new file mode 100644 index 00000000..331da3cd --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/insert_nick.sql @@ -0,0 +1,2 @@ +INSERT INTO identity_nick (identityid, nick) +VALUES (:identityid, :nick) diff --git a/src/core/SQL/PostgreSQL/14/insert_quasseluser.sql b/src/core/SQL/PostgreSQL/14/insert_quasseluser.sql new file mode 100644 index 00000000..f336d0cb --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/insert_quasseluser.sql @@ -0,0 +1,3 @@ +INSERT INTO quasseluser (username, password) +VALUES (:username, :password) +RETURNING userid diff --git a/src/core/SQL/PostgreSQL/14/insert_sender.sql b/src/core/SQL/PostgreSQL/14/insert_sender.sql new file mode 100644 index 00000000..0e84f63c --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/insert_sender.sql @@ -0,0 +1,2 @@ +INSERT INTO sender (sender) +VALUES (:sender) \ No newline at end of file diff --git a/src/core/SQL/PostgreSQL/14/insert_server.sql b/src/core/SQL/PostgreSQL/14/insert_server.sql new file mode 100644 index 00000000..d9605ebd --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/insert_server.sql @@ -0,0 +1,2 @@ +INSERT INTO ircserver (userid, networkid, hostname, port, password, ssl, sslversion, useproxy, proxytype, proxyhost, proxyport, proxyuser, proxypass) +VALUES (:userid, :networkid, :hostname, :port, :password, :ssl, :sslversion, :useproxy, :proxytype, :proxyhost, :proxyport, :proxyuser, :proxypass) diff --git a/src/core/SQL/PostgreSQL/14/insert_user_setting.sql b/src/core/SQL/PostgreSQL/14/insert_user_setting.sql new file mode 100644 index 00000000..f85d340b --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/insert_user_setting.sql @@ -0,0 +1,2 @@ +INSERT INTO user_setting (userid, settingname, settingvalue) +VALUES (:userid, :settingname, :settingvalue) diff --git a/src/core/SQL/PostgreSQL/14/select_authuser.sql b/src/core/SQL/PostgreSQL/14/select_authuser.sql new file mode 100644 index 00000000..f11bf18a --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_authuser.sql @@ -0,0 +1,3 @@ +SELECT userid +FROM quasseluser +WHERE username = :username AND password = :password diff --git a/src/core/SQL/PostgreSQL/14/select_bufferByName.sql b/src/core/SQL/PostgreSQL/14/select_bufferByName.sql new file mode 100644 index 00000000..79febdbf --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_bufferByName.sql @@ -0,0 +1,3 @@ +SELECT bufferid, buffertype, groupid +FROM buffer +WHERE networkid = :networkid AND userid = :userid AND buffercname = :buffercname diff --git a/src/core/SQL/PostgreSQL/14/select_bufferExists.sql b/src/core/SQL/PostgreSQL/14/select_bufferExists.sql new file mode 100644 index 00000000..47caae17 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_bufferExists.sql @@ -0,0 +1,3 @@ +SELECT bufferid +FROM buffer +WHERE userid = :userid AND bufferid = :bufferid diff --git a/src/core/SQL/PostgreSQL/14/select_buffer_by_id.sql b/src/core/SQL/PostgreSQL/14/select_buffer_by_id.sql new file mode 100644 index 00000000..09f202e8 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_buffer_by_id.sql @@ -0,0 +1,3 @@ +SELECT bufferid, networkid, buffertype, groupid, buffername +FROM buffer +WHERE bufferid = :bufferid diff --git a/src/core/SQL/PostgreSQL/14/select_buffer_lastseen_messages.sql b/src/core/SQL/PostgreSQL/14/select_buffer_lastseen_messages.sql new file mode 100644 index 00000000..d3a0eccb --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_buffer_lastseen_messages.sql @@ -0,0 +1,3 @@ +SELECT bufferid, lastseenmsgid +FROM buffer +WHERE userid = :userid diff --git a/src/core/SQL/PostgreSQL/14/select_buffers.sql b/src/core/SQL/PostgreSQL/14/select_buffers.sql new file mode 100644 index 00000000..2bea9c8c --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_buffers.sql @@ -0,0 +1,4 @@ +SELECT DISTINCT buffer.bufferid, network.networkid, buffertype, groupid, buffername +FROM buffer +JOIN network ON buffer.networkid = network.networkid +WHERE buffer.userid = :userid diff --git a/src/core/SQL/PostgreSQL/14/select_buffers_for_network.sql b/src/core/SQL/PostgreSQL/14/select_buffers_for_network.sql new file mode 100644 index 00000000..204a0c2c --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_buffers_for_network.sql @@ -0,0 +1,4 @@ +SELECT bufferid +FROM buffer +WHERE networkid = :networkid and userid = :userid + diff --git a/src/core/SQL/PostgreSQL/14/select_checkidentity.sql b/src/core/SQL/PostgreSQL/14/select_checkidentity.sql new file mode 100644 index 00000000..8254f03b --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_checkidentity.sql @@ -0,0 +1,3 @@ +SELECT count(*) +FROM identity +WHERE identityid = :identityid AND userid = :userid diff --git a/src/core/SQL/PostgreSQL/14/select_connected_networks.sql b/src/core/SQL/PostgreSQL/14/select_connected_networks.sql new file mode 100644 index 00000000..471f6c83 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_connected_networks.sql @@ -0,0 +1,3 @@ +SELECT networkid +FROM network +WHERE userid = :userid AND connected = true diff --git a/src/core/SQL/PostgreSQL/14/select_identities.sql b/src/core/SQL/PostgreSQL/14/select_identities.sql new file mode 100644 index 00000000..cb7a883c --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_identities.sql @@ -0,0 +1,6 @@ +SELECT identityid, identityname, realname, awaynick, awaynickenabled, + awayreason, awayreasonenabled, autoawayenabled, autoawaytime, autoawayreason, autoawayreasonenabled, + detachawayenabled, detachawayreason, detachawayreasonenabled, ident, kickreason, partreason, quitreason, + sslcert, sslkey +FROM identity +WHERE userid = :userid diff --git a/src/core/SQL/PostgreSQL/14/select_internaluser.sql b/src/core/SQL/PostgreSQL/14/select_internaluser.sql new file mode 100644 index 00000000..8486d187 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_internaluser.sql @@ -0,0 +1,2 @@ +SELECT min(userid) +FROM quasseluser diff --git a/src/core/SQL/PostgreSQL/14/select_messages.sql b/src/core/SQL/PostgreSQL/14/select_messages.sql new file mode 100644 index 00000000..641179f2 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_messages.sql @@ -0,0 +1,8 @@ +SELECT messageid, time, type, flags, sender, message +FROM backlog +JOIN sender ON backlog.senderid = sender.senderid +WHERE bufferid = :bufferid + AND backlog.messageid >= :firstmsg + AND backlog.messageid < :lastmsg +ORDER BY messageid DESC +LIMIT :limit diff --git a/src/core/SQL/PostgreSQL/14/select_messagesAll.sql b/src/core/SQL/PostgreSQL/14/select_messagesAll.sql new file mode 100644 index 00000000..52285aff --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_messagesAll.sql @@ -0,0 +1,8 @@ +SELECT messageid, bufferid, time, type, flags, sender, message +FROM backlog +JOIN sender ON backlog.senderid = sender.senderid +WHERE backlog.bufferid IN (SELECT bufferid FROM buffer WHERE userid = :userid) + AND backlog.messageid >= :firstmsg + AND backlog.messageid < :lastmsg +ORDER BY messageid DESC +LIMIT :limit diff --git a/src/core/SQL/PostgreSQL/14/select_messagesAllNew.sql b/src/core/SQL/PostgreSQL/14/select_messagesAllNew.sql new file mode 100644 index 00000000..a29f094b --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_messagesAllNew.sql @@ -0,0 +1,7 @@ +SELECT messageid, bufferid, time, type, flags, sender, message +FROM backlog +JOIN sender ON backlog.senderid = sender.senderid +WHERE backlog.bufferid IN (SELECT bufferid FROM buffer WHERE userid = :userid) + AND backlog.messageid >= :firstmsg +ORDER BY messageid DESC +LIMIT :limit diff --git a/src/core/SQL/PostgreSQL/14/select_messagesNewerThan.sql b/src/core/SQL/PostgreSQL/14/select_messagesNewerThan.sql new file mode 100644 index 00000000..69d948d6 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_messagesNewerThan.sql @@ -0,0 +1,7 @@ +SELECT messageid, time, type, flags, sender, message +FROM backlog +JOIN sender ON backlog.senderid = sender.senderid +WHERE bufferid = :bufferid + AND backlog.messageid >= :firstmsg +ORDER BY messageid DESC +LIMIT :limit diff --git a/src/core/SQL/PostgreSQL/14/select_messagesNewestK.sql b/src/core/SQL/PostgreSQL/14/select_messagesNewestK.sql new file mode 100644 index 00000000..6cc81cc5 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_messagesNewestK.sql @@ -0,0 +1,6 @@ +SELECT messageid, time, type, flags, sender, message +FROM backlog +JOIN sender ON backlog.senderid = sender.senderid +WHERE bufferid = :bufferid +ORDER BY messageid DESC +LIMIT :limit diff --git a/src/core/SQL/PostgreSQL/14/select_networkExists.sql b/src/core/SQL/PostgreSQL/14/select_networkExists.sql new file mode 100644 index 00000000..ce11c53a --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_networkExists.sql @@ -0,0 +1,3 @@ +SELECT networkname +FROM network +WHERE userid = :userid AND networkid = :networkid diff --git a/src/core/SQL/PostgreSQL/14/select_network_awaymsg.sql b/src/core/SQL/PostgreSQL/14/select_network_awaymsg.sql new file mode 100644 index 00000000..8b55cf43 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_network_awaymsg.sql @@ -0,0 +1,3 @@ +SELECT awaymessage +FROM network +WHERE userid = :userid AND networkid = :networkid diff --git a/src/core/SQL/PostgreSQL/14/select_network_usermode.sql b/src/core/SQL/PostgreSQL/14/select_network_usermode.sql new file mode 100644 index 00000000..a6d6a774 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_network_usermode.sql @@ -0,0 +1,3 @@ +SELECT usermode +FROM network +WHERE userid = :userid AND networkid = :networkid \ No newline at end of file diff --git a/src/core/SQL/PostgreSQL/14/select_networks_for_user.sql b/src/core/SQL/PostgreSQL/14/select_networks_for_user.sql new file mode 100644 index 00000000..08855c93 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_networks_for_user.sql @@ -0,0 +1,5 @@ +SELECT networkid, networkname, identityid, servercodec, encodingcodec, decodingcodec, + userandomserver, perform, useautoidentify, autoidentifyservice, autoidentifypassword, + useautoreconnect, autoreconnectinterval, autoreconnectretries, unlimitedconnectretries, rejoinchannels +FROM network +WHERE userid = :userid \ No newline at end of file diff --git a/src/core/SQL/PostgreSQL/14/select_nicks.sql b/src/core/SQL/PostgreSQL/14/select_nicks.sql new file mode 100644 index 00000000..41dc6e4d --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_nicks.sql @@ -0,0 +1,4 @@ +SELECT nick +FROM identity_nick +WHERE identityid = :identityid +ORDER BY nickid ASC diff --git a/src/core/SQL/PostgreSQL/14/select_persistent_channels.sql b/src/core/SQL/PostgreSQL/14/select_persistent_channels.sql new file mode 100644 index 00000000..8288a6a7 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_persistent_channels.sql @@ -0,0 +1,3 @@ +SELECT buffername, key +FROM buffer +WHERE userid = :userid AND networkid = :networkid AND buffertype = 2 AND joined = true diff --git a/src/core/SQL/PostgreSQL/14/select_servers_for_network.sql b/src/core/SQL/PostgreSQL/14/select_servers_for_network.sql new file mode 100644 index 00000000..d6b5cf46 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_servers_for_network.sql @@ -0,0 +1,3 @@ +SELECT hostname, port, password, ssl, sslversion, useproxy, proxytype, proxyhost, proxyport, proxyuser, proxypass +FROM ircserver +WHERE networkid = :networkid diff --git a/src/core/SQL/PostgreSQL/14/select_user_setting.sql b/src/core/SQL/PostgreSQL/14/select_user_setting.sql new file mode 100644 index 00000000..a5da306e --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_user_setting.sql @@ -0,0 +1,3 @@ +SELECT settingvalue +FROM user_setting +WHERE userid = :userid AND settingname = :settingname diff --git a/src/core/SQL/PostgreSQL/14/select_userid.sql b/src/core/SQL/PostgreSQL/14/select_userid.sql new file mode 100644 index 00000000..181c1b35 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/select_userid.sql @@ -0,0 +1,3 @@ +SELECT userid +FROM quasseluser +WHERE username = :username diff --git a/src/core/SQL/PostgreSQL/14/setup_000_quasseluser.sql b/src/core/SQL/PostgreSQL/14/setup_000_quasseluser.sql new file mode 100644 index 00000000..cd8292c4 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/setup_000_quasseluser.sql @@ -0,0 +1,5 @@ +CREATE TABLE quasseluser ( + userid serial NOT NULL PRIMARY KEY, + username varchar(64) UNIQUE NOT NULL, + password char(40) NOT NULL -- hex reppresentation of sha1 hashes +) diff --git a/src/core/SQL/PostgreSQL/14/setup_010_sender.sql b/src/core/SQL/PostgreSQL/14/setup_010_sender.sql new file mode 100644 index 00000000..0e9cdf1b --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/setup_010_sender.sql @@ -0,0 +1,4 @@ +CREATE TABLE sender ( -- THE SENDER OF IRC MESSAGES + senderid serial NOT NULL PRIMARY KEY, + sender varchar(128) UNIQUE NOT NULL +) diff --git a/src/core/SQL/PostgreSQL/14/setup_020_identity.sql b/src/core/SQL/PostgreSQL/14/setup_020_identity.sql new file mode 100644 index 00000000..35ffe725 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/setup_020_identity.sql @@ -0,0 +1,24 @@ +CREATE TABLE identity ( + identityid serial PRIMARY KEY, + userid integer NOT NULL REFERENCES quasseluser (userid) ON DELETE CASCADE, + identityname varchar(64) NOT NULL, + realname varchar(128) NOT NULL, + awaynick varchar(64), + awaynickenabled boolean NOT NULL DEFAULT FALSE, + awayreason varchar(256), + awayreasonenabled boolean NOT NULL DEFAULT FALSE, + autoawayenabled boolean NOT NULL DEFAULT FALSE, + autoawaytime integer NOT NULL, + autoawayreason varchar(256), + autoawayreasonenabled boolean NOT NULL DEFAULT FALSE, + detachawayenabled boolean NOT NULL DEFAULT FALSE, + detachawayreason varchar(256), + detachawayreasonenabled boolean NOT NULL DEFAULT FALSE, + ident varchar(64), + kickreason varchar(256), + partreason varchar(256), + quitreason varchar(256), + sslcert bytea, + sslkey bytea, + UNIQUE (userid, identityname) +) diff --git a/src/core/SQL/PostgreSQL/14/setup_030_identity_nick.sql b/src/core/SQL/PostgreSQL/14/setup_030_identity_nick.sql new file mode 100644 index 00000000..65fb5ecb --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/setup_030_identity_nick.sql @@ -0,0 +1,6 @@ +CREATE TABLE identity_nick ( + nickid serial PRIMARY KEY, + identityid integer NOT NULL REFERENCES identity (identityid) ON DELETE CASCADE, + nick varchar(64) NOT NULL, + UNIQUE (identityid, nick) +) diff --git a/src/core/SQL/PostgreSQL/14/setup_040_network.sql b/src/core/SQL/PostgreSQL/14/setup_040_network.sql new file mode 100644 index 00000000..87f48b44 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/setup_040_network.sql @@ -0,0 +1,25 @@ +CREATE TABLE network ( + networkid serial NOT NULL PRIMARY KEY, + userid integer NOT NULL REFERENCES quasseluser (userid) ON DELETE CASCADE, + networkname varchar(32) NOT NULL, + identityid integer REFERENCES identity (identityid) ON DELETE SET NULL, + encodingcodec varchar(32) NOT NULL DEFAULT 'ISO-8859-15', + decodingcodec varchar(32) NOT NULL DEFAULT 'ISO-8859-15', + servercodec varchar(32), + userandomserver boolean NOT NULL DEFAULT FALSE, + perform TEXT, + useautoidentify boolean NOT NULL DEFAULT FALSE, + autoidentifyservice varchar(128), + autoidentifypassword varchar(128), + useautoreconnect boolean NOT NULL DEFAULT TRUE, + autoreconnectinterval integer NOT NULL DEFAULT 0, + autoreconnectretries integer NOT NULL DEFAULT 0, + unlimitedconnectretries boolean NOT NULL DEFAULT FALSE, + rejoinchannels boolean NOT NULL DEFAULT FALSE, + connected boolean NOT NULL DEFAULT FALSE, + usermode varchar(32), -- user mode to restore + awaymessage varchar(256), -- away message to restore (empty if not away) + attachperform text, -- perform list for on attach + detachperform text, -- perform list for on detach + UNIQUE (userid, networkname) +) diff --git a/src/core/SQL/PostgreSQL/14/setup_050_buffer.sql b/src/core/SQL/PostgreSQL/14/setup_050_buffer.sql new file mode 100644 index 00000000..d620a761 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/setup_050_buffer.sql @@ -0,0 +1,13 @@ +create TABLE buffer ( + bufferid serial PRIMARY KEY, + userid integer NOT NULL REFERENCES quasseluser (userid) ON DELETE CASCADE, + groupid integer, + networkid integer NOT NULL REFERENCES network (networkid) ON DELETE CASCADE, + buffername varchar(128) NOT NULL, + buffercname varchar(128) NOT NULL, -- CANONICAL BUFFER NAME (lowercase version) + buffertype integer NOT NULL DEFAULT 0, + lastseenmsgid integer NOT NULL DEFAULT 0, + key varchar(128), + joined boolean NOT NULL DEFAULT FALSE, -- BOOL + UNIQUE(userid, networkid, buffercname) +) diff --git a/src/core/SQL/PostgreSQL/14/setup_060_backlog.sql b/src/core/SQL/PostgreSQL/14/setup_060_backlog.sql new file mode 100644 index 00000000..1f281b0e --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/setup_060_backlog.sql @@ -0,0 +1,9 @@ +CREATE TABLE backlog ( + messageid serial PRIMARY KEY, + time integer NOT NULL, + bufferid integer NOT NULL REFERENCES buffer (bufferid) ON DELETE CASCADE, + type integer NOT NULL, + flags integer NOT NULL, + senderid integer NOT NULL REFERENCES sender (senderid) ON DELETE SET NULL, + message TEXT +) diff --git a/src/core/SQL/PostgreSQL/14/setup_070_coreinfo.sql b/src/core/SQL/PostgreSQL/14/setup_070_coreinfo.sql new file mode 100644 index 00000000..652ec696 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/setup_070_coreinfo.sql @@ -0,0 +1,4 @@ +CREATE TABLE coreinfo ( + key TEXT NOT NULL PRIMARY KEY, + value TEXT +) diff --git a/src/core/SQL/PostgreSQL/14/setup_080_ircservers.sql b/src/core/SQL/PostgreSQL/14/setup_080_ircservers.sql new file mode 100644 index 00000000..c7784409 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/setup_080_ircservers.sql @@ -0,0 +1,16 @@ +CREATE TABLE ircserver ( + serverid serial PRIMARY KEY, + userid integer NOT NULL REFERENCES quasseluser (userid) ON DELETE CASCADE, + networkid integer NOT NULL REFERENCES network (networkid) ON DELETE CASCADE, + hostname varchar(128) NOT NULL, + port integer NOT NULL DEFAULT 6667, + password varchar(64), + ssl boolean NOT NULL DEFAULT FALSE, -- bool + sslversion integer NOT NULL DEFAULT 0, + useproxy boolean NOT NULL DEFAULT FALSE, -- bool + proxytype integer NOT NULL DEFAULT 0, + proxyhost varchar(128) NOT NULL DEFAULT 'localhost', + proxyport integer NOT NULL DEFAULT 8080, + proxyuser varchar(64), + proxypass varchar(64) +) diff --git a/src/core/SQL/PostgreSQL/14/setup_090_backlog_idx.sql b/src/core/SQL/PostgreSQL/14/setup_090_backlog_idx.sql new file mode 100644 index 00000000..25b5711d --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/setup_090_backlog_idx.sql @@ -0,0 +1 @@ +CREATE INDEX backlog_bufferid_idx ON backlog(bufferid, messageid DESC) diff --git a/src/core/SQL/PostgreSQL/14/setup_100_user_setting.sql b/src/core/SQL/PostgreSQL/14/setup_100_user_setting.sql new file mode 100644 index 00000000..bf6d85d2 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/setup_100_user_setting.sql @@ -0,0 +1,6 @@ +CREATE TABLE user_setting ( + userid integer NOT NULL REFERENCES quasseluser (userid) ON DELETE CASCADE, + settingname TEXT NOT NULL, + settingvalue bytea, + PRIMARY KEY (userid, settingname) +) diff --git a/src/core/SQL/PostgreSQL/14/update_backlog_bufferid.sql b/src/core/SQL/PostgreSQL/14/update_backlog_bufferid.sql new file mode 100644 index 00000000..b490b29f --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/update_backlog_bufferid.sql @@ -0,0 +1,3 @@ +UPDATE backlog +SET bufferid = :newbufferid +WHERE bufferid = :oldbufferid diff --git a/src/core/SQL/PostgreSQL/14/update_buffer_lastseen.sql b/src/core/SQL/PostgreSQL/14/update_buffer_lastseen.sql new file mode 100644 index 00000000..55415050 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/update_buffer_lastseen.sql @@ -0,0 +1,3 @@ +UPDATE buffer +SET lastseenmsgid = :lastseenmsgid +WHERE userid = :userid AND bufferid = :bufferid diff --git a/src/core/SQL/PostgreSQL/14/update_buffer_name.sql b/src/core/SQL/PostgreSQL/14/update_buffer_name.sql new file mode 100644 index 00000000..14d65e7a --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/update_buffer_name.sql @@ -0,0 +1,3 @@ +UPDATE buffer +SET buffername = :buffername, buffercname = :buffercname +WHERE bufferid = :bufferid diff --git a/src/core/SQL/PostgreSQL/14/update_buffer_persistent_channel.sql b/src/core/SQL/PostgreSQL/14/update_buffer_persistent_channel.sql new file mode 100644 index 00000000..e75360a0 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/update_buffer_persistent_channel.sql @@ -0,0 +1,3 @@ +UPDATE buffer +SET joined = :joined +WHERE userid = :userid AND networkid = :networkid AND buffercname = :buffercname AND buffertype = 2 diff --git a/src/core/SQL/PostgreSQL/14/update_buffer_set_channel_key.sql b/src/core/SQL/PostgreSQL/14/update_buffer_set_channel_key.sql new file mode 100644 index 00000000..803d6fd7 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/update_buffer_set_channel_key.sql @@ -0,0 +1,3 @@ +UPDATE buffer +SET key = :key +WHERE userid = :userid AND networkid = :networkid AND buffercname = :buffercname AND buffertype = 2 diff --git a/src/core/SQL/PostgreSQL/14/update_identity.sql b/src/core/SQL/PostgreSQL/14/update_identity.sql new file mode 100644 index 00000000..c25a708c --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/update_identity.sql @@ -0,0 +1,21 @@ +UPDATE identity +SET identityname = :identityname, + realname = :realname, + awaynick = :awaynick, + awaynickenabled = :awaynickenabled, + awayreason = :awayreason, + awayreasonenabled = :awayreasonenabled, + autoawayenabled = :autoawayenabled, + autoawaytime = :autoawaytime, + autoawayreason = :autoawayreason, + autoawayreasonenabled = :autoawayreasonenabled, + detachawayenabled = :detachawayenabled, + detachawayreason = :detachawayreason, + detachawayreasonenabled = :detachawayreasonenabled, + ident = :ident, + kickreason = :kickreason, + partreason = :partreason, + quitreason = :quitreason, + sslcert = :sslcert, + sslkey = :sslkey +WHERE identityid = :identityid diff --git a/src/core/SQL/PostgreSQL/14/update_network.sql b/src/core/SQL/PostgreSQL/14/update_network.sql new file mode 100644 index 00000000..8d5a4628 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/update_network.sql @@ -0,0 +1,17 @@ +UPDATE network SET +networkname = :networkname, +identityid = :identityid, +servercodec = :servercodec, +encodingcodec = :encodingcodec, +decodingcodec = :decodingcodec, +userandomserver = :userandomserver, +perform = :perform, +useautoidentify = :useautoidentify, +autoidentifyservice = :autoidentifyservice, +autoidentifypassword = :autoidentifypassword, +useautoreconnect = :useautoreconnect, +autoreconnectinterval = :autoreconnectinterval, +autoreconnectretries = :autoreconnectretries, +unlimitedconnectretries = :unlimitedconnectretries, +rejoinchannels = :rejoinchannels +WHERE networkid = :networkid diff --git a/src/core/SQL/PostgreSQL/14/update_network_connected.sql b/src/core/SQL/PostgreSQL/14/update_network_connected.sql new file mode 100644 index 00000000..0bd89de5 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/update_network_connected.sql @@ -0,0 +1,3 @@ +UPDATE network +SET connected = :connected +WHERE userid = :userid AND networkid = :networkid diff --git a/src/core/SQL/PostgreSQL/14/update_network_set_awaymsg.sql b/src/core/SQL/PostgreSQL/14/update_network_set_awaymsg.sql new file mode 100644 index 00000000..e0254da5 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/update_network_set_awaymsg.sql @@ -0,0 +1,3 @@ +UPDATE network +SET awaymessage = :awaymsg +WHERE userid = :userid AND networkid = :networkid diff --git a/src/core/SQL/PostgreSQL/14/update_network_set_usermode.sql b/src/core/SQL/PostgreSQL/14/update_network_set_usermode.sql new file mode 100644 index 00000000..b87c4c8e --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/update_network_set_usermode.sql @@ -0,0 +1,3 @@ +UPDATE network +SET usermode = :usermode +WHERE userid = :userid AND networkid = :networkid \ No newline at end of file diff --git a/src/core/SQL/PostgreSQL/14/update_user_setting.sql b/src/core/SQL/PostgreSQL/14/update_user_setting.sql new file mode 100644 index 00000000..3585fbc9 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/update_user_setting.sql @@ -0,0 +1,3 @@ +UPDATE user_setting +SET settingvalue = :settingvalue +WHERE userid = :userid AND settingname = :settingname diff --git a/src/core/SQL/PostgreSQL/14/update_username.sql b/src/core/SQL/PostgreSQL/14/update_username.sql new file mode 100644 index 00000000..951e17a7 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/update_username.sql @@ -0,0 +1,3 @@ +UPDATE quasseluser +SET username = :username +WHERE userid = :userid diff --git a/src/core/SQL/PostgreSQL/14/update_userpassword.sql b/src/core/SQL/PostgreSQL/14/update_userpassword.sql new file mode 100644 index 00000000..44a514a1 --- /dev/null +++ b/src/core/SQL/PostgreSQL/14/update_userpassword.sql @@ -0,0 +1,3 @@ +UPDATE quasseluser +SET password = :password +WHERE userid = :userid diff --git a/src/core/abstractsqlstorage.cpp b/src/core/abstractsqlstorage.cpp index 7e5dee59..fa230f31 100644 --- a/src/core/abstractsqlstorage.cpp +++ b/src/core/abstractsqlstorage.cpp @@ -72,6 +72,9 @@ void AbstractSqlStorage::addConnectionToPool() { if(!hostName().isEmpty()) db.setHostName(hostName()); + if(port() != -1) + db.setPort(port()); + if(!userName().isEmpty()) { db.setUserName(userName()); db.setPassword(password()); @@ -84,7 +87,7 @@ void AbstractSqlStorage::addConnectionToPool() { } Storage::State AbstractSqlStorage::init(const QVariantMap &settings) { - Q_UNUSED(settings) + setConnectionProperties(settings); QSqlDatabase db = logDb(); if(!db.isValid() || !db.isOpen()) @@ -108,7 +111,7 @@ Storage::State AbstractSqlStorage::init(const QVariantMap &settings) { } } - quInfo() << "Storage Backend is ready. Quassel Schema Version:" << installedSchemaVersion(); + quInfo() << qPrintable(displayName()) << "Storage Backend is ready. Quassel Schema Version:" << installedSchemaVersion(); return IsReady; } @@ -141,21 +144,28 @@ QStringList AbstractSqlStorage::setupQueries() { } bool AbstractSqlStorage::setup(const QVariantMap &settings) { - Q_UNUSED(settings) + setConnectionProperties(settings); QSqlDatabase db = logDb(); if(!db.isOpen()) { qCritical() << "Unable to setup Logging Backend!"; return false; } + db.transaction(); foreach(QString queryString, setupQueries()) { QSqlQuery query = db.exec(queryString); if(!watchQuery(query)) { qCritical() << "Unable to setup Logging Backend!"; + db.rollback(); return false; } } - return setupSchemaVersion(schemaVersion()); + bool success = setupSchemaVersion(schemaVersion()); + if(success) + db.commit(); + else + db.rollback(); + return success; } QStringList AbstractSqlStorage::upgradeQueries(int version) { diff --git a/src/core/abstractsqlstorage.h b/src/core/abstractsqlstorage.h index e3b4ec4c..e087c6df 100644 --- a/src/core/abstractsqlstorage.h +++ b/src/core/abstractsqlstorage.h @@ -56,8 +56,10 @@ protected: virtual bool updateSchemaVersion(int newVersion) = 0; virtual bool setupSchemaVersion(int version) = 0; + virtual void setConnectionProperties(const QVariantMap &properties) = 0; virtual QString driverName() = 0; inline virtual QString hostName() { return QString(); } + inline virtual int port() { return -1; } virtual QString databaseName() = 0; inline virtual QString userName() { return QString(); } inline virtual QString password() { return QString(); } diff --git a/src/core/core.cpp b/src/core/core.cpp index e1a53600..c7827934 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -23,6 +23,7 @@ #include "core.h" #include "coresession.h" #include "coresettings.h" +#include "postgresqlstorage.h" #include "quassel.h" #include "signalproxy.h" #include "sqlitestorage.h" @@ -132,6 +133,7 @@ Core::Core() // Register storage backends here! registerStorageBackend(new SqliteStorage(this)); + registerStorageBackend(new PostgreSqlStorage(this)); connect(&_storageSyncTimer, SIGNAL(timeout()), this, SLOT(syncStorage())); _storageSyncTimer.start(10 * 60 * 1000); // 10 minutes @@ -273,12 +275,14 @@ bool Core::initStorage(QVariantMap dbSettings, bool setup) { return false; } - Storage::State storageState = storage->init(dbSettings); + QVariantMap connectionProperties = dbSettings["ConnectionProperties"].toMap(); + + Storage::State storageState = storage->init(connectionProperties); switch(storageState) { case Storage::NeedsSetup: if(!setup) return false; // trigger setup process - if(storage->setup(dbSettings)) + if(storage->setup(connectionProperties)) return initStorage(dbSettings, false); // if setup wasn't successfull we mark the backend as unavailable case Storage::NotAvailable: @@ -501,6 +505,8 @@ void Core::processClientMessage(QTcpSocket *socket, const QVariantMap &msg) { QVariantMap v; v["DisplayName"] = backend->displayName(); v["Description"] = backend->description(); + v["ConnectionProperties"] = backend->setupKeys(); + qDebug() << backend->setupKeys(); backends.append(v); } reply["StorageBackends"] = backends; diff --git a/src/core/core.h b/src/core/core.h index 2c1fa07d..6d743e89 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -134,17 +134,6 @@ class Core : public QObject { return instance()->_storage->networks(user); } - //! Get the NetworkId for a network name. - /** \note This method is threadsafe. - * - * \param user The core user - * \param network The name of the network - * \return The NetworkId corresponding to the given network. - */ - static inline NetworkId networkId(UserId user, const QString &network) { - return instance()->_storage->getNetworkId(user, network); - } - //! Get a list of Networks to restore /** Return a list of networks the user was connected at the time of core shutdown * \note This method is threadsafe. diff --git a/src/core/coreapplication.cpp b/src/core/coreapplication.cpp index f0c84f32..3056b8a7 100644 --- a/src/core/coreapplication.cpp +++ b/src/core/coreapplication.cpp @@ -73,7 +73,7 @@ CoreApplication::~CoreApplication() { bool CoreApplication::init() { if(Quassel::init() && _internal->init()) { - qInstallMsgHandler(Logger::logMessage); + // qInstallMsgHandler(Logger::logMessage); return true; } return false; diff --git a/src/core/corenetwork.cpp b/src/core/corenetwork.cpp index a3570441..ece012eb 100644 --- a/src/core/corenetwork.cpp +++ b/src/core/corenetwork.cpp @@ -333,7 +333,14 @@ void CoreNetwork::socketInitialized() { if(!server.password.isEmpty()) { putRawLine(serverEncode(QString("PASS %1").arg(server.password))); } - putRawLine(serverEncode(QString("NICK :%1").arg(identity->nicks()[0]))); + QString nick; + if(identity->nicks().isEmpty()) { + nick = "quassel"; + qWarning() << "CoreNetwork::socketInitialized(): no nicks supplied for identity Id" << identity->id(); + } else { + nick = identity->nicks()[0]; + } + putRawLine(serverEncode(QString("NICK :%1").arg(nick))); putRawLine(serverEncode(QString("USER %1 8 * :%2").arg(identity->ident(), identity->realName()))); } diff --git a/src/core/coresession.cpp b/src/core/coresession.cpp index b5ae06c8..7a4f6222 100644 --- a/src/core/coresession.cpp +++ b/src/core/coresession.cpp @@ -272,6 +272,7 @@ void CoreSession::createIdentity(const Identity &identity, const QVariantMap &ad if(additional.contains("CertPem")) coreIdentity.setSslCert(additional["CertPem"].toByteArray()); #endif + qDebug() << Q_FUNC_INFO; IdentityId id = Core::createIdentity(user(), coreIdentity); if(!id.isValid()) return; diff --git a/src/core/postgresqlstorage.cpp b/src/core/postgresqlstorage.cpp new file mode 100644 index 00000000..56be64ef --- /dev/null +++ b/src/core/postgresqlstorage.cpp @@ -0,0 +1,1235 @@ +/*************************************************************************** + * Copyright (C) 2005-07 by the Quassel Project * + * devel@quassel-irc.org * + * * + * 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) version 3. * + * * + * 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., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "postgresqlstorage.h" + +#include + +#include "logger.h" +#include "network.h" +#include "quassel.h" + +int PostgreSqlStorage::_maxRetryCount = 150; // yes this is a large number... only other way to "handle" this is bailing out... + +PostgreSqlStorage::PostgreSqlStorage(QObject *parent) + : AbstractSqlStorage(parent), + _port(-1) +{ +} + +PostgreSqlStorage::~PostgreSqlStorage() { +} + +bool PostgreSqlStorage::isAvailable() const { + if(!QSqlDatabase::isDriverAvailable("QPSQL")) return false; + return true; +} + +QString PostgreSqlStorage::displayName() const { + return QString("PostgreSQL"); +} + +QString PostgreSqlStorage::description() const { + // FIXME: proper description + return tr("PostgreSQL Turbo Bomber HD!"); +} + +QVariantMap PostgreSqlStorage::setupKeys() const { + QVariantMap map; + map["Username"] = QVariant(QString("quassel")); + map["Password"] = QVariant(QString()); + map["Hostname"] = QVariant(QString("localhost")); + map["Port"] = QVariant(5432); + map["Database"] = QVariant(QString("quassel")); + return map; +} + +void PostgreSqlStorage::setConnectionProperties(const QVariantMap &properties) { + _userName = properties["Username"].toString(); + _password = properties["Password"].toString(); + _hostName = properties["Hostname"].toString(); + _port = properties["Port"].toInt(); + _databaseName = properties["Database"].toString(); +} + +int PostgreSqlStorage::installedSchemaVersion() { + QSqlQuery query = logDb().exec("SELECT value FROM coreinfo WHERE key = 'schemaversion'"); + if(query.first()) + return query.value(0).toInt(); + + // maybe it's really old... (schema version 0) + query = logDb().exec("SELECT MAX(version) FROM coreinfo"); + if(query.first()) + return query.value(0).toInt(); + + return AbstractSqlStorage::installedSchemaVersion(); +} + +bool PostgreSqlStorage::updateSchemaVersion(int newVersion) { + QSqlQuery query(logDb()); + query.prepare("UPDATE coreinfo SET value = :version WHERE key = 'schemaversion'"); + query.bindValue(":version", newVersion); + query.exec(); + + bool success = true; + if(query.lastError().isValid()) { + qCritical() << "PostgreSqlStorage::updateSchemaVersion(int): Updating schema version failed!"; + success = false; + } + return success; +} + +bool PostgreSqlStorage::setupSchemaVersion(int version) { + QSqlQuery query(logDb()); + query.prepare("INSERT INTO coreinfo (key, value) VALUES ('schemaversion', :version)"); + query.bindValue(":version", version); + query.exec(); + + bool success = true; + if(query.lastError().isValid()) { + qCritical() << "PostgreSqlStorage::setupSchemaVersion(int): Updating schema version failed!"; + success = false; + } + return success; +} + +UserId PostgreSqlStorage::addUser(const QString &user, const QString &password) { + QSqlQuery query(logDb()); + query.prepare(queryString("insert_quasseluser")); + query.bindValue(":username", user); + query.bindValue(":password", cryptedPassword(password)); + safeExec(query); + if(!watchQuery(query)) + return 0; + + query.first(); + UserId uid = query.value(0).toInt(); + emit userAdded(uid, user); + return uid; +} + +void PostgreSqlStorage::updateUser(UserId user, const QString &password) { + QSqlQuery query(logDb()); + query.prepare(queryString("update_userpassword")); + query.bindValue(":userid", user.toInt()); + query.bindValue(":password", cryptedPassword(password)); + safeExec(query); +} + +void PostgreSqlStorage::renameUser(UserId user, const QString &newName) { + QSqlQuery query(logDb()); + query.prepare(queryString("update_username")); + query.bindValue(":userid", user.toInt()); + query.bindValue(":username", newName); + safeExec(query); + emit userRenamed(user, newName); +} + +UserId PostgreSqlStorage::validateUser(const QString &user, const QString &password) { + QSqlQuery query(logDb()); + query.prepare(queryString("select_authuser")); + query.bindValue(":username", user); + query.bindValue(":password", cryptedPassword(password)); + safeExec(query); + + if(query.first()) { + return query.value(0).toInt(); + } else { + return 0; + } +} + +UserId PostgreSqlStorage::internalUser() { + QSqlQuery query(logDb()); + query.prepare(queryString("select_internaluser")); + safeExec(query); + + if(query.first()) { + return query.value(0).toInt(); + } else { + return 0; + } +} + +void PostgreSqlStorage::delUser(UserId user) { + QSqlDatabase db = logDb(); + if(!db.transaction()) { + qWarning() << "PostgreSqlStorage::delUser(): cannot start transaction!"; + return; + } + + QSqlQuery query(db); + query.prepare(queryString("delete_quasseluser")); + query.bindValue(":userid", user.toInt()); + safeExec(query); + if(!watchQuery(query)) { + db.rollback(); + return; + } else { + db.commit(); + emit userRemoved(user); + } +} + +void PostgreSqlStorage::setUserSetting(UserId userId, const QString &settingName, const QVariant &data) { + QByteArray rawData; + QDataStream out(&rawData, QIODevice::WriteOnly); + out.setVersion(QDataStream::Qt_4_2); + out << data; + + QSqlDatabase db = logDb(); + QSqlQuery query(db); + query.prepare(queryString("insert_user_setting")); + query.bindValue(":userid", userId.toInt()); + query.bindValue(":settingname", settingName); + query.bindValue(":settingvalue", rawData); + safeExec(query); + + if(query.lastError().isValid()) { + QSqlQuery updateQuery(db); + updateQuery.prepare(queryString("update_user_setting")); + updateQuery.bindValue(":userid", userId.toInt()); + updateQuery.bindValue(":settingname", settingName); + updateQuery.bindValue(":settingvalue", rawData); + safeExec(updateQuery); + } + +} + +QVariant PostgreSqlStorage::getUserSetting(UserId userId, const QString &settingName, const QVariant &defaultData) { + QSqlQuery query(logDb()); + query.prepare(queryString("select_user_setting")); + query.bindValue(":userid", userId.toInt()); + query.bindValue(":settingname", settingName); + safeExec(query); + + if(query.first()) { + QVariant data; + QByteArray rawData = query.value(0).toByteArray(); + QDataStream in(&rawData, QIODevice::ReadOnly); + in.setVersion(QDataStream::Qt_4_2); + in >> data; + return data; + } else { + return defaultData; + } +} + +IdentityId PostgreSqlStorage::createIdentity(UserId user, CoreIdentity &identity) { + IdentityId identityId; + + QSqlDatabase db = logDb(); + if(!db.transaction()) { + qWarning() << "PostgreSqlStorage::createIdentity(): Unable to start Transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return identityId; + } + + QSqlQuery query(db); + query.prepare(queryString("insert_identity")); + query.bindValue(":userid", user.toInt()); + query.bindValue(":identityname", identity.identityName()); + query.bindValue(":realname", identity.realName()); + query.bindValue(":awaynick", identity.awayNick()); + query.bindValue(":awaynickenabled", identity.awayNickEnabled()); + query.bindValue(":awayreason", identity.awayReason()); + query.bindValue(":awayreasonenabled", identity.awayReasonEnabled()); + query.bindValue(":autoawayenabled", identity.awayReasonEnabled()); + query.bindValue(":autoawaytime", identity.autoAwayTime()); + query.bindValue(":autoawayreason", identity.autoAwayReason()); + query.bindValue(":autoawayreasonenabled", identity.autoAwayReasonEnabled()); + query.bindValue(":detachawayenabled", identity.detachAwayEnabled()); + query.bindValue(":detachawayreason", identity.detachAwayReason()); + query.bindValue(":detachawayreasonenabled", identity.detachAwayReasonEnabled()); + query.bindValue(":ident", identity.ident()); + query.bindValue(":kickreason", identity.kickReason()); + query.bindValue(":partreason", identity.partReason()); + query.bindValue(":quitreason", identity.quitReason()); +#ifdef HAVE_SSL + query.bindValue(":sslcert", identity.sslCert().toPem()); + query.bindValue(":sslkey", identity.sslKey().toPem()); +#else + query.bindValue(":sslcert", QByteArray()); + query.bindValue(":sslkey", QByteArray()); +#endif + safeExec(query); + if(query.lastError().isValid()) { + watchQuery(query); + db.rollback(); + return IdentityId(); + } + + qDebug() << "creatId" << query.first() << query.value(0).toInt(); + identityId = query.value(0).toInt(); + identity.setId(identityId); + + if(!identityId.isValid()) { + watchQuery(query); + db.rollback(); + return IdentityId(); + } + + QSqlQuery insertNickQuery(db); + insertNickQuery.prepare(queryString("insert_nick")); + foreach(QString nick, identity.nicks()) { + insertNickQuery.bindValue(":identityid", identityId.toInt()); + insertNickQuery.bindValue(":nick", nick); + safeExec(insertNickQuery); + if(!watchQuery(insertNickQuery)) { + db.rollback(); + return IdentityId(); + } + } + + if(!db.commit()) { + qWarning() << "PostgreSqlStorage::createIdentity(): commiting data failed!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return IdentityId(); + } + return identityId; +} + +bool PostgreSqlStorage::updateIdentity(UserId user, const CoreIdentity &identity) { + QSqlDatabase db = logDb(); + if(!db.transaction()) { + qWarning() << "PostgreSqlStorage::updateIdentity(): Unable to start Transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return false; + } + + QSqlQuery checkQuery(db); + checkQuery.prepare(queryString("select_checkidentity")); + checkQuery.bindValue(":identityid", identity.id().toInt()); + checkQuery.bindValue(":userid", user.toInt()); + safeExec(checkQuery); + + // there should be exactly one identity for the given id and user + if(!checkQuery.first() || checkQuery.value(0).toInt() != 1) { + db.rollback(); + return false; + } + + QSqlQuery query(db); + query.prepare(queryString("update_identity")); + query.bindValue(":identityname", identity.identityName()); + query.bindValue(":realname", identity.realName()); + query.bindValue(":awaynick", identity.awayNick()); + query.bindValue(":awaynickenabled", identity.awayNickEnabled()); + query.bindValue(":awayreason", identity.awayReason()); + query.bindValue(":awayreasonenabled", identity.awayReasonEnabled()); + query.bindValue(":autoawayenabled", identity.awayReasonEnabled()); + query.bindValue(":autoawaytime", identity.autoAwayTime()); + query.bindValue(":autoawayreason", identity.autoAwayReason()); + query.bindValue(":autoawayreasonenabled", identity.autoAwayReasonEnabled()); + query.bindValue(":detachawayenabled", identity.detachAwayEnabled()); + query.bindValue(":detachawayreason", identity.detachAwayReason()); + query.bindValue(":detachawayreasonenabled", identity.detachAwayReasonEnabled()); + query.bindValue(":ident", identity.ident()); + query.bindValue(":kickreason", identity.kickReason()); + query.bindValue(":partreason", identity.partReason()); + query.bindValue(":quitreason", identity.quitReason()); +#ifdef HAVE_SSL + query.bindValue(":sslcert", identity.sslCert().toPem()); + query.bindValue(":sslkey", identity.sslKey().toPem()); +#else + query.bindValue(":sslcert", QByteArray()); + query.bindValue(":sslkey", QByteArray()); +#endif + query.bindValue(":identityid", identity.id().toInt()); + + safeExec(query); + if(!watchQuery(query)) { + db.rollback(); + return false; + } + + QSqlQuery deleteNickQuery(db); + deleteNickQuery.prepare(queryString("delete_nicks")); + deleteNickQuery.bindValue(":identityid", identity.id().toInt()); + safeExec(deleteNickQuery); + if(!watchQuery(deleteNickQuery)) { + db.rollback(); + return false; + } + + QSqlQuery insertNickQuery(db); + insertNickQuery.prepare(queryString("insert_nick")); + foreach(QString nick, identity.nicks()) { + insertNickQuery.bindValue(":identityid", identity.id().toInt()); + insertNickQuery.bindValue(":nick", nick); + safeExec(insertNickQuery); + if(!watchQuery(insertNickQuery)) { + db.rollback(); + return false; + } + } + + if(!db.commit()) { + qWarning() << "PostgreSqlStorage::updateIdentity(): commiting data failed!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return false; + } + return true; +} + +void PostgreSqlStorage::removeIdentity(UserId user, IdentityId identityId) { + QSqlDatabase db = logDb(); + if(!db.transaction()) { + qWarning() << "PostgreSqlStorage::removeIdentity(): Unable to start Transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return; + } + + QSqlQuery query(db); + query.prepare(queryString("delete_identity")); + query.bindValue(":identityid", identityId.toInt()); + query.bindValue(":userid", user.toInt()); + safeExec(query); + if(!watchQuery(query)) { + db.rollback(); + } else { + db.commit(); + } +} + +QList PostgreSqlStorage::identities(UserId user) { + QList identities; + + QSqlDatabase db = logDb(); + if(!beginReadOnlyTransaction(db)) { + qWarning() << "PostgreSqlStorage::identites(): cannot start read only transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return identities; + } + + QSqlQuery query(db); + query.prepare(queryString("select_identities")); + query.bindValue(":userid", user.toInt()); + + QSqlQuery nickQuery(db); + nickQuery.prepare(queryString("select_nicks")); + + safeExec(query); + + while(query.next()) { + CoreIdentity identity(IdentityId(query.value(0).toInt())); + + identity.setIdentityName(query.value(1).toString()); + identity.setRealName(query.value(2).toString()); + identity.setAwayNick(query.value(3).toString()); + identity.setAwayNickEnabled(!!query.value(4).toInt()); + identity.setAwayReason(query.value(5).toString()); + identity.setAwayReasonEnabled(!!query.value(6).toInt()); + identity.setAutoAwayEnabled(!!query.value(7).toInt()); + identity.setAutoAwayTime(query.value(8).toInt()); + identity.setAutoAwayReason(query.value(9).toString()); + identity.setAutoAwayReasonEnabled(!!query.value(10).toInt()); + identity.setDetachAwayEnabled(!!query.value(11).toInt()); + identity.setDetachAwayReason(query.value(12).toString()); + identity.setDetachAwayReasonEnabled(!!query.value(13).toInt()); + identity.setIdent(query.value(14).toString()); + identity.setKickReason(query.value(15).toString()); + identity.setPartReason(query.value(16).toString()); + identity.setQuitReason(query.value(17).toString()); +#ifdef HAVE_SSL + identity.setSslCert(query.value(18).toByteArray()); + identity.setSslKey(query.value(19).toByteArray()); +#endif + + nickQuery.bindValue(":identityid", identity.id().toInt()); + QList nicks; + safeExec(nickQuery); + watchQuery(nickQuery); + while(nickQuery.next()) { + nicks << nickQuery.value(0).toString(); + } + identity.setNicks(nicks); + identities << identity; + } + db.commit(); + return identities; +} + +NetworkId PostgreSqlStorage::createNetwork(UserId user, const NetworkInfo &info) { + NetworkId networkId; + + QSqlDatabase db = logDb(); + if(!db.transaction()) { + qWarning() << "PostgreSqlStorage::createNetwork(): failed to begin transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return false; + } + + QSqlQuery query(db); + query.prepare(queryString("insert_network")); + query.bindValue(":userid", user.toInt()); + bindNetworkInfo(query, info); + safeExec(query); + if(query.lastError().isValid()) { + watchQuery(query); + db.rollback(); + return NetworkId(); + } + + qDebug() << "createNet:" << query.first() << query.value(0).toInt(); + networkId = query.value(0).toInt(); + + if(!networkId.isValid()) { + watchQuery(query); + db.rollback(); + return NetworkId(); + } + + QSqlQuery insertServersQuery(db); + insertServersQuery.prepare(queryString("insert_server")); + foreach(Network::Server server, info.serverList) { + insertServersQuery.bindValue(":userid", user.toInt()); + insertServersQuery.bindValue(":networkid", networkId.toInt()); + bindServerInfo(insertServersQuery, server); + safeExec(insertServersQuery); + if(!watchQuery(insertServersQuery)) { + db.rollback(); + return NetworkId(); + } + } + + if(!db.commit()) { + qWarning() << "PostgreSqlStorage::updateNetwork(): commiting data failed!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return NetworkId(); + } + return networkId; +} + +void PostgreSqlStorage::bindNetworkInfo(QSqlQuery &query, const NetworkInfo &info) { + query.bindValue(":networkname", info.networkName); + query.bindValue(":identityid", info.identity.toInt()); + query.bindValue(":encodingcodec", QString(info.codecForEncoding)); + query.bindValue(":decodingcodec", QString(info.codecForDecoding)); + query.bindValue(":servercodec", QString(info.codecForServer)); + query.bindValue(":userandomserver", info.useRandomServer); + query.bindValue(":perform", info.perform.join("\n")); + query.bindValue(":useautoidentify", info.useAutoIdentify); + query.bindValue(":autoidentifyservice", info.autoIdentifyService); + query.bindValue(":autoidentifypassword", info.autoIdentifyPassword); + query.bindValue(":useautoreconnect", info.useAutoReconnect); + query.bindValue(":autoreconnectinterval", info.autoReconnectInterval); + query.bindValue(":autoreconnectretries", info.autoReconnectRetries); + query.bindValue(":unlimitedconnectretries", info.unlimitedReconnectRetries); + query.bindValue(":rejoinchannels", info.rejoinChannels); + if(info.networkId.isValid()) + query.bindValue(":networkid", info.networkId.toInt()); +} + +void PostgreSqlStorage::bindServerInfo(QSqlQuery &query, const Network::Server &server) { + query.bindValue(":hostname", server.host); + query.bindValue(":port", server.port); + query.bindValue(":password", server.password); + query.bindValue(":ssl", server.useSsl); + query.bindValue(":sslversion", server.sslVersion); + query.bindValue(":useproxy", server.useProxy); + query.bindValue(":proxytype", server.proxyType); + query.bindValue(":proxyhost", server.proxyHost); + query.bindValue(":proxyport", server.proxyPort); + query.bindValue(":proxyuser", server.proxyUser); + query.bindValue(":proxypass", server.proxyPass); +} + +bool PostgreSqlStorage::updateNetwork(UserId user, const NetworkInfo &info) { + if(!isValidNetwork(user, info.networkId)) + return false; + + QSqlDatabase db = logDb(); + if(!db.transaction()) { + qWarning() << "PostgreSqlStorage::updateNetwork(): failed to begin transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return false; + } + + QSqlQuery updateQuery(db); + updateQuery.prepare(queryString("update_network")); + bindNetworkInfo(updateQuery, info); + safeExec(updateQuery); + if(!watchQuery(updateQuery)) { + db.rollback(); + return false; + } + + QSqlQuery dropServersQuery(db); + dropServersQuery.prepare("DELETE FROM ircserver WHERE networkid = :networkid"); + dropServersQuery.bindValue(":networkid", info.networkId.toInt()); + safeExec(dropServersQuery); + if(!watchQuery(dropServersQuery)) { + db.rollback(); + return false; + } + + QSqlQuery insertServersQuery(db); + insertServersQuery.prepare(queryString("insert_server")); + foreach(Network::Server server, info.serverList) { + insertServersQuery.bindValue(":userid", user.toInt()); + insertServersQuery.bindValue(":networkid", info.networkId.toInt()); + bindServerInfo(insertServersQuery, server); + safeExec(insertServersQuery); + if(!watchQuery(insertServersQuery)) { + db.rollback(); + return false; + } + } + + if(!db.commit()) { + qWarning() << "PostgreSqlStorage::updateNetwork(): commiting data failed!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return false; + } + return true; +} + +bool PostgreSqlStorage::removeNetwork(UserId user, const NetworkId &networkId) { + if(!isValidNetwork(user, networkId)) + return false; + + QSqlDatabase db = logDb(); + if(!db.transaction()) { + qWarning() << "PostgreSqlStorage::removeNetwork(): cannot start transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return false; + } + + QSqlQuery query(db); + query.prepare(queryString("delete_network")); + query.bindValue(":networkid", networkId.toInt()); + safeExec(query); + if(!watchQuery(query)) { + db.rollback(); + return false; + } + + db.commit(); + return true; +} + +QList PostgreSqlStorage::networks(UserId user) { + QList nets; + + QSqlDatabase db = logDb(); + if(!beginReadOnlyTransaction(db)) { + qWarning() << "PostgreSqlStorage::networks(): cannot start read only transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return nets; + } + + QSqlQuery networksQuery(db); + networksQuery.prepare(queryString("select_networks_for_user")); + networksQuery.bindValue(":userid", user.toInt()); + + QSqlQuery serversQuery(db); + serversQuery.prepare(queryString("select_servers_for_network")); + + safeExec(networksQuery); + if(!watchQuery(networksQuery)) { + db.rollback(); + return nets; + } + + while(networksQuery.next()) { + NetworkInfo net; + net.networkId = networksQuery.value(0).toInt(); + net.networkName = networksQuery.value(1).toString(); + net.identity = networksQuery.value(2).toInt(); + net.codecForServer = networksQuery.value(3).toString().toAscii(); + net.codecForEncoding = networksQuery.value(4).toString().toAscii(); + net.codecForDecoding = networksQuery.value(5).toString().toAscii(); + net.useRandomServer = networksQuery.value(6).toBool(); + net.perform = networksQuery.value(7).toString().split("\n"); + net.useAutoIdentify = networksQuery.value(8).toBool(); + net.autoIdentifyService = networksQuery.value(9).toString(); + net.autoIdentifyPassword = networksQuery.value(10).toString(); + net.useAutoReconnect = networksQuery.value(11).toBool(); + net.autoReconnectInterval = networksQuery.value(12).toUInt(); + net.autoReconnectRetries = networksQuery.value(13).toInt(); + net.unlimitedReconnectRetries = networksQuery.value(14).toBool(); + net.rejoinChannels = networksQuery.value(15).toBool(); + + serversQuery.bindValue(":networkid", net.networkId.toInt()); + safeExec(serversQuery); + if(!watchQuery(serversQuery)) { + db.rollback(); + return nets; + } + + Network::ServerList servers; + while(serversQuery.next()) { + Network::Server server; + server.host = serversQuery.value(0).toString(); + server.port = serversQuery.value(1).toUInt(); + server.password = serversQuery.value(2).toString(); + server.useSsl = serversQuery.value(3).toBool(); + server.sslVersion = serversQuery.value(4).toInt(); + server.useProxy = serversQuery.value(5).toBool(); + server.proxyType = serversQuery.value(6).toInt(); + server.proxyHost = serversQuery.value(7).toString(); + server.proxyPort = serversQuery.value(8).toUInt(); + server.proxyUser = serversQuery.value(9).toString(); + server.proxyPass = serversQuery.value(10).toString(); + servers << server; + } + net.serverList = servers; + nets << net; + } + db.commit(); + return nets; +} + +bool PostgreSqlStorage::isValidNetwork(UserId user, const NetworkId &networkId) { + QSqlQuery query(logDb()); + query.prepare(queryString("select_networkExists")); + query.bindValue(":userid", user.toInt()); + query.bindValue(":networkid", networkId.toInt()); + safeExec(query); + + watchQuery(query); + if(!query.first()) + return false; + + Q_ASSERT(!query.next()); + return true; +} + +bool PostgreSqlStorage::isValidBuffer(const UserId &user, const BufferId &bufferId) { + QSqlQuery query(logDb()); + query.prepare(queryString("select_bufferExists")); + query.bindValue(":userid", user.toInt()); + query.bindValue(":bufferid", bufferId.toInt()); + safeExec(query); + + watchQuery(query); + if(!query.first()) + return false; + + Q_ASSERT(!query.next()); + return true; +} + +QList PostgreSqlStorage::connectedNetworks(UserId user) { + QList connectedNets; + + QSqlDatabase db = logDb(); + if(!beginReadOnlyTransaction(db)) { + qWarning() << "PostgreSqlStorage::connectedNetworks(): cannot start read only transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return connectedNets; + } + + QSqlQuery query(db); + query.prepare(queryString("select_connected_networks")); + query.bindValue(":userid", user.toInt()); + safeExec(query); + watchQuery(query); + + while(query.next()) { + connectedNets << query.value(0).toInt(); + } + + db.commit(); + return connectedNets; +} + +void PostgreSqlStorage::setNetworkConnected(UserId user, const NetworkId &networkId, bool isConnected) { + QSqlQuery query(logDb()); + query.prepare(queryString("update_network_connected")); + query.bindValue(":userid", user.toInt()); + query.bindValue(":networkid", networkId.toInt()); + query.bindValue(":connected", isConnected); + safeExec(query); + watchQuery(query); +} + +QHash PostgreSqlStorage::persistentChannels(UserId user, const NetworkId &networkId) { + QHash persistentChans; + + QSqlDatabase db = logDb(); + if(!beginReadOnlyTransaction(db)) { + qWarning() << "PostgreSqlStorage::persistentChannels(): cannot start read only transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return persistentChans; + } + + QSqlQuery query(db); + query.prepare(queryString("select_persistent_channels")); + query.bindValue(":userid", user.toInt()); + query.bindValue(":networkid", networkId.toInt()); + safeExec(query); + watchQuery(query); + + while(query.next()) { + persistentChans[query.value(0).toString()] = query.value(1).toString(); + } + + db.commit(); + return persistentChans; +} + +void PostgreSqlStorage::setChannelPersistent(UserId user, const NetworkId &networkId, const QString &channel, bool isJoined) { + QSqlQuery query(logDb()); + query.prepare(queryString("update_buffer_persistent_channel")); + query.bindValue(":userid", user.toInt()); + query.bindValue(":networkId", networkId.toInt()); + query.bindValue(":buffercname", channel.toLower()); + query.bindValue(":joined", isJoined); + safeExec(query); + watchQuery(query); +} + +void PostgreSqlStorage::setPersistentChannelKey(UserId user, const NetworkId &networkId, const QString &channel, const QString &key) { + QSqlQuery query(logDb()); + query.prepare(queryString("update_buffer_set_channel_key")); + query.bindValue(":userid", user.toInt()); + query.bindValue(":networkId", networkId.toInt()); + query.bindValue(":buffercname", channel.toLower()); + query.bindValue(":key", key); + safeExec(query); + watchQuery(query); +} + +QString PostgreSqlStorage::awayMessage(UserId user, NetworkId networkId) { + QSqlQuery query(logDb()); + query.prepare(queryString("select_network_awaymsg")); + query.bindValue(":userid", user.toInt()); + query.bindValue(":networkid", networkId.toInt()); + safeExec(query); + watchQuery(query); + QString awayMsg; + if(query.first()) + awayMsg = query.value(0).toString(); + return awayMsg; +} + +void PostgreSqlStorage::setAwayMessage(UserId user, NetworkId networkId, const QString &awayMsg) { + QSqlQuery query(logDb()); + query.prepare(queryString("update_network_set_awaymsg")); + query.bindValue(":userid", user.toInt()); + query.bindValue(":networkid", networkId.toInt()); + query.bindValue(":awaymsg", awayMsg); + safeExec(query); + watchQuery(query); +} + +QString PostgreSqlStorage::userModes(UserId user, NetworkId networkId) { + QSqlQuery query(logDb()); + query.prepare(queryString("select_network_usermode")); + query.bindValue(":userid", user.toInt()); + query.bindValue(":networkid", networkId.toInt()); + safeExec(query); + watchQuery(query); + QString modes; + if(query.first()) + modes = query.value(0).toString(); + return modes; +} + +void PostgreSqlStorage::setUserModes(UserId user, NetworkId networkId, const QString &userModes) { + QSqlQuery query(logDb()); + query.prepare(queryString("update_network_set_usermode")); + query.bindValue(":userid", user.toInt()); + query.bindValue(":networkid", networkId.toInt()); + query.bindValue(":usermode", userModes); + safeExec(query); + watchQuery(query); +} + +BufferInfo PostgreSqlStorage::bufferInfo(UserId user, const NetworkId &networkId, BufferInfo::Type type, const QString &buffer, bool create) { + QSqlDatabase db = logDb(); + if(!db.transaction()) { + qWarning() << "PostgreSqlStorage::bufferInfo(): cannot start read only transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return BufferInfo(); + } + + QSqlQuery query(db); + query.prepare(queryString("select_bufferByName")); + query.bindValue(":networkid", networkId.toInt()); + query.bindValue(":userid", user.toInt()); + query.bindValue(":buffercname", buffer.toLower()); + safeExec(query); + + if(query.first()) { + BufferInfo bufferInfo = BufferInfo(query.value(0).toInt(), networkId, (BufferInfo::Type)query.value(1).toInt(), 0, buffer); + if(query.next()) { + qCritical() << "PostgreSqlStorage::getBufferInfo(): received more then one Buffer!"; + qCritical() << " Query:" << query.lastQuery(); + qCritical() << " bound Values:"; + QList list = query.boundValues().values(); + for (int i = 0; i < list.size(); ++i) + qCritical() << i << ":" << list.at(i).toString().toAscii().data(); + Q_ASSERT(false); + } + db.commit(); + return bufferInfo; + } + + if(!create) { + db.rollback(); + return BufferInfo(); + } + + QSqlQuery createQuery(db); + createQuery.prepare(queryString("insert_buffer")); + createQuery.bindValue(":userid", user.toInt()); + createQuery.bindValue(":networkid", networkId.toInt()); + createQuery.bindValue(":buffertype", (int)type); + createQuery.bindValue(":buffername", buffer); + createQuery.bindValue(":buffercname", buffer.toLower()); + safeExec(createQuery); + + if(createQuery.lastError().isValid()) { + qWarning() << "PostgreSqlStorage::bufferInfo(): unable to create buffer"; + watchQuery(createQuery); + db.rollback(); + return BufferInfo(); + } + + createQuery.first(); + + BufferInfo bufferInfo = BufferInfo(createQuery.value(0).toInt(), networkId, type, 0, buffer); + db.commit(); + return bufferInfo; +} + +BufferInfo PostgreSqlStorage::getBufferInfo(UserId user, const BufferId &bufferId) { + QSqlQuery query(logDb()); + query.prepare(queryString("select_buffer_by_id")); + query.bindValue(":userid", user.toInt()); + query.bindValue(":bufferid", bufferId.toInt()); + safeExec(query); + if(!watchQuery(query)) + return BufferInfo(); + + if(!query.first()) + return BufferInfo(); + + BufferInfo bufferInfo(query.value(0).toInt(), query.value(1).toInt(), (BufferInfo::Type)query.value(2).toInt(), 0, query.value(4).toString()); + Q_ASSERT(!query.next()); + + return bufferInfo; +} + +QList PostgreSqlStorage::requestBuffers(UserId user) { + QList bufferlist; + + QSqlDatabase db = logDb(); + if(!beginReadOnlyTransaction(db)) { + qWarning() << "PostgreSqlStorage::requestBuffers(): cannot start read only transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return bufferlist; + } + + QSqlQuery query(db); + query.prepare(queryString("select_buffers")); + query.bindValue(":userid", user.toInt()); + + safeExec(query); + watchQuery(query); + while(query.next()) { + bufferlist << BufferInfo(query.value(0).toInt(), query.value(1).toInt(), (BufferInfo::Type)query.value(2).toInt(), query.value(3).toInt(), query.value(4).toString()); + } + db.commit(); + return bufferlist; +} + +QList PostgreSqlStorage::requestBufferIdsForNetwork(UserId user, NetworkId networkId) { + QList bufferList; + + QSqlDatabase db = logDb(); + if(!beginReadOnlyTransaction(db)) { + qWarning() << "PostgreSqlStorage::requestBufferIdsForNetwork(): cannot start read only transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return bufferList; + } + + QSqlQuery query(db); + query.prepare(queryString("select_buffers_for_network")); + query.bindValue(":networkid", networkId.toInt()); + query.bindValue(":userid", user.toInt()); + + safeExec(query); + watchQuery(query); + while(query.next()) { + bufferList << BufferId(query.value(0).toInt()); + } + db.commit(); + return bufferList; +} + +bool PostgreSqlStorage::removeBuffer(const UserId &user, const BufferId &bufferId) { + if(!isValidBuffer(user, bufferId)) + return false; + + QSqlDatabase db = logDb(); + if(!db.transaction()) { + qWarning() << "PostgreSqlStorage::removeBuffer(): cannot start transaction!"; + return false; + } + + QSqlQuery query(db); + query.prepare(queryString("delete_buffer_for_bufferid")); + query.bindValue(":bufferid", bufferId.toInt()); + safeExec(query); + if(!watchQuery(query)) { + db.rollback(); + return false; + } + db.commit(); + return true; +} + +bool PostgreSqlStorage::renameBuffer(const UserId &user, const BufferId &bufferId, const QString &newName) { + if(!isValidBuffer(user, bufferId)) + return false; + + QSqlQuery query(logDb()); + query.prepare(queryString("update_buffer_name")); + query.bindValue(":buffername", newName); + query.bindValue(":buffercname", newName.toLower()); + query.bindValue(":bufferid", bufferId.toInt()); + safeExec(query); + if(query.lastError().isValid()) { + return false; + } + return true; +} + +bool PostgreSqlStorage::mergeBuffersPermanently(const UserId &user, const BufferId &bufferId1, const BufferId &bufferId2) { + if(!isValidBuffer(user, bufferId1) || !isValidBuffer(user, bufferId2)) + return false; + + QSqlDatabase db = logDb(); + if(!db.transaction()) { + qWarning() << "PostgreSqlStorage::mergeBuffersPermanently(): cannot start transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return false; + } + + QSqlQuery query(db); + query.prepare(queryString("update_backlog_bufferid")); + query.bindValue(":oldbufferid", bufferId2.toInt()); + query.bindValue(":newbufferid", bufferId1.toInt()); + safeExec(query); + if(!watchQuery(query)) { + db.rollback(); + return false; + } + + QSqlQuery delBufferQuery(logDb()); + delBufferQuery.prepare(queryString("delete_buffer_for_bufferid")); + delBufferQuery.bindValue(":bufferid", bufferId2.toInt()); + safeExec(delBufferQuery); + if(!watchQuery(delBufferQuery)) { + db.rollback(); + return false; + } + + db.commit(); + return true; +} + +void PostgreSqlStorage::setBufferLastSeenMsg(UserId user, const BufferId &bufferId, const MsgId &msgId) { + QSqlQuery query(logDb()); + query.prepare(queryString("update_buffer_lastseen")); + + query.bindValue(":userid", user.toInt()); + query.bindValue(":bufferid", bufferId.toInt()); + query.bindValue(":lastseenmsgid", msgId.toInt()); + safeExec(query); + watchQuery(query); +} + +QHash PostgreSqlStorage::bufferLastSeenMsgIds(UserId user) { + QHash lastSeenHash; + + QSqlDatabase db = logDb(); + if(!beginReadOnlyTransaction(db)) { + qWarning() << "PostgreSqlStorage::bufferLastSeenMsgIds(): cannot start read only transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return lastSeenHash; + } + + QSqlQuery query(db); + query.prepare(queryString("select_buffer_lastseen_messages")); + query.bindValue(":userid", user.toInt()); + safeExec(query); + if(!watchQuery(query)) { + db.rollback(); + return lastSeenHash; + } + + while(query.next()) { + lastSeenHash[query.value(0).toInt()] = query.value(1).toInt(); + } + + db.commit(); + return lastSeenHash; +} + +MsgId PostgreSqlStorage::logMessage(Message msg) { + QSqlDatabase db = logDb(); + if(!db.transaction()) { + qWarning() << "PostgreSqlStorage::logMessage(): cannot start transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return false; + } + + QSqlQuery logMessageQuery(db); + logMessageQuery.prepare(queryString("insert_message")); + logMessageQuery.bindValue(":time", msg.timestamp().toTime_t()); + logMessageQuery.bindValue(":bufferid", msg.bufferInfo().bufferId().toInt()); + logMessageQuery.bindValue(":type", msg.type()); + logMessageQuery.bindValue(":flags", (int)msg.flags()); + logMessageQuery.bindValue(":sender", msg.sender()); + logMessageQuery.bindValue(":message", msg.contents()); + safeExec(logMessageQuery); + + if(logMessageQuery.lastError().isValid()) { + // first we need to reset the transaction + db.rollback(); + db.transaction(); + + QSqlQuery addSenderQuery(db); + addSenderQuery.prepare(queryString("insert_sender")); + addSenderQuery.bindValue(":sender", msg.sender()); + safeExec(addSenderQuery); + safeExec(logMessageQuery); + + if(!watchQuery(logMessageQuery)) { + db.rollback(); + return MsgId(); + } + } + + logMessageQuery.first(); + MsgId msgId = logMessageQuery.value(0).toInt(); + db.commit(); + + Q_ASSERT(msgId.isValid()); + return msgId; +} + +QList PostgreSqlStorage::requestMsgs(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit) { + QList messagelist; + + BufferInfo bufferInfo = getBufferInfo(user, bufferId); + if(!bufferInfo.isValid()) + return messagelist; + + QSqlQuery query(logDb()); + + if(last == -1 && first == -1) { + query.prepare(queryString("select_messagesNewestK")); + } else if(last == -1) { + query.prepare(queryString("select_messagesNewerThan")); + query.bindValue(":firstmsg", first.toInt()); + } else { + query.prepare(queryString("select_messages")); + query.bindValue(":lastmsg", last.toInt()); + query.bindValue(":firstmsg", first.toInt()); + } + + query.bindValue(":bufferid", bufferId.toInt()); + query.bindValue(":limit", limit); + safeExec(query); + + watchQuery(query); + + while(query.next()) { + Message msg(QDateTime::fromTime_t(query.value(1).toInt()), + bufferInfo, + (Message::Type)query.value(2).toUInt(), + query.value(5).toString(), + query.value(4).toString(), + (Message::Flags)query.value(3).toUInt()); + msg.setMsgId(query.value(0).toInt()); + messagelist << msg; + } + return messagelist; +} + +QList PostgreSqlStorage::requestAllMsgs(UserId user, MsgId first, MsgId last, int limit) { + QList messagelist; + + QHash bufferInfoHash; + foreach(BufferInfo bufferInfo, requestBuffers(user)) { + bufferInfoHash[bufferInfo.bufferId()] = bufferInfo; + } + + QSqlQuery query(logDb()); + if(last == -1) { + query.prepare(queryString("select_messagesAllNew")); + } else { + query.prepare(queryString("select_messagesAll")); + query.bindValue(":lastmsg", last.toInt()); + } + query.bindValue(":userid", user.toInt()); + query.bindValue(":firstmsg", first.toInt()); + query.bindValue(":limit", limit); + safeExec(query); + + watchQuery(query); + + while(query.next()) { + Message msg(QDateTime::fromTime_t(query.value(2).toInt()), + bufferInfoHash[query.value(1).toInt()], + (Message::Type)query.value(3).toUInt(), + query.value(6).toString(), + query.value(5).toString(), + (Message::Flags)query.value(4).toUInt()); + msg.setMsgId(query.value(0).toInt()); + messagelist << msg; + } + + return messagelist; +} + +// void PostgreSqlStorage::safeExec(QSqlQuery &query) { +// qDebug() << "PostgreSqlStorage::safeExec"; +// qDebug() << " executing:\n" << query.executedQuery(); +// qDebug() << " bound Values:"; +// QList list = query.boundValues().values(); +// for (int i = 0; i < list.size(); ++i) +// qCritical() << i << ": " << list.at(i).toString().toAscii().data(); + +// query.exec(); + +// qDebug() << "Success:" << !query.lastError().isValid(); +// qDebug(); + +// if(!query.lastError().isValid()) +// return; + +// qDebug() << "==================== ERROR ===================="; +// watchQuery(query); +// qDebug() << "==============================================="; +// qDebug(); +// return; +// } + +bool PostgreSqlStorage::beginReadOnlyTransaction(QSqlDatabase &db) { + QSqlQuery query = db.exec("BEGIN TRANSACTION READ ONLY"); + return !query.lastError().isValid(); +} diff --git a/src/core/postgresqlstorage.h b/src/core/postgresqlstorage.h new file mode 100644 index 00000000..d83b4cc5 --- /dev/null +++ b/src/core/postgresqlstorage.h @@ -0,0 +1,131 @@ +/*************************************************************************** + * Copyright (C) 2005-09 by the Quassel Project * + * devel@quassel-irc.org * + * * + * 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) version 3. * + * * + * 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., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef POSTGRESQLSTORAGE_H +#define POSTGRESQLSTORAGE_H + +#include "abstractsqlstorage.h" + +#include +#include + +class PostgreSqlStorage : public AbstractSqlStorage { + Q_OBJECT + +public: + PostgreSqlStorage(QObject *parent = 0); + virtual ~PostgreSqlStorage(); + +public slots: + /* General */ + + bool isAvailable() const; + QString displayName() const; + QString description() const; + QVariantMap setupKeys() const; + + // TODO: Add functions for configuring the backlog handling, i.e. defining auto-cleanup settings etc + + /* User handling */ + + virtual UserId addUser(const QString &user, const QString &password); + virtual void updateUser(UserId user, const QString &password); + virtual void renameUser(UserId user, const QString &newName); + virtual UserId validateUser(const QString &user, const QString &password); + virtual UserId internalUser(); + virtual void delUser(UserId user); + virtual void setUserSetting(UserId userId, const QString &settingName, const QVariant &data); + virtual QVariant getUserSetting(UserId userId, const QString &settingName, const QVariant &defaultData = QVariant()); + + /* Identity handling */ + virtual IdentityId createIdentity(UserId user, CoreIdentity &identity); + virtual bool updateIdentity(UserId user, const CoreIdentity &identity); + virtual void removeIdentity(UserId user, IdentityId identityId); + virtual QList identities(UserId user); + + /* Network handling */ + virtual NetworkId createNetwork(UserId user, const NetworkInfo &info); + virtual bool updateNetwork(UserId user, const NetworkInfo &info); + virtual bool removeNetwork(UserId user, const NetworkId &networkId); + virtual QList networks(UserId user); + virtual QList connectedNetworks(UserId user); + virtual void setNetworkConnected(UserId user, const NetworkId &networkId, bool isConnected); + + /* persistent channels */ + virtual QHash persistentChannels(UserId user, const NetworkId &networkId); + virtual void setChannelPersistent(UserId user, const NetworkId &networkId, const QString &channel, bool isJoined); + virtual void setPersistentChannelKey(UserId user, const NetworkId &networkId, const QString &channel, const QString &key); + + /* persistent user states */ + virtual QString awayMessage(UserId user, NetworkId networkId); + virtual void setAwayMessage(UserId user, NetworkId networkId, const QString &awayMsg); + virtual QString userModes(UserId user, NetworkId networkId); + virtual void setUserModes(UserId user, NetworkId networkId, const QString &userModes); + + /* Buffer handling */ + virtual BufferInfo bufferInfo(UserId user, const NetworkId &networkId, BufferInfo::Type type, const QString &buffer = "", bool create = true); + virtual BufferInfo getBufferInfo(UserId user, const BufferId &bufferId); + virtual QList requestBuffers(UserId user); + virtual QList requestBufferIdsForNetwork(UserId user, NetworkId networkId); + virtual bool removeBuffer(const UserId &user, const BufferId &bufferId); + virtual bool renameBuffer(const UserId &user, const BufferId &bufferId, const QString &newName); + virtual bool mergeBuffersPermanently(const UserId &user, const BufferId &bufferId1, const BufferId &bufferId2); + virtual void setBufferLastSeenMsg(UserId user, const BufferId &bufferId, const MsgId &msgId); + virtual QHash bufferLastSeenMsgIds(UserId user); + + /* Message handling */ + + virtual MsgId logMessage(Message msg); + virtual QList requestMsgs(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1); + virtual QList requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1); + +protected: + virtual void setConnectionProperties(const QVariantMap &properties); + inline virtual QString driverName() { return "QPSQL"; } + inline virtual QString hostName() { return _hostName; } + inline virtual int port() { return _port; } + inline virtual QString databaseName() { return _databaseName; } + inline virtual QString userName() { return _userName; } + inline virtual QString password() { return _password; } + virtual int installedSchemaVersion(); + virtual bool updateSchemaVersion(int newVersion); + virtual bool setupSchemaVersion(int version); + void safeExec(QSqlQuery &query); + bool beginReadOnlyTransaction(QSqlDatabase &db); + +private: + bool isValidNetwork(UserId user, const NetworkId &networkId); + bool isValidBuffer(const UserId &user, const BufferId &bufferId); + + void bindNetworkInfo(QSqlQuery &query, const NetworkInfo &info); + void bindServerInfo(QSqlQuery &query, const Network::Server &server); + + QString _hostName; + int _port; + QString _databaseName; + QString _userName; + QString _password; + + static int _maxRetryCount; +}; + +inline void PostgreSqlStorage::safeExec(QSqlQuery &query) { query.exec(); } + +#endif diff --git a/src/core/sql.qrc b/src/core/sql.qrc index 7c58469a..2890a0ec 100644 --- a/src/core/sql.qrc +++ b/src/core/sql.qrc @@ -1,5 +1,75 @@ + ./SQL/PostgreSQL/14/delete_backlog_by_uid.sql + ./SQL/PostgreSQL/14/delete_backlog_for_buffer.sql + ./SQL/PostgreSQL/14/delete_backlog_for_network.sql + ./SQL/PostgreSQL/14/delete_buffer_for_bufferid.sql + ./SQL/PostgreSQL/14/delete_buffers_by_uid.sql + ./SQL/PostgreSQL/14/delete_buffers_for_network.sql + ./SQL/PostgreSQL/14/delete_identity.sql + ./SQL/PostgreSQL/14/delete_ircservers_for_network.sql + ./SQL/PostgreSQL/14/delete_network.sql + ./SQL/PostgreSQL/14/delete_networks_by_uid.sql + ./SQL/PostgreSQL/14/delete_nicks.sql + ./SQL/PostgreSQL/14/delete_quasseluser.sql + ./SQL/PostgreSQL/14/insert_buffer.sql + ./SQL/PostgreSQL/14/insert_identity.sql + ./SQL/PostgreSQL/14/insert_message.sql + ./SQL/PostgreSQL/14/insert_network.sql + ./SQL/PostgreSQL/14/insert_nick.sql + ./SQL/PostgreSQL/14/insert_quasseluser.sql + ./SQL/PostgreSQL/14/insert_sender.sql + ./SQL/PostgreSQL/14/insert_server.sql + ./SQL/PostgreSQL/14/insert_user_setting.sql + ./SQL/PostgreSQL/14/select_authuser.sql + ./SQL/PostgreSQL/14/select_buffer_by_id.sql + ./SQL/PostgreSQL/14/select_buffer_lastseen_messages.sql + ./SQL/PostgreSQL/14/select_bufferByName.sql + ./SQL/PostgreSQL/14/select_bufferExists.sql + ./SQL/PostgreSQL/14/select_buffers.sql + ./SQL/PostgreSQL/14/select_buffers_for_network.sql + ./SQL/PostgreSQL/14/select_checkidentity.sql + ./SQL/PostgreSQL/14/select_connected_networks.sql + ./SQL/PostgreSQL/14/select_identities.sql + ./SQL/PostgreSQL/14/select_internaluser.sql + ./SQL/PostgreSQL/14/select_messages.sql + ./SQL/PostgreSQL/14/select_messagesAll.sql + ./SQL/PostgreSQL/14/select_messagesAllNew.sql + ./SQL/PostgreSQL/14/select_messagesNewerThan.sql + ./SQL/PostgreSQL/14/select_messagesNewestK.sql + ./SQL/PostgreSQL/14/select_network_awaymsg.sql + ./SQL/PostgreSQL/14/select_network_usermode.sql + ./SQL/PostgreSQL/14/select_networkExists.sql + ./SQL/PostgreSQL/14/select_networks_for_user.sql + ./SQL/PostgreSQL/14/select_nicks.sql + ./SQL/PostgreSQL/14/select_persistent_channels.sql + ./SQL/PostgreSQL/14/select_servers_for_network.sql + ./SQL/PostgreSQL/14/select_user_setting.sql + ./SQL/PostgreSQL/14/select_userid.sql + ./SQL/PostgreSQL/14/setup_000_quasseluser.sql + ./SQL/PostgreSQL/14/setup_010_sender.sql + ./SQL/PostgreSQL/14/setup_020_identity.sql + ./SQL/PostgreSQL/14/setup_030_identity_nick.sql + ./SQL/PostgreSQL/14/setup_040_network.sql + ./SQL/PostgreSQL/14/setup_050_buffer.sql + ./SQL/PostgreSQL/14/setup_060_backlog.sql + ./SQL/PostgreSQL/14/setup_070_coreinfo.sql + ./SQL/PostgreSQL/14/setup_080_ircservers.sql + ./SQL/PostgreSQL/14/setup_090_backlog_idx.sql + ./SQL/PostgreSQL/14/setup_100_user_setting.sql + ./SQL/PostgreSQL/14/update_backlog_bufferid.sql + ./SQL/PostgreSQL/14/update_buffer_lastseen.sql + ./SQL/PostgreSQL/14/update_buffer_name.sql + ./SQL/PostgreSQL/14/update_buffer_persistent_channel.sql + ./SQL/PostgreSQL/14/update_buffer_set_channel_key.sql + ./SQL/PostgreSQL/14/update_identity.sql + ./SQL/PostgreSQL/14/update_network.sql + ./SQL/PostgreSQL/14/update_network_connected.sql + ./SQL/PostgreSQL/14/update_network_set_awaymsg.sql + ./SQL/PostgreSQL/14/update_network_set_usermode.sql + ./SQL/PostgreSQL/14/update_user_setting.sql + ./SQL/PostgreSQL/14/update_username.sql + ./SQL/PostgreSQL/14/update_userpassword.sql ./SQL/SQLite/1/upgrade_000_drop_coreinfo.sql ./SQL/SQLite/1/upgrade_010_create_coreinfo.sql ./SQL/SQLite/1/upgrade_020_update_schemaversion.sql diff --git a/src/core/sqlitestorage.h b/src/core/sqlitestorage.h index fbb366f6..feb2c5aa 100644 --- a/src/core/sqlitestorage.h +++ b/src/core/sqlitestorage.h @@ -39,6 +39,7 @@ public slots: bool isAvailable() const; QString displayName() const; + inline QVariantMap setupKeys() const { return QVariantMap(); } QString description() const; // TODO: Add functions for configuring the backlog handling, i.e. defining auto-cleanup settings etc @@ -97,6 +98,7 @@ public slots: virtual QList requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1); protected: + inline virtual void setConnectionProperties(const QVariantMap & /* properties */) {} inline virtual QString driverName() { return "QSQLITE"; } inline virtual QString databaseName() { return backlogFile(); } virtual int installedSchemaVersion(); diff --git a/src/core/storage.h b/src/core/storage.h index 1cb2ee82..17fdd70a 100644 --- a/src/core/storage.h +++ b/src/core/storage.h @@ -59,6 +59,10 @@ public slots: /** \return A string that can be displayed by the client to describe the storage backend */ virtual QString description() const = 0; + //! Returns a map where the keys are required properties to use the storage backend + /* the values are QVariants with default values */ + virtual QVariantMap setupKeys() const = 0; + //! Setup the storage provider. /** This prepares the storage provider (e.g. create tables, etc.) for use within Quassel. * \param settings Hostname, port, username, password, ... @@ -176,13 +180,6 @@ public slots: */ virtual QList networks(UserId user) = 0; - //! Get the unique NetworkId of the network for a user. - /** \param user The core user who owns this network - * \param network The network name - * \return The NetworkId corresponding to the given network, or 0 if not found - */ - virtual NetworkId getNetworkId(UserId user, const QString &network) = 0; - //! Get a list of Networks to restore /** Return a list of networks the user was connected at the time of core shutdown * \note This method is threadsafe. diff --git a/src/qtui/coreconfigwizard.cpp b/src/qtui/coreconfigwizard.cpp index bc2ebf3c..030af574 100644 --- a/src/qtui/coreconfigwizard.cpp +++ b/src/qtui/coreconfigwizard.cpp @@ -20,6 +20,8 @@ #include #include +#include +#include #include "coreconfigwizard.h" #include "iconloader.h" @@ -30,7 +32,7 @@ CoreConfigWizard::CoreConfigWizard(const QList &backends, QWidget *par setPage(AdminUserPage, new CoreConfigWizardPages::AdminUserPage(this)); setPage(StorageSelectionPage, new CoreConfigWizardPages::StorageSelectionPage(_backends, this)); syncPage = new CoreConfigWizardPages::SyncPage(this); - connect(syncPage, SIGNAL(setupCore(const QString &)), this, SLOT(prepareCoreSetup(const QString &))); + connect(syncPage, SIGNAL(setupCore(const QString &, const QVariantMap &)), this, SLOT(prepareCoreSetup(const QString &, const QVariantMap &))); setPage(SyncPage, syncPage); syncRelayPage = new CoreConfigWizardPages::SyncRelayPage(this); connect(syncRelayPage, SIGNAL(startOver()), this, SLOT(startOver())); @@ -63,13 +65,16 @@ QHash CoreConfigWizard::backends() const { return _backends; } -void CoreConfigWizard::prepareCoreSetup(const QString &backend) { +void CoreConfigWizard::prepareCoreSetup(const QString &backend, const QVariantMap &properties) { // Prevent the user from changing any settings he already specified... - foreach(int idx, visitedPages()) page(idx)->setEnabled(false); + foreach(int idx, visitedPages()) + page(idx)->setEnabled(false); + QVariantMap foo; foo["AdminUser"] = field("adminUser.user").toString(); foo["AdminPasswd"] = field("adminUser.password").toString(); foo["Backend"] = backend; + foo["ConnectionProperties"] = properties; emit setupCore(foo); } @@ -91,7 +96,6 @@ void CoreConfigWizard::coreSetupFailed(const QString &error) { //foreach(int idx, visitedPages()) page(idx)->setEnabled(true); //setStartId(SyncPage); //restart(); - } void CoreConfigWizard::startOver() { @@ -183,9 +187,73 @@ QString StorageSelectionPage::selectedBackend() const { return ui.backendList->currentText(); } +QVariantMap StorageSelectionPage::connectionProperties() const { + QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString(); + QVariantMap properties = _backends[backend].toMap()["ConnectionProperties"].toMap(); + if(!properties.isEmpty() && _connectionBox) { + QVariantMap::iterator propertyIter = properties.begin(); + while(propertyIter != properties.constEnd()) { + QWidget *widget = _connectionBox->findChild(propertyIter.key()); + switch(propertyIter.value().type()) { + case QVariant::Int: + { + QSpinBox *spinbox = qobject_cast(widget); + Q_ASSERT(spinbox); + propertyIter.value() = QVariant(spinbox->value()); + } + break; + default: + { + QLineEdit *lineEdit = qobject_cast(widget); + Q_ASSERT(lineEdit); + propertyIter.value() = QVariant(lineEdit->text()); + } + } + propertyIter++; + } + } + return properties; +} + void StorageSelectionPage::on_backendList_currentIndexChanged() { QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString(); ui.description->setText(_backends[backend].toMap()["Description"].toString()); + + if(_connectionBox) { + layout()->removeWidget(_connectionBox); + _connectionBox->deleteLater(); + _connectionBox = 0; + } + + QVariantMap properties = _backends[backend].toMap()["ConnectionProperties"].toMap(); + if(!properties.isEmpty()) { + QGroupBox *propertyBox = new QGroupBox(this); + propertyBox->setTitle(tr("Connection Properties")); + QFormLayout *formlayout = new QFormLayout; + + QVariantMap::const_iterator propertyIter = properties.constBegin(); + while(propertyIter != properties.constEnd()) { + QWidget *widget = 0; + switch(propertyIter.value().type()) { + case QVariant::Int: + { + QSpinBox *spinbox = new QSpinBox(propertyBox); + spinbox->setMaximum(64000); + spinbox->setValue(propertyIter.value().toInt()); + widget = spinbox; + } + break; + default: + widget = new QLineEdit(propertyIter.value().toString(), propertyBox); + } + widget->setObjectName(propertyIter.key()); + formlayout->addRow(propertyIter.key() + ":", widget); + propertyIter++; + } + propertyBox->setLayout(formlayout); + static_cast(layout())->insertWidget(layout()->indexOf(ui.descriptionBox) + 1, propertyBox); + _connectionBox = propertyBox; + } } /*** Sync Page ***/ @@ -199,11 +267,14 @@ SyncPage::SyncPage(QWidget *parent) : QWizardPage(parent) { void SyncPage::initializePage() { complete = false; hasError = false; - QString backend = qobject_cast(wizard()->page(CoreConfigWizard::StorageSelectionPage))->selectedBackend(); + + StorageSelectionPage *storagePage = qobject_cast(wizard()->page(CoreConfigWizard::StorageSelectionPage)); + QString backend = storagePage->selectedBackend(); + QVariantMap properties = storagePage->connectionProperties(); Q_ASSERT(!backend.isEmpty()); ui.user->setText(wizard()->field("adminUser.user").toString()); ui.backend->setText(backend); - emit setupCore(backend); + emit setupCore(backend, properties); } int SyncPage::nextId() const { diff --git a/src/qtui/coreconfigwizard.h b/src/qtui/coreconfigwizard.h index 7ceae20c..91b532fc 100644 --- a/src/qtui/coreconfigwizard.h +++ b/src/qtui/coreconfigwizard.h @@ -61,7 +61,7 @@ class CoreConfigWizard : public QWizard { void syncFinished(); private slots: - void prepareCoreSetup(const QString &backend); + void prepareCoreSetup(const QString &backend, const QVariantMap &connectionProperties); void coreSetupSuccess(); void coreSetupFailed(const QString &); void startOver(); @@ -102,10 +102,13 @@ namespace CoreConfigWizardPages { StorageSelectionPage(const QHash &backends, QWidget *parent = 0); int nextId() const; QString selectedBackend() const; + QVariantMap connectionProperties() const; + private slots: void on_backendList_currentIndexChanged(); private: Ui::CoreConfigWizardStorageSelectionPage ui; + QGroupBox *_connectionBox; QHash _backends; }; @@ -124,7 +127,7 @@ namespace CoreConfigWizardPages { void setComplete(bool); signals: - void setupCore(const QString &backend); + void setupCore(const QString &backend, const QVariantMap &); private: Ui::CoreConfigWizardSyncPage ui; diff --git a/src/qtui/ui/coreconfigwizardstorageselectionpage.ui b/src/qtui/ui/coreconfigwizardstorageselectionpage.ui index 261426b8..75f45e9d 100644 --- a/src/qtui/ui/coreconfigwizardstorageselectionpage.ui +++ b/src/qtui/ui/coreconfigwizardstorageselectionpage.ui @@ -5,8 +5,8 @@ 0 0 - 400 - 161 + 310 + 168 @@ -40,7 +40,7 @@ Qt::Horizontal - + 40 20 @@ -73,14 +73,14 @@ - + Qt::Vertical - + - 392 - 51 + 20 + 40