/* 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>

extern char myHostName[MAXHOSTNAME];
struct connList connPool;

int
pushHistory(struct mlfiPriv *privData, char *action, char *formattedEmail){
#ifdef WITH_SPF
    char *pgStatFormat = "insert into history (connectdate, connectfrom, helofrom, relaypresip, mxnum, mxesthatreject, mxesthataccept, mxesoutoforder, mxesthattempfail, gracefuldns, whitelisted, resolvedrelayip, receivinghost, envfrom, action, spf, reverserelay, fakerelay) values('%s','%s','%s','%s',%d,%d,%d,%d,%d,%s,%s,'%s','%s','%s', '%s',%d,%d,%d)";
#else
    char *pgStatFormat = "insert into history (connectdate, connectfrom, helofrom, relaypresip, mxnum, mxesthatreject, mxesthataccept, mxesoutoforder, mxesthattempfail, gracefuldns, whitelisted, resolvedrelayip, receivinghost, envfrom, action, reverserelay, fakerelay) values('%s','%s','%s','%s',%d,%d,%d,%d,%d,%s,%s,'%s','%s','%s', '%s',%d,%d)";
#endif
    char *pgStat = NULL;
    int wantedSize = 0;
    int wantedTimeSize = 0;
    char *curTimePres = NULL;
    char *curTimePresFormat = "%.2d/%.2d/%d %.2d:%.2d:%.2d";
    int curYear, curMonth;
    time_t now;
    char whitelistedBool[6];
    char gracefulDNSBool[6];
    int pgConnId;
    struct tm *curTime;
    char tmpLog[MAXLOGLINE];
    
    void
    intToStrBool (int intBool, char *boolContainer, int boolContainerSize, struct mlfiPriv *privData) {
	logNow("Entered intToStrBool().", 3, privData);
	bzero(boolContainer, boolContainerSize);
	if (intBool == 1) {
    	    strncpy(boolContainer, "true", boolContainerSize);
	} else {
    	    strncpy(boolContainer, "false", boolContainerSize);
	}
    }
	
    logNow("Entered pushHistory().", 3, privData);
	
    pgConnId = getPgConn();
	
    now = time(NULL);
    curTime = localtime(&now);
    curYear = curTime->tm_year + 1900;
    curMonth = curTime->tm_mon + 1;
    wantedTimeSize = snprintf(curTimePres, 0, curTimePresFormat, 
    		curMonth, curTime->tm_mday, curYear, 
		curTime->tm_hour, curTime->tm_min, curTime->tm_sec);
    wantedTimeSize++;
    curTimePres = malloc(wantedTimeSize);
    if (curTimePres == NULL) {
        logNow("Cannot allocate memory.", 0, privData);
        exit(EXIT_FAILURE);
    }
    bzero(curTimePres, wantedTimeSize);
    snprintf(curTimePres, wantedTimeSize, curTimePresFormat, 
    		curMonth, curTime->tm_mday, curYear, 
    		curTime->tm_hour, curTime->tm_min, curTime->tm_sec);
    snprintf(tmpLog, MAXLOGLINE, "Aquired current date, %s.", curTimePres);
    logNow(&tmpLog[0], 3, privData);
    logNow("Trying to get the size needed for DML statement.", 3, privData);
    snprintf(tmpLog, MAXLOGLINE, "Sample of milter data [connectfrom]: \"%s\".", privData->mcfi_connectfrom);
    logNow(&tmpLog[0], 3, privData);
    snprintf(tmpLog, MAXLOGLINE, "Sample of milter data [helofrom]: \"%s\".", privData->mcfi_helofrom);
    logNow(&tmpLog[0], 3, privData);
    intToStrBool(privData->whitelisted, &whitelistedBool[0], 6, privData);
    intToStrBool(privData->gracefulDNS, &gracefulDNSBool[0], 6, privData);
    wantedSize = snprintf(pgStat, 0, pgStatFormat,
    			curTimePres, privData->mcfi_connectfrom, 
    			privData->mcfi_helofrom, privData->relayPresIP, privData->MXesNum, 
    			privData->MXesThatReject, privData->MXesThatAccept, privData->MXesOutOfOrder, 
    			privData->MXesThatTempfail, gracefulDNSBool,
#ifdef WITH_SPF
    			whitelistedBool, privData->resolvedRelayIP, myHostName, formattedEmail, action, privData -> SPFResult, privData -> reverseRes, privData -> fakeRes);
#else
			whitelistedBool, privData->resolvedRelayIP, myHostName, formattedEmail, action, privData -> reverseRes, privData -> fakeRes);
#endif
    wantedSize++;
    snprintf(tmpLog, MAXLOGLINE, "Got the size needed for DML statement, it's %d.", wantedSize);
    logNow(&tmpLog[0], 3, privData);
    pgStat = malloc(wantedSize);
    bzero(pgStat, wantedSize);
    if (pgStat == NULL) {
        logNow("Cannot allocate memory.", 0, privData);
        exit(EXIT_FAILURE);
    }
    snprintf(pgStat, wantedSize, pgStatFormat,
    			curTimePres, privData->mcfi_connectfrom, 
    			privData->mcfi_helofrom, privData->relayPresIP, privData->MXesNum, 
    			privData->MXesThatReject, privData->MXesThatAccept, privData->MXesOutOfOrder, 
    			privData->MXesThatTempfail, gracefulDNSBool,
#ifdef WITH_SPF
    			whitelistedBool, privData->resolvedRelayIP, myHostName, formattedEmail, action, privData -> SPFResult, privData -> reverseRes, privData -> fakeRes);
#else
			whitelistedBool, privData->resolvedRelayIP, myHostName, formattedEmail, action, privData -> reverseRes, privData -> fakeRes);
#endif
    snprintf(tmpLog, MAXLOGLINE, "Got the DML statement for insert: \"%s\".", pgStat);
    logNow(&tmpLog[0], 3, privData);
    
    connPool.pgResArr[pgConnId] = PQexec(connPool.pgConnArr[pgConnId], pgStat);
    if (PQresultStatus(connPool.pgResArr[pgConnId]) != PGRES_COMMAND_OK){
        snprintf(tmpLog, MAXLOGLINE, "INSERT command failed: %s", PQerrorMessage(connPool.pgConnArr[pgConnId]));
        logNow(&tmpLog[0], 0, privData);
        snprintf(tmpLog, MAXLOGLINE, "The result status is: %s",PQresStatus(PQresultStatus(connPool.pgResArr[pgConnId])));
        logNow(&tmpLog[0], 0, privData);
        PQclear(connPool.pgResArr[pgConnId]);
        return 1;
    }
    privData->SQLlogged = 1;
    PQclear(connPool.pgResArr[pgConnId]);
    /* freeing lock */
    unlockPgConn(pgConnId);
    
    logNow("Trying to free pgStat in pushHistory().", 3, privData);
    free(pgStat);
    logNow("Trying to free curTimePres in pushHistory().", 3, privData);
    free(curTimePres);
    return 0;
}
#endif
