#include "ts3db.h" #include #include #include #define MAX_CONNECTIONS 100 typedef struct { PGconn *conn; PGresult *result; } pg_connection; static log_callback log = 0; static pg_connection connections[MAX_CONNECTIONS]; static unsigned int connection_count = 0; static const char *keywords[] = { "host", "hostaddr", "port", "dbname", "user", "password", "sslmode", "sslcert", "sslkey", "sslrootcert", "sslcrl", "application_name", 0}; typedef struct { char *host; char *hostaddr; char *port; char *dbname; char *user; char *password; char *sslmode; char *sslcert; char *sslkey; char *sslrootcert; char *sslcrl; char *application_name; } pg_settings; static pg_settings settings; char *ts3dbplugin_version() { return "0.1"; } char *ts3dbplugin_name() { return "PostgreSQL plugin"; } int ts3dbplugin_disconnect() { log("disconnect", LOG_DEVELOP); ts3dbplugin_shutdown(); return 0; } void ts3dbplugin_shutdown() { log("shutdown", LOG_DEVELOP); unsigned int i; for (i = 0; i < connection_count; i++) { PQclear(connections[i].result); PQfinish(connections[i].conn); } connection_count = 0; } int ts3dbplugin_init(log_callback logging, char *parameter) { log = logging; settings.host = "localhost"; settings.hostaddr = ""; settings.port = ""; settings.dbname = "ts3"; settings.user = "ts3"; settings.password = ""; settings.sslmode = NULL; settings.sslcert = NULL; settings.sslkey = NULL; settings.sslrootcert = NULL; settings.sslcrl = NULL; settings.application_name = "teamspeak3"; return 0; } int ts3dbplugin_connect(unsigned int *connection_nr) { PGconn *conn; conn = PQconnectdbParams(keywords, (const char **)&settings, true); if (PQstatus(conn) != CONNECTION_OK) { log(PQerrorMessage(conn), LOG_CRITICAL); return 1280; } *connection_nr = connection_count; connections[connection_count].conn = conn; connections[connection_count].result = NULL; connection_count++; return 0; } PGconn *get_connection(unsigned int connection_nr) { if (connection_nr >= connection_count) { log("Connection not found.", LOG_ERROR); return NULL; } return connections[connection_nr].conn; } PGresult *get_last_result(unsigned int connection_nr) { if (connection_nr >= connection_count) { log("Connection not found.", LOG_ERROR); return NULL; } return connections[connection_nr].result; } void save_last_result(unsigned int connection_nr, PGresult *result) { if (connection_nr >= connection_count) { log("Connection not found.", LOG_ERROR); return; } if (connections[connection_nr].result != NULL) { PQclear(connections[connection_nr].result); } connections[connection_nr].result = result; } char *ts3dbplugin_getlasterror(unsigned int connection_nr) { log("getlasterror", LOG_DEVELOP); const PGconn *conn = get_connection(connection_nr); return PQerrorMessage(conn); } unsigned int ts3dbplugin_tableexists(unsigned int connection_nr, const char* table_name) { log("tableexists", LOG_DEVELOP); log(table_name, LOG_DEVELOP); PGconn *conn = get_connection(connection_nr); const char* const params[] = { table_name }; PGresult *result; int tables; result = PQexecParams(conn, "select 1 from pg_tables where \ schemaname='public' and \ tablename = $1 limit 1;", 1, NULL, params, NULL, NULL, 0); tables = PQntuples(result); PQclear(result); if (tables == 0) { /* table not exists */ return 0; } return 1; } unsigned long long ts3dbplugin_getmodifiedrowcount(unsigned int connection_nr) { log("getmodifiedrowcount", LOG_DEVELOP); PGresult *result = get_last_result(connection_nr); const char *count = PQcmdTuples(result); unsigned long long number; sscanf(count, "%llu", &number); return number; } unsigned long long ts3dbplugin_getlastinsertid(unsigned int connection_nr) { log("getlastinsertid", LOG_DEVELOP); const PGresult *result = get_last_result(connection_nr); if (PQnfields(result) == 1) { if (strcmp(PQfname(result, 0), "last_inserted_id") == 0) { const char *count = PQgetvalue(result, 0, 0); unsigned long long number; sscanf(count, "%llu", &number); return number; } } return 0; } unsigned int ts3dbplugin_open(unsigned int connection_nr, const char* query, field_callback new_field, value_callback new_value, row_callback new_row, void *context) { log(query, LOG_DEBUG); ExecStatusType status; int col_count, row_count, i, j; PGconn *conn = get_connection(connection_nr); PGresult *result = PQexec(conn, query); save_last_result(connection_nr, result); status = PQresultStatus(result); if (status == PGRES_BAD_RESPONSE || status == PGRES_FATAL_ERROR) { log(PQresultErrorMessage(result), LOG_ERROR); return 1280; } if (status == PGRES_NONFATAL_ERROR) { log(PQresultErrorMessage(result), LOG_WARNING); } col_count = PQnfields(result); for (i = 0; i < col_count; i++) { log(PQfname(result, i), LOG_DEBUG); new_field(i, PQfname(result, i), context); } row_count = PQntuples(result); for (i = 0; i < row_count; i++) { log("new row", LOG_DEBUG); new_row(context); log("new row done.", LOG_DEBUG); for (j = 0; j < col_count; j++) { if (PQgetisnull(result, i, j) == 1) { log("", LOG_DEBUG); new_value(j, NULL, context); } else { log(PQgetvalue(result, i, j), LOG_DEBUG); new_value(j, PQgetvalue(result, i, j), context); } } } return 0; } unsigned int ts3dbplugin_exec(unsigned int connection_nr, const char* query) { log(query, LOG_DEVELOP); ExecStatusType status; PGconn *conn = get_connection(connection_nr); PGresult *result = PQexec(conn, query); save_last_result(connection_nr, result); status = PQresultStatus(result); if (status == PGRES_BAD_RESPONSE || status == PGRES_FATAL_ERROR) { log(PQresultErrorMessage(result), LOG_ERROR); return 1280; } if (status == PGRES_NONFATAL_ERROR) { log(PQresultErrorMessage(result), LOG_WARNING); } return 0; }