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

#include <milter-callback.h>
#include <commonprocs.h>
#include <mcspf.h>

extern int logLevel;
extern int mcDebug;
extern SPF_server_t *SPFServer;

SPF_server_t *
createSPFServer () {
    SPF_server_t *SPFServer = NULL;
    
    logNow("Creating SPF server.", 3, 0);
    SPFServer = SPF_server_new(SPF_DNS_CACHE, 0);
    
    if (SPFServer == NULL) {
        logNow("Cannot allocate memory.", 0, 0);
	exit(EXIT_FAILURE);
    }
    return(SPFServer);
}

SPF_result_t
goWithSPF (struct mlfiPriv *privData, char *envFrom) {
    SPF_request_t *SPFRequest;
    SPF_response_t *SPFResponse;
    SPF_result_t SPFResult;
    int errorCount;
    char tmpLog[MAXLOGLINE];
    
    errorCount = 0;
    
    logNow("Entered goWithSPF().", 3, privData);
    snprintf(tmpLog, MAXLOGLINE, "Got %s as envFrom.", envFrom);
    logNow(&tmpLog[0], 3, privData);
    /* if we got an empty HELO/EHLO we return SPF_RESULT_SOFTFAIL */
    if (privData -> mcfi_helofrom == NULL) {
	logNow("Got empty HELO, skipping SPF check.", 0, privData);
	return(SPF_RESULT_SOFTFAIL);
    }
    
    logNow("Setting SPF IP.", 3, privData);

    logNow("Creating SPF request.", 3, privData);    
    SPFRequest = SPF_request_new(SPFServer);
    
    snprintf(tmpLog, MAXLOGLINE, "Setting SPF IP to %s.", privData -> relayPresIP);
    logNow(&tmpLog[0], 3, privData);
    if (SPF_request_set_ipv4_str(SPFRequest, privData -> relayPresIP)){
        logNow("Error setting SPF IP.", 0, privData);
	errorCount++;
    }
    snprintf(tmpLog, MAXLOGLINE, "Setting SPF HELO to %s.", privData -> mcfi_helofrom);
    logNow(&tmpLog[0], 3, privData);
    if (SPF_request_set_helo_dom(SPFRequest, privData -> mcfi_helofrom)){
        logNow("Error setting SPF HELO.", 0, privData);
	errorCount++;
    }
    snprintf(tmpLog, MAXLOGLINE, "Setting SPF envelope-from to %s.", envFrom);
    logNow(&tmpLog[0], 3, privData);
    if (SPF_request_set_env_from(SPFRequest, envFrom)){
        logNow("Error setting SPF envelope-from.", 0, privData);
	errorCount++;
    }
    logNow("Trying to get SPF response.", 3, privData);
    SPF_request_query_mailfrom(SPFRequest, &SPFResponse);
    SPFResult = SPF_response_result(SPFResponse);
    
    snprintf(tmpLog, MAXLOGLINE, "Got SPF result: %s:%s,%s,%s.", 
	SPF_strresult(SPF_response_result(SPFResponse)),
	SPF_response_get_smtp_comment(SPFResponse),
	SPF_response_get_header_comment(SPFResponse),
	SPF_response_get_received_spf(SPFResponse)
    );
    logNow(&tmpLog[0], 2, privData);
    
    if (errorCount == 0) {
        logNow("Trying to free() SPFResponse.", 3, privData);
	SPF_response_free(SPFResponse);
        logNow("Trying to free() SPFRequest.", 3, privData);
	SPF_request_free(SPFRequest);
    }
    return(SPFResult);
}

void
destroySPFServer () {    
    logNow("Freeing SPF server.", 3, 0);
    SPF_server_free(SPFServer);    
}

#endif
