summaryrefslogblamecommitdiffstats
path: root/ts3db.c
blob: 69085f44bb95e8275415dda1d39cbba2e50fa8ee (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
                  

                     
                   






                           

                            























                                                                           


                           




                        
                               



                            

                                   




                           







                                            



                                                           
                  












                                             




                                                    











                                                                       
 


             










                                                     
 



                                                
 
                                             

 
                                                                   
 







































                                                                                        
 




                                                                              



                                                      
 

                                   



                                                                          

                                                            
 







                                                                  
     
 
             





                                                                                 






























                                                                      

                                                            


         




                                                                            
















                                                                      

             
#include "ts3db.h"
#include <libpq-fe.h>
#include <stdbool.h>
#include <string.h>

#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++) {
            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;
}