/* milter-callback - a sendmail milter to perform variuos sender verifications
 Copyright (C) 2008  Eugene M. Zheganin, milter-callback@norma.perm.ru
 
 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 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifdef WITH_PGSQL
#include <milter-callback.h>
#include <commonprocs.h>

struct connList connPool;
/*
 Here we will do all the needed updates with the database
*/

int
getDBVersionId () {
    int pgConnId, bufStrLen, dbVID;
    char *dbVersionIDStr;
    char *dbVersionIdDML = "select dbvid from version;";
    char tmpLog[MAXLOGLINE];
    
    logNow("Entered getUpdates().", 3, 0);
    
    pgConnId = getPgConn();
    
    connPool.pgResArr[pgConnId] = PQexec(connPool.pgConnArr[pgConnId], dbVersionIdDML);
    if (PQresultStatus(connPool.pgResArr[pgConnId]) != PGRES_TUPLES_OK){
        snprintf(tmpLog, MAXLOGLINE, "SELECT command failed: %s", PQerrorMessage(connPool.pgConnArr[pgConnId]));
        logNow(&tmpLog[0], 0, 0);
        snprintf(tmpLog, MAXLOGLINE, "The result status is: %s",PQresStatus(PQresultStatus(connPool.pgResArr[pgConnId])));
        logNow(&tmpLog[0], 0, 0);
	snprintf(tmpLog, MAXLOGLINE, "This actually means that DB version is 0, all updates are needed.");
        logNow(&tmpLog[0], 0, 0);
        PQclear(connPool.pgResArr[pgConnId]);
	/* freeing lock */
	unlockPgConn(pgConnId);
        return 0;
    }
    snprintf(tmpLog, MAXLOGLINE, "Successfully queried database version, got %d rows.", PQntuples(connPool.pgResArr[pgConnId]));
    logNow(&tmpLog[0], 2, 0);
    
    bufStrLen = strlen(PQgetvalue(connPool.pgResArr[pgConnId], 0, 0));
    dbVersionIDStr = malloc(bufStrLen + 1);
    if (dbVersionIDStr == NULL) {
	logNow("Cannot allocate memory.", 0, 0);
        exit(EXIT_FAILURE);
    }
    bzero(dbVersionIDStr, bufStrLen + 1);
    strncpy(dbVersionIDStr, PQgetvalue(connPool.pgResArr[pgConnId], 0, 0), bufStrLen);
    snprintf(tmpLog, MAXLOGLINE, "Successfully got a row containing version string: %s.", dbVersionIDStr);
    logNow(&tmpLog[0], 3, 0);
    dbVID = strtol(dbVersionIDStr, NULL, 10);
    if (dbVID == 0) {
	logNow("Invalid version found or no strtol() conversion can be performed, aborting.", 0, 0);
	exit(EXIT_FAILURE);
    }
    logNow("Trying to free() dbVersionIDStr.", 3, 0);
    free(dbVersionIDStr);
    PQclear(connPool.pgResArr[pgConnId]);
    /* freeing lock */
    unlockPgConn(pgConnId);
    return(dbVID);
}

void
getUpdates () {
    int pgConnId, updCounter, dbVID;
    const char *pgUpdates[] = {"alter table history add column spf integer;", 
				"alter table history add column reverserelay integer;",
				"alter table history add column fakerelay integer;",
				"update history set spf=-1 where spf is null",
				"update history set reverserelay=-1 where reverserelay is null",
				"update history set fakerelay=-1 where fakerelay is null",
				"create table version(dbvid integer);",
				"insert into version(dbvid) values(1);",
				NULL};
    const int requiredDBVID = 1;
    char tmpLog[MAXLOGLINE];
	
    logNow("Entered getUpdates().", 3, 0);
		
    pgConnId = getPgConn();
    
    dbVID = getDBVersionId();
    if (dbVID < requiredDBVID) {
	for (updCounter = 0; pgUpdates[updCounter] != NULL; updCounter++) {
	    snprintf(tmpLog, MAXLOGLINE, "Trying to apply the following update: %s.", pgUpdates[updCounter]);
	    logNow(&tmpLog[0], 2, 0);
	
	    /* actually applying updates */
	    connPool.pgResArr[pgConnId] = PQexec(connPool.pgConnArr[pgConnId], pgUpdates[updCounter]);
	    if (PQresultStatus(connPool.pgResArr[pgConnId]) != PGRES_COMMAND_OK && PQresultStatus(connPool.pgResArr[pgConnId]) != PGRES_TUPLES_OK){
		snprintf(tmpLog, MAXLOGLINE, PQerrorMessage(connPool.pgConnArr[pgConnId]));
		logNow(&tmpLog[0], 0, 0);
		snprintf(tmpLog, MAXLOGLINE, "The result status is: %s",PQresStatus(PQresultStatus(connPool.pgResArr[pgConnId])));
    		logNow(&tmpLog[0], 0, 0);
		snprintf(tmpLog, MAXLOGLINE, "Database version update statement %d failed, aborting. You probably need manual intervention.", updCounter + 1);
    		logNow(&tmpLog[0], 0, 0);
		exit(EXIT_FAILURE);
	    } else {
		snprintf(tmpLog, MAXLOGLINE, "Database successfully updated with statement %d.", updCounter);
    		logNow(&tmpLog[0], 0, 0);
	    }
	}
	snprintf(tmpLog, MAXLOGLINE, "Database successfully updated to version %d.", requiredDBVID);
	logNow(&tmpLog[0], 0, 0);
    } else {
	snprintf(tmpLog, MAXLOGLINE, "Database version id %d, required version %d, no updates needed.", dbVID, requiredDBVID);
	logNow(&tmpLog[0], 3, 0);
    }
    /* freeing lock */
    unlockPgConn(pgConnId);
}

#endif
