All pastes #1293016 Raw Edit

Stuff

public text v1 · immutable
#1293016 ·published 2008-12-24 14:50 UTC
rendered paste body
/*
 * Asterisk -- A telephony toolkit for Linux.
 *
 * MCC - Termination Edition  application
 * 
 * Copyright (C) 2005, Mindaugas Kezys, Upnet
 *
 * $Id: app_mcc2.c,v 1.4.5
 *
 * TODO:
 *
 * check credit right before updating it and kill all other user's calls if new credit <=0 (how to do this?)
 *
 * 
 * This program is free software, distributed under the terms of
 * the GNU General Public License
 *
 */

/*
    HANGUP_CAUSE Error Codes:
    
    NO_DB_ACCESS
    DB_FATAL_ERROR
    NO_USER_FOUND    
    LOW_CREDIT
    BAD_DESTINATION
    CANT_FREEZE_CREDIT
    BLOCKED

*/


//        ast_log(LOG_WARNING,"mes cia'\n");

#include <asterisk/lock.h>
#include <stdio.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/app.h>
#include <asterisk/say.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <math.h>

#include <asterisk/config.h>
#include <libpq-fe.h>

#include <asterisk/translate.h>
#include <asterisk/features.h>
#include <asterisk/musiconhold.h>
#include <asterisk/callerid.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <asterisk/options.h>

#define DATE_FORMAT "%Y-%m-%d"
#define TIME_FORMAT "%T"

static char *tdesc = "MCC2 - Calling Application for Authorization and Accounting";

static char *app = "mcc2";

static char *config = "mcc2.conf";

static char *synopsis = "MCC2 - Authorization, Calling and Accounting";

static char *descrip =
" Prepaid/postpaid calling application\n"
" Finds user (checks the credit) and calls destination (if it's enough)\n"
" Updates DB and allows simultaneus calls.\n";

static char *pghostname = NULL, *pgdbname = NULL, *pgdbuser = NULL, *pgpassword = NULL, *pgdbsock = NULL, *pgdbport = NULL, *min_frozen = NULL, *frozen_time = NULL, *pround_sec = NULL;
static int hostname_alloc = 0, dbname_alloc = 0, dbuser_alloc = 0, password_alloc = 0, dbsock_alloc = 0, dbport_alloc = 0, min_frozen_alloc = 0, frozen_time_alloc = 0, pround_sec_alloc = 0;
static int connected = 0; /* Initially not connected to the DB */

PGconn *conn;
ast_mutex_t postgreslock;

STANDARD_LOCAL_USER;

LOCAL_USER_DECL;

struct calldata {

    char accountcode[30];
    char user_id[20];
    char tariff_id[20];
    char credit[20];
    char credit_frozen[20];
    char connection_fee[20];    
    char rate_connection_fee[20];

    char min_time[20];
    char increment[20];

    char hangup_cause[20];
    
    char destination[30];
    char prefix[30];
    char tech[100];
    char rate[20];

    char enable_cid_prefix[20];
    char disable_cid_prefix[20];
    char enable_cid_to_provider[20];

    int credit_to_freeze;
    int timeout;

    char date[20];
    char time[20];
    char source[30];

    char cid[20];
    char postpaid[20];

    char blocked[20];

};

int SHOW_NOTICE;
int SHOW_ERROR;
int SHOW_WARNING;

int ROUND_TIME;

int ROUND_TO;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

// SHOW_NOTICE = atoi(pshow_notice);


/* Checks if we are connected to the db - if not then it tries to reconnect */
static int db_check_connected(void)
{
        int i;
        PGresult *result;

        if (connected) {
                /* seems that we are connected - but let us check that */
                for (i=0; i<3; i++) {
                        /* PQstatus is not working as expected - so we are trying a query before PQstatus - hope that helps */
			ast_mutex_lock(&postgreslock);                        
			result = PQexec(conn, "SELECT 1");
    			ast_mutex_unlock(&postgreslock);
                        PQclear(result);
                        if (PQstatus(conn) == CONNECTION_BAD) {
                                /* seems that we are having troubles with the connection - trying to reset the connection */
                                /* and set connected to false */
                                connected = 0;
                                if (SHOW_ERROR) ast_log(LOG_ERROR, "app_mcc2: connection to database server '%s' is broken - I will try to reconnect (up to) 3 times\n", pghostname);
                                PQreset(conn);
                                /* retry it up to 3 times */
                                continue;
                        } else {
                                /* Everything is fine - so go on */
                                connected = 1;
                                break;
                        }
                }
        } else {
                /* We are not connected - so make the initial connection */
                conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword);
                if (PQstatus(conn) != CONNECTION_BAD) {
                        ast_log(LOG_DEBUG, "app_mcc2: Succesfully connected to database '%s'.\n", pgdbname);
                        connected = 1;
                } else {
                        if (SHOW_ERROR) ast_log(LOG_ERROR, "app_mcc2: FATAL - Couldn't connect to database server '%s'. \n", pghostname);
                        connected = 0;
                }
        }
        return connected;
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////


static int mcc2_ivr_authorize(struct ast_channel *chan, struct calldata *cd, int aaskext, void *data)
{
    int res=0;
    int got_account_code=0;
    char sqlcmd[2048] = "";
    PGresult *result;
    int total_frozen_credit;
    char cust_rate[10] = "";


    struct tm tm;
    struct timeval tv;
    time_t t;

    //------------------

    strcpy(cd->rate,"0");
    strcpy(cd->credit_frozen,"0");    
    strcpy(cd->connection_fee,"0");        
    strcpy(cd->min_time,"0");
    strcpy(cd->increment,"0");

    strcpy(cd->rate_connection_fee,"0");

    strcpy(cd->hangup_cause,"");
    strcpy(cd->cid,"");    

    strcpy(cd->enable_cid_prefix,"");    
    strcpy(cd->disable_cid_prefix,"");    
    strcpy(cd->enable_cid_to_provider,"t");    

    //date-time
    gettimeofday(&tv, NULL);
    t=tv.tv_sec;
    localtime_r(&t, &tm);
    strftime(cd->date, 128, DATE_FORMAT, &tm);
    strftime(cd->time, 128, TIME_FORMAT, &tm);
    if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Date: %s, time: %s\n", cd->date, cd->time);


    //ast_log(LOG_WARNING,"1\n");
    //source
    strcpy(cd->source,chan->cdr->src);
    //strncpy(cd->source,chan->cdr->src, strlen(chan->cdr->src));
    //ast_log(LOG_WARNING,"2\n");

    if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Source: %s\n", cd->source);
    
    //destination

    //ast_log(LOG_WARNING,"AUTHORIZE -  data; '%s',  aaskext; '%i'\n", data, aaskext);
    strcpy(cd->destination,data);
    if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Destination: %s\n", cd->destination);

    //accountcode
    strcpy(cd->accountcode,chan->accountcode);
    if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Accountcode: %s\n", cd->accountcode);
    
    //check if we are connected to db
    if (!db_check_connected()){
	strcpy(cd->hangup_cause,"NO_DB_ACCESS");
	strcpy(cd->user_id,"0");
	res = -1;
    }

    //check if accountcode not empty
    if ((!res)&&(!strlen(cd->accountcode))) {
        if (SHOW_WARNING) ast_log(LOG_WARNING,"app_mcc2: ERROR: Empty accountcode!\n");
	//send mail to me with same message, play some excuse audio to user
        //res = ast_streamfile(chan, "prepaid-dest-unreachable", chan->language);  if (!res) res = ast_waitstream(chan, "");
        res = -1;
    } 

    //-------- Looking for accountcode in 'users' table ----------------

    if (!res){    

	sprintf(sqlcmd,"SELECT id, tariff_id, credit, credit_frozen, postpaid, blocked, connection_fee, min_time, increment FROM users WHERE users.id = '%s'", cd->accountcode);

	ast_mutex_lock(&postgreslock);	
	result = PQexec(conn, sqlcmd);
	ast_mutex_unlock(&postgreslock);

        if (PQresultStatus(result) != PGRES_TUPLES_OK) {
            if (SHOW_ERROR) {
		ast_log(LOG_ERROR,"app_mcc2: FATAL ERROR 4: %s\n", PQresultErrorMessage(result));
		ast_log(LOG_ERROR,"app_mcc2: FATAL ERROR 4: is your accountcode a number???\n");
	    }
	      //send mail to me with same message, play some excuse audio to user
              //res = ast_streamfile(chan, "prepaid-no-aaa", chan->language);
            //if (!res) res = ast_waitstream(chan, "");
            res = -1;
        } else {
	    if(PQntuples(result)<=0) {
    		if (SHOW_WARNING) ast_log(LOG_WARNING,"app_mcc2: WARNING: User with accountcode '%s' not found in database\n", cd->accountcode);
		//send mail to me with same message, play some excuse audio to user
    		//res = ast_streamfile(chan, "prepaid-dest-unreachable", chan->language);  if (!res) res = ast_waitstream(chan, "");
    		res = -1;
	    } 
	} 
    	
    //retrieving user data
        if (!res){
	    strcpy(cd->user_id,   	PQgetvalue(result,0,0));
    	    strcpy(cd->tariff_id, 	PQgetvalue(result,0,1));
    	    strcpy(cd->credit, 		PQgetvalue(result,0,2));
    	    strcpy(cd->credit_frozen, 	PQgetvalue(result,0,3));	
    	    strcpy(cd->postpaid, 	PQgetvalue(result,0,4));		    
    	    strcpy(cd->blocked, 	PQgetvalue(result,0,5));
    	    strcpy(cd->connection_fee, 	PQgetvalue(result,0,6)); 
    	    strcpy(cd->min_time, 	PQgetvalue(result,0,7));
    	    strcpy(cd->increment, 	PQgetvalue(result,0,8)); 
    	    if (SHOW_NOTICE)  ast_log(LOG_NOTICE,"app_mcc2: User's data retrieved by accountcode: user_id: %s, tariff_id: %s, credit: %s, credit_frozen: %s, postpaid: %s, connection_fee: %s, min_time: %s, increment: %s\n", cd->user_id, cd->tariff_id, cd->credit, cd->credit_frozen, cd->postpaid, cd->connection_fee, cd->min_time, cd->increment);	

	    got_account_code = 1;
	} 
        PQclear(result);
    }

    //---------------------- no account code, looking at cid --------------------------

    //+++++++++++++++++++++++++++++++++++++++++
    //----Post 1.2----
//    if (chan->cid.cid_num) strncpy(cd->cid,chan->cid.cid_num, strlen(chan->cid.cid_num));
    if (chan->cid.cid_num) strcpy(cd->cid,chan->cid.cid_num);
    //----Prior 1.2------
    //if (cd->source) strcpy(cd->cid,cd->source);
    //+++++++++++++++++++++++++++++++++++++++++

    if (!got_account_code){    

	//search one more time
	res=0;
    

        if (SHOW_NOTICE) ast_log(LOG_NOTICE,"No account code, searching user by CID: %s\n", cd->cid);	    

	//---Taking user's data---


	sprintf(sqlcmd,"SELECT users.id, users.tariff_id, users.credit, users.credit_frozen, users.postpaid, users.blocked, users.connection_fee, cids.enable_to_provider, users.min_time, users.increment FROM users INNER JOIN cids ON users.id=cids.user_id WHERE cids.cid='%s'", cd->cid);

	ast_mutex_lock(&postgreslock);	
	result = PQexec(conn, sqlcmd);
	ast_mutex_unlock(&postgreslock);

        if (PQresultStatus(result) != PGRES_TUPLES_OK) {
            if (SHOW_ERROR) ast_log(LOG_ERROR,"app_mcc2: FATAL ERROR 4: %s\n", PQresultErrorMessage(result));
	      //send mail to me with same message, play some excuse audio to user
              //res = ast_streamfile(chan, "prepaid-no-aaa", chan->language);
            //if (!res) res = ast_waitstream(chan, "");
	    strcpy(cd->hangup_cause,"DB_FATAL_ERROR");
	    strcpy(cd->user_id,"0");
            res = -1;
        } else {
	    if(PQntuples(result)<=0) {
    		if (SHOW_WARNING) ast_log(LOG_WARNING,"app_mcc2: WARNING: User with cid %s not found in database\n", cd->cid);
		//send mail to me with same message, play some excuse audio to user
    		res = ast_streamfile(chan, "prepaid-auth-fail", chan->language);  
		if (!res) res = ast_waitstream(chan, "");
		strcpy(cd->hangup_cause,"NO_USER_FOUND");
		strcpy(cd->user_id,"0");
    		res = -1;
	    } 
	} 
    	
        //retrieving user data
        if (!res){
	    strcpy(cd->user_id,   	PQgetvalue(result,0,0));
    	    strcpy(cd->tariff_id, 	PQgetvalue(result,0,1));
    	    strcpy(cd->credit, 		PQgetvalue(result,0,2));
    	    strcpy(cd->credit_frozen, 	PQgetvalue(result,0,3));	
    	    strcpy(cd->postpaid, 	PQgetvalue(result,0,4));
    	    strcpy(cd->blocked, 	PQgetvalue(result,0,5));
    	    strcpy(cd->connection_fee, 	PQgetvalue(result,0,6)); 
    	    strcpy(cd->enable_cid_to_provider, 	PQgetvalue(result,0,7)); 	    
    	    strcpy(cd->min_time, 	PQgetvalue(result,0,8)); 
    	    strcpy(cd->increment, 	PQgetvalue(result,0,9)); 	    
    	    if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: User's data retrieved by cid: user_id: %s, tariff_id: %s, credit: %s, credit_frozen: %s, postpaid: %s, connection_fee: %s, enable_cid_to_provider: %s, min_time: %s, increment: %s\n", cd->user_id, cd->tariff_id, cd->credit, cd->credit_frozen, cd->postpaid, cd->connection_fee, cd->enable_cid_to_provider, cd->min_time, cd->increment);	
	} 
        PQclear(result);

    
    }
    //-------------------------------- end checking cid -------------------------------


    //-------------------------------- process for prepaid users ----------------------

    if (!strcmp("f", cd->postpaid)) {
	//if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Processing credit for prepaid users\n");	
    

	//check credit
	if ((!res)&&(atof(cd->credit) <= 0)) {
	    if (SHOW_WARNING) ast_log(LOG_WARNING,"app_mcc2: Low credit for user with account: %s\n", cd->accountcode);	
    	    res = ast_streamfile(chan, "prepaid-credit-low", chan->language);  
	    if (!res) res = ast_waitstream(chan, "");	
	    strcpy(cd->hangup_cause,"LOW_CREDIT");
	    res = -1;
        }	    

        //check frozen credit
        if ((!res) && (atof(cd->credit)-atoi(cd->credit_frozen) < atoi(min_frozen)) && (atoi(cd->credit_frozen)) ){
    	    if (SHOW_WARNING) ast_log(LOG_WARNING,"app_mcc2: Too low credit for more simultaneus calls\n");	    
	    res = ast_streamfile(chan, "prepaid-credit-low", chan->language);  
	    if (!res) res = ast_waitstream(chan, "");	
	    strcpy(cd->hangup_cause,"LOW_CREDIT");
    	    res = -1;
	}
    }

    //-------------------------------- end processing for prepaid users ---------------




    //------------------------------------ BLOCKING users -----------------------------
    

    if (!strcmp("t", cd->blocked)) { 
    	    if (SHOW_WARNING) ast_log(LOG_WARNING,"app_mcc2: This user is BLOCKED!!!\n");	    
	    res = ast_streamfile(chan, "prepaid-blocked", chan->language);  
	    if (!res) res = ast_waitstream(chan, "");	
	    strcpy(cd->hangup_cause,"BLOCKED");
    	    res = -1;
    }

    //---------------------------------- stop blocking users --------------------------



    //-------------------------------- asking for extension if needed -----------------
    if ((!res)&&(aaskext)) {
    
	if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Asking for extension.\n");	    
    
	res = ast_app_getdata(chan, "prepaid-enter-dest", cd->destination, sizeof(cd->destination)-2,0);
	if (res < 0) res = -1; 

	ast_log(LOG_DEBUG,"app_mcc2: destination's length: %i, res = %i\n",strlen(cd->destination), res);	
//	if (strlen(cd->destination)<5) {
//	    strcpy(cd->hangup_cause,"BAD_DESTINATION");
//	    res = -1;
//	}

    }
    //-------------------------------- end asking for extension -----------------------




    //looking for most compatible destination and take tech/rate
    if (!res){    

	sprintf(sqlcmd,"SELECT destinations.prefix, providers.tech, rates.rate, providers.enable_cid_prefix, providers.disable_cid_prefix, rates.connection_fee FROM destinations, providers, rates WHERE destinations.prefix=SUBSTRING('%s', 0, LENGTH(destinations.prefix)+1) AND destinations.provider_id = providers.id AND destinations.prefix = rates.prefix AND rates.tariff_id = '%s' ORDER BY LENGTH(destinations.prefix) DESC LIMIT 1", cd->destination, cd->tariff_id);

	ast_mutex_lock(&postgreslock);
	result = PQexec(conn, sqlcmd);
	ast_mutex_unlock(&postgreslock);

        if (PQresultStatus(result) != PGRES_TUPLES_OK) {
            if (SHOW_ERROR) ast_log(LOG_ERROR,"app_mcc2: FATAL ERROR 4: %s\n", PQresultErrorMessage(result));
	    //send mail to me with same message, play some excuse audio to user
            res = ast_streamfile(chan, "prepaid-no-aaa", chan->language);
            if (!res) res = ast_waitstream(chan, "");
	    strcpy(cd->hangup_cause,"DB_FATAL_ERROR");
	    strcpy(cd->user_id,"0");
            res = -1;
        } else {
	    if(PQntuples(result)<=0) {
    		if (SHOW_WARNING) ast_log(LOG_WARNING,"app_mcc2: ERROR: Could not find prefix for destination %s\n", cd->destination);
		//send mail to me with same message!!! BIG PRIORITY, play some excuse audio to user
    		res = ast_streamfile(chan, "prepaid-dest-unreachable", chan->language);  
		if (!res) res = ast_waitstream(chan, "");
		strcpy(cd->hangup_cause,"BAD_DESTINATION");
    		res = -1;
	    } 
	} 

	//retrieving destination data
	if (!res){
          strcpy(cd->prefix,	   	PQgetvalue(result,0,0));
          strcpy(cd->tech,	 	PQgetvalue(result,0,1));
          strcpy(cd->rate, 		PQgetvalue(result,0,2));
          strcpy(cd->enable_cid_prefix,	PQgetvalue(result,0,3));
          strcpy(cd->disable_cid_prefix,PQgetvalue(result,0,4));
          strcpy(cd->rate_connection_fee,PQgetvalue(result,0,5));	  
    	  if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Destination's data retrieved: prefix: %s, tech: %s, rate: %s, enable_cid_prefix: %s, disable_cid_prefix: %s, rate_connection_fee: %s\n", cd->prefix, cd->tech, cd->rate, cd->enable_cid_prefix, cd->disable_cid_prefix, cd->rate_connection_fee);	
	} 

	PQclear(result);
    }


    //-------------------------------- modify CALLERID NUMBER ----------------------
    char buf[100] = "";

    if (!strcmp(cd->enable_cid_to_provider,"t")) 
	snprintf(buf, sizeof(buf), "%s%s", cd->enable_cid_prefix, cd->cid);
    else
	snprintf(buf, sizeof(buf), "%s%s", cd->disable_cid_prefix, cd->cid);
	
    pbx_builtin_setvar_helper(chan, "CALLERID(num)", buf);
    //-------------------------------------------------------------------------
					    



    // timeout for postpaid users (2h)
    cd->timeout = 72000;


    //-------------------------------- checking for custom rates ----------------------

    if (!res){    

	sprintf(sqlcmd,"SELECT rate FROM cust_rates WHERE prefix='%s' AND user_id = '%s'", cd->prefix, cd->user_id);

	ast_mutex_lock(&postgreslock);
	result = PQexec(conn, sqlcmd);
	ast_mutex_unlock(&postgreslock);

        if (PQresultStatus(result) != PGRES_TUPLES_OK) {
            if (SHOW_ERROR) ast_log(LOG_ERROR,"app_mcc2: FATAL ERROR 4: %s\n", PQresultErrorMessage(result));
	    //send mail to me with same message, play some excuse audio to user
            res = ast_streamfile(chan, "prepaid-no-aaa", chan->language);
            if (!res) res = ast_waitstream(chan, "");
	    strcpy(cd->hangup_cause,"DB_FATAL_ERROR");
	    strcpy(cd->user_id,"0");
            res = -1;
        } else {
	    if(PQntuples(result)<=0) {  //cust rate not found
    		if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Custom rate for prefix: '%s' not found.\n", cd->prefix);
	    } else { //cust rate found
	        strcpy(cust_rate, PQgetvalue(result,0,0));
    		if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Custom rate fot prefix: '%s' FOUND! Custom rate: %s\n", cd->prefix, cust_rate);
    		if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Primary rate: %s changed to custom rate: %s\n", cd->rate, cust_rate);
	        strcpy(cd->rate, cust_rate);    
	    } 
	}

	PQclear(result);
    }



    //-------------------------------- process for prepaid users ----------------------

    if (!strcmp("f", cd->postpaid)) {
	//if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Processing credit for prepaid users\n");	

	//freezing credit
	if (!res) {
    
	    cd->credit_to_freeze = ceilf( atof(cd->rate)* atoi(frozen_time) );
	    cd->timeout = floorf(atoi(cd->credit) / atof(cd->rate) *60);
	    if (cd->credit_to_freeze > (atof(cd->credit) - atoi(cd->credit_frozen))) { 
		cd->credit_to_freeze = (atof(cd->credit) - atoi(cd->credit_frozen));
	    }

	    if (cd->timeout <0 ) cd->timeout = 72000;
            if (cd->timeout == 0 ) res = -1;
	    
	    if (!res){

		if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Frozen credit time: %s minutes, credit to freeze: %i ct(EUR), timeout: %i s\n", frozen_time, cd->credit_to_freeze, cd->timeout);    

		//update users.credit_frozen
		total_frozen_credit = atoi(cd->credit_frozen) + cd->credit_to_freeze;
		if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Total frozen credit:  %i\n", total_frozen_credit);

    		sprintf(sqlcmd,"UPDATE users SET credit_frozen='%i' WHERE users.id='%s'", total_frozen_credit ,cd->user_id);
		ast_mutex_lock(&postgreslock);
		result = PQexec(conn, sqlcmd);
		ast_mutex_unlock(&postgreslock);	
		PQclear(result);
	    } else {
                if (SHOW_WARNING) ast_log(LOG_WARNING,"app_mcc2: Too low credit for more simultaneus calls\n");
                res = ast_streamfile(chan, "prepaid-credit-low", chan->language);
                if (!res) res = ast_waitstream(chan, "");
                strcpy(cd->hangup_cause,"LOW_CREDIT");
                res = -1;
	    }
	}
    }

    //-------------------------------- end processing for prepaid users ---------------


    return res;
//
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

static int mcc2_pbx_dial(struct ast_channel *chan, void *data)
{
    struct ast_app *app;
    int ret;

    app = pbx_findapp("Dial");
    if (app) {
        ret = pbx_exec(chan, app, data, 1);
    } else {
        if (SHOW_WARNING) ast_log(LOG_WARNING, "Could not find application (Dial)\n");
        ret = -2;
    }

    //if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: HANGUP CAUSE: %s\n", ast_cdr_disp2str(chan->cdr->disposition));

    return ret;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

static int mcc2_acct_stop(struct ast_channel *chan, struct ast_cdr *cdr, struct calldata *cd)
{

    int res=0;
    int billsec;
    int round_sec;
    int icredit;
    float price;
    char sqlcmd[2048] = "";
    PGresult *result;
    float new_credit = 0, new_frozen_credit = 0;

    //hangup_cause
    if (!strlen(cd->hangup_cause)) {strcpy(cd->hangup_cause,ast_cdr_disp2str(cdr->disposition));}

//    if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Destination: %s\n", cd->destination);
    if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: HANGUP CAUSE: %s\n", ast_cdr_disp2str(cdr->disposition));

    //billsec
    ast_cdr_end(cdr);

    if (!cdr->end.tv_sec && !cdr->end.tv_usec)
        if (SHOW_WARNING) ast_log(LOG_WARNING, "app_mcc2: CDR on channel '%s' lacks end\n", cdr->channel);
    if (!cdr->start.tv_sec && !cdr->start.tv_usec)
        if (SHOW_WARNING) ast_log(LOG_WARNING, "app_mcc2: CDR on channel '%s' lacks start\n", cdr->channel);
    cdr->duration = cdr->end.tv_sec - cdr->start.tv_sec + (cdr->end.tv_usec - cdr->start.tv_usec) / 1000000;
    if (cdr->answer.tv_sec || cdr->answer.tv_usec) {
        cdr->billsec = cdr->end.tv_sec - cdr->answer.tv_sec + (cdr->end.tv_usec - cdr->answer.tv_usec) / 1000000;
    } else
        cdr->billsec = 0;
    if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Seconds to bill: %i\n", cdr->billsec);

    //some bug fixing
//    if (((atof(cd->rate)==0)||(cdr->billsec ==0))&&(!strcmp(cd->hangup_cause,"ANSWERED"))) {strcpy(cd->hangup_cause,"NO ANSWER");}
    if ((cdr->billsec ==0)&&(!strcmp(cd->hangup_cause,"ANSWERED"))) {strcpy(cd->hangup_cause,"NO ANSWER");}

    if (!strcmp(cd->hangup_cause,"ANSWERED")){

	//round bill time (increment)
	round_sec = atoi(cd->increment);//atoi(pround_sec);    
	if (!(cdr->billsec % round_sec)){  
	    billsec = ceilf(cdr->billsec / round_sec)*round_sec;
	} else {  
	    billsec = (ceilf(cdr->billsec / round_sec)+1)*round_sec;
	}

	//if time less than xxx then time=xxx (min_time)
	//if ((ROUND_TIME)&&(billsec<ROUND_TIME)) billsec=ROUND_TIME;
	if ((cd->min_time)&&(billsec < atoi(cd->min_time))) billsec=atoi(cd->min_time);

	//calculate price for the call

	if (ROUND_TO == 1) {price = ceilf( (atof(cd->rate)* billsec)/6 )/10; } else
    	    if (ROUND_TO == 2) {price = ceilf( (atof(cd->rate)* billsec)/0.6)/100; }else	
    	        {price = (atof(cd->rate)* billsec)/60 ;}  // round to 0

	//adding connection fee
	price += atof(cd->connection_fee) + atof(cd->rate_connection_fee);

	//ast_log(LOG_NOTICE,"ROUND_TO: %i, PRICE: %f\n", ROUND_TO, price);


    } else {
	billsec = 0;
	price = 0;    
    }
    if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Rounded seconds to bill: %i\n", billsec);
    if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Price for the call: %f (connection fee: %s and rate_connectio_fee %s included)\n", price, cd->connection_fee, cd->rate_connection_fee);


    //update table 'calls'
    sprintf(sqlcmd,"INSERT INTO calls (user_id, date, time, src, dst, hangup_cause, billsec, price, rate, user_connection_fee, rate_connection_fee) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%i', '%f', '%s', '%s', '%s')", cd->user_id, cd->date, cd->time, cd->source, cd->destination, cd->hangup_cause, billsec, price, cd->rate, cd->connection_fee, cd->rate_connection_fee);
    //if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: SQL command as follows:  %s\n",sqlcmd);
    ast_mutex_lock(&postgreslock);
    result = PQexec(conn, sqlcmd);
    ast_mutex_unlock(&postgreslock);	
    PQclear(result);
    
    //msg to console about call status
    ast_log(LOG_NOTICE,"User ID: %s, src: %s, dst: %s, hangup: %s, time: %i, rate: %s, price: %f\n",cd->user_id, cd->source, cd->destination, cd->hangup_cause, billsec, cd->rate, price);

    //--------- if we have user and he is prepaid user, then ..... -----------------

    if ((strcmp(cd->user_id,"0"))&&(!strcmp("f", cd->postpaid))){
        
	//get credit, credit_frozen
	//update credit, credit_frozen
	sprintf(sqlcmd,"SELECT credit, credit_frozen FROM users WHERE users.id = '%s'", cd->user_id);

	ast_mutex_lock(&postgreslock);	
	result = PQexec(conn, sqlcmd);
	ast_mutex_unlock(&postgreslock);

	if (PQresultStatus(result) != PGRES_TUPLES_OK) {
    	    if (SHOW_ERROR) ast_log(LOG_ERROR,"app_mcc2: FATAL ERROR 4: %s\n", PQresultErrorMessage(result));
    	    //send mail to me with same message, play some excuse audio to user
    	    res = ast_streamfile(chan, "prepaid-no-aaa", chan->language);
    	    if (!res) res = ast_waitstream(chan, "");
	    strcpy(cd->hangup_cause,"DB_FATAL_ERROR");
    	    res = -1;
	} else {
	    if(PQntuples(result)<=0) {
    		if (SHOW_ERROR) ast_log(LOG_ERROR,"app_mcc2: ERROR: User with accountcode %s not found in database\n", cd->accountcode);
		//send mail to me with same message, play some excuse audio to user
    		res = ast_streamfile(chan, "prepaid-auth-fail", chan->language);  
		if (!res) res = ast_waitstream(chan, "");
		strcpy(cd->hangup_cause,"NO_USER_FOUND");
    		res = -1;
	    } 
	} 

	//retrieving user data
	if (!res){
	    strcpy(cd->credit, 		PQgetvalue(result,0,0));
    	    strcpy(cd->credit_frozen, 	PQgetvalue(result,0,1));	
    	    if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: User's data retrieved: credit: %s, credit_frozen: %s\n", cd->credit, cd->credit_frozen);	
	} 
	PQclear(result);
    
	//calculate credit, credit_frozen
	new_credit = atof(cd->credit) - price;
	new_frozen_credit = atoi(cd->credit_frozen) - cd->credit_to_freeze;
	if ((new_frozen_credit<0)||(new_frozen_credit>new_credit)) new_frozen_credit=0;
	if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: New credit: %f, new credit_frozen: %f\n", new_credit, new_frozen_credit);	    

	//update db with new values
	icredit = round(new_frozen_credit);
	sprintf(sqlcmd,"UPDATE users SET credit='%f', credit_frozen='%i' WHERE users.id='%s'", new_credit, icredit ,cd->user_id);
	ast_mutex_lock(&postgreslock);
	result = PQexec(conn, sqlcmd);
	ast_mutex_unlock(&postgreslock);	
	PQclear(result);

    }
    //------------------- end user operations --------------------

    //no difference if we return error code
    return 0;
}




////////////////////////////////////////////////////////////////////////////////////////////////////////




static int mcc2_exec(struct ast_channel *chan, void *data)
{
	struct ast_cdr *cdr1; // Create local ast_cdr struct

	int res = 0;
	struct localuser *u;
	struct calldata cd;
	char dialstr[256] = "";
	char dialstr2[256] = "";	
	char destination2[256] = "";		
	int askext = 0;
	int nopickup = 0;   //channell will not be picked up
	int direct=0;		//provaider's tech will be taken from mcc argument
	char direct_tech[256] = "";	//tech for direct calling from mcc
	char temp_tech[256] = "";	//temp tech for original tech formating
	char cut[2] = ""; // how much to cut extension from provider's tech

	int f,l,e; //variables for dialstring formating

    	//if (strncmp(data,"askext",strlen(data))==0)  askext=1;
	if (strstr(data,"askext"))  askext=1;
	//debug
	//ast_log(LOG_WARNING,"data; '%s',  askext; '%i'\n", data, askext);

	if (strstr(data,"nopickup"))  nopickup=1;

        l=0;
	f=0;
	e=0;
	
	//taking tech from mcc argument
	if (strstr(data,"direct")){

	    strcpy(temp_tech, data);
    	    l=strlen(temp_tech);
	    f=l-strlen(strstr((temp_tech),"direct|"));
	    e=f+7;
	    
	    strcpy(direct_tech,"");
	    strcat(direct_tech,&temp_tech[e]);

	    ast_log(LOG_NOTICE,"Using tech from mcc: %s\n",direct_tech);
	    direct=1;	
	}

	//removing garbage
	if (strstr(data,"|")){	
    	    l=strlen(data);
	    f=l-strlen(strstr((data),"|"));	
	    strcpy(data,(char *)strndup(data,f));
	}

	LOCAL_USER_ADD(u);

	if ((chan->_state != AST_STATE_UP)&&(!nopickup)) {
    		if (SHOW_NOTICE)  ast_log(LOG_NOTICE,"Answering channel\n");
		res = ast_answer(chan);
		if (res) {
			LOCAL_USER_REMOVE(u);
			return -1;
		}
	}else{
    		if (SHOW_NOTICE)  ast_log(LOG_NOTICE,"NOT answering channel\n");	
	}

	//authorizing
        res = mcc2_ivr_authorize(chan, &cd, askext, data);

	cdr1 = (struct ast_cdr*) malloc(sizeof(struct ast_cdr));
        memcpy(cdr1,chan->cdr,sizeof(struct ast_cdr)); // Copy

	//dialing
	if (!res) {
            ast_cdr_reset(chan->cdr,0);
//            ast_cdr_reset(cdr1,0);
            //ast_channel_setwhentohangup(chan,cd.timeout);

	    //if direct calling, use right tech
	    if (direct==1) {strcpy(cd.tech, direct_tech);}

	    // format new dialstring
	    if (strstr((cd.tech),"EXTEN")){
	    
		// get cutting param
		if (strstr(cd.tech,"|")){	
		    l = strlen(cd.tech);
    		    f = l - strlen(strstr(cd.tech,"|")) + 1; 
		    strcpy(cut,"");
		    strcat(cut,&cd.tech[f]);
		    //ast_log(LOG_NOTICE,"cut: %s\n", cut);
		    
		    strcpy(cd.tech,(char *)strndup(cd.tech,f-1)); //trash the garbage
		}
	    
    		l=strlen(cd.tech);
		f=l-strlen(strstr((cd.tech),"EXTEN"));
		e=f+5;
	    
		strcpy(dialstr2,(char *)strndup(cd.tech,f));
	    
		//cut destination if necessary
		if (cut){
		    strcat(destination2,&cd.destination[atoi(cut)]);		
		    ast_log(LOG_NOTICE,"destination2: %s\n", destination2);
		} else {
		    strcpy(destination2,cd.destination);		
		}

		strcat(dialstr2,destination2);
		strcat(dialstr2,&cd.tech[e]);
	    }else { //adding extension at the end of provider
		strcpy(dialstr2,cd.tech);
		if (direct!=1) strcat(dialstr2,cd.destination);
	    }

//	    //strcat(dialstr2,cd.destination);	    

    	    if (SHOW_NOTICE)  ast_log(LOG_NOTICE,"Formating dialstring: length %i, first %i, last %i, string: %s\n", l,f,e,dialstr2);
	    // end format new dialstring

	    //adding timeout
	    strcpy(dialstr,dialstr2);
            sprintf(dialstr2,"||S(%d)tT", cd.timeout);
	    strcat(dialstr,dialstr2);


    	    if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: Dialing '%s' with timeout of '%d'.\n", dialstr, cd.timeout);
            res = mcc2_pbx_dial(chan, dialstr);
	}

    
    //    if (SHOW_NOTICE) ast_log(LOG_NOTICE,"app_mcc2: HANGUP CAUSE: %s\n", ast_cdr_disp2str(chan->cdr->disposition));


    	//res = 
	mcc2_acct_stop(chan, chan->cdr, &cd);
	
//        res = mcc2_acct_stop(chan, cdr1, &cd);
	free(cdr1); // Free memory
		  

	LOCAL_USER_REMOVE(u);

        if (SHOW_NOTICE) ast_log(LOG_NOTICE,"Application mcc2 started and ended succesfully, with end code: %i!\n", res);

//	res=0;

	return res;
}

int unload_module(void)
{
        STANDARD_HANGUP_LOCALUSERS;
        PQfinish(conn);
        connected = 0;
        if (pghostname && hostname_alloc) {
                free(pghostname);
                pghostname = NULL;
                hostname_alloc = 0;
        }
        if (pgdbname && dbname_alloc) {
                free(pgdbname);
                pgdbname = NULL;
                dbname_alloc = 0;
        }
        if (pgdbuser && dbuser_alloc) {
                free(pgdbuser);
                pgdbuser = NULL;
                dbuser_alloc = 0;
        }
        if (pgdbsock && dbsock_alloc) {
                free(pgdbsock);
                pgdbsock = NULL;
                dbsock_alloc = 0;
        }
        if (pgpassword && password_alloc) {
                free(pgpassword);
                pgpassword = NULL;
                password_alloc = 0;
        }
        if (pgdbport && dbport_alloc) {
                free(pgdbport);
                pgdbport = NULL;
                dbport_alloc = 0;
        }
        if (min_frozen && min_frozen_alloc) {
                free(min_frozen);
                min_frozen = NULL;
                min_frozen_alloc = 0;
        }
        if (frozen_time && frozen_time_alloc) {
                free(frozen_time);
                frozen_time = NULL;
                frozen_time_alloc = 0;
        }
        if (pround_sec && pround_sec_alloc) {
                free(pround_sec);
                pround_sec = NULL;
                pround_sec_alloc = 0;
        }



	ast_unregister_application(app);

	return 0;
}

int load_module(void)
{
        int res;
        struct ast_config *cfg;
        struct ast_variable *var;
        char *tmp;

	//+++++ Post 1.2 +++++++++++
        cfg = ast_config_load(config);
	//++++++ Prior 1.2 +++++++++++
	//cfg = ast_load(config);
	//+++++++++++++++++++++++++
        if (!cfg) {
                if (SHOW_WARNING) ast_log(LOG_WARNING, "Unable to load config for mcc2 Application: %s\n", config);
                return 0;
        }

        var = ast_variable_browse(cfg, "global");
        if (!var) {
                /* nothing configured */
                return 0;
        }

        tmp = ast_variable_retrieve(cfg,"global","hostname");
        if (tmp) {
                pghostname = malloc(strlen(tmp) + 1);
                if (pghostname != NULL) {
                        hostname_alloc = 1;
			strcpy(pghostname, tmp);
                } else {
                        if (SHOW_ERROR) ast_log(LOG_ERROR,"Out of memory error.\n");
                        return -1;
                }
        } else {
                if (SHOW_WARNING) ast_log(LOG_WARNING,"mcc2 database server hostname not specified.  Assuming localhost\n");
//                pghostname = "localhost";
                pghostname = malloc(strlen("localhost") + 1);
                if (pghostname != NULL) {
                        hostname_alloc = 1;
			strcpy(pghostname, "localhost");
                } else {
                        if (SHOW_ERROR) ast_log(LOG_ERROR,"Out of memory error.\n");
                        return -1;
                }

        }

        tmp = ast_variable_retrieve(cfg,"global","dbname");
        if (tmp) {
                pgdbname = malloc(strlen(tmp) + 1);
                if (pgdbname != NULL) {
                        dbname_alloc = 1;
			strcpy(pgdbname, tmp);
                } else {
                        ast_log(LOG_ERROR,"Out of memory error.\n");
                        return -1;
                }
        } else {
                if (SHOW_WARNING) ast_log(LOG_WARNING,"mcc2 database not specified.  Assuming asterisk\n");
//                pgdbname = "asterisk";
                pgdbname = malloc(strlen("asterisk") + 1);
                if (pgdbname != NULL) {
                        dbname_alloc = 1;
			strcpy(pgdbname, "asterisk");
                } else {
                        ast_log(LOG_ERROR,"Out of memory error.\n");
                        return -1;
                }

        }

        tmp = ast_variable_retrieve(cfg,"global","user");
        if (tmp) {
                pgdbuser = malloc(strlen(tmp) + 1);
                if (pgdbuser != NULL) {
                        dbuser_alloc = 1;
			strcpy(pgdbuser, tmp);
                } else {
                        ast_log(LOG_ERROR,"Out of memory error.\n");
                        return -1;
                }
        } else {
                if (SHOW_WARNING) ast_log(LOG_WARNING,"mcc2 database user not specified.  Assuming postgres\n");
//                pgdbuser = "postgres";
                pgdbuser = malloc(strlen("postgres") + 1);
                if (pgdbuser != NULL) {
                        dbuser_alloc = 1;
			strcpy(pgdbuser, "postgres");
                } else {
                        ast_log(LOG_ERROR,"Out of memory error.\n");
                        return -1;
                }

        }

        tmp = ast_variable_retrieve(cfg,"global","password");
        if (tmp) {
                pgpassword = malloc(strlen(tmp) + 1);
                if (pgpassword != NULL) {
                        password_alloc = 1;
			//strncpy(pgpassword, tmp, strlen(tmp));
			strcpy(pgpassword, tmp);
                } else {
                        ast_log(LOG_ERROR,"Out of memory error.\n");
                        return -1;
                }
        } else {
                if (SHOW_WARNING) ast_log(LOG_WARNING,"mcc2 database password not specified.  Assuming blank\n");
//                pgpassword = "";
                pgpassword = malloc(strlen("") + 1);
                if (pgpassword != NULL) {
                        password_alloc = 1;
			//strncpy(pgpassword, tmp, strlen(tmp));
			strcpy(pgpassword, "");
                } else {
                        ast_log(LOG_ERROR,"Out of memory error.\n");
                        return -1;
                }

        }

        tmp = ast_variable_retrieve(cfg,"global","port");
        if (tmp) {
                pgdbport = malloc(strlen(tmp) + 1);
                if (pgdbport != NULL) {
                        dbport_alloc = 1;
			//strncpy(pgdbport, tmp, strlen(tmp));
			strcpy(pgdbport,tmp);
                } else {
                        ast_log(LOG_ERROR,"Out of memory error.\n");
                        return -1;
                }
        } else {
                if (SHOW_WARNING) ast_log(LOG_WARNING,"mcc2 database port not specified.  Using 5432.\n");
//                pgdbport = "5432";
                pgdbport = malloc(strlen("5432") + 1);
                if (pgdbport != NULL) {
                        dbport_alloc = 1;
			//strncpy(pgdbport, tmp, strlen(tmp));
			strcpy(pgdbport,"5432");
                } else {
                        ast_log(LOG_ERROR,"Out of memory error.\n");
                        return -1;
                }

        }

        tmp = ast_variable_retrieve(cfg,"global","min_frozen");
        if (tmp) {
                min_frozen = malloc(strlen(tmp) + 1);
                if (min_frozen != NULL) {
                        min_frozen_alloc = 1;
			//strncpy(pgdbport, tmp, strlen(tmp));
			strcpy(min_frozen,tmp);
                } else {
                        ast_log(LOG_ERROR,"Out of memory error.\n");
                        return -1;
                }
        } else {
                if (SHOW_WARNING) ast_log(LOG_WARNING,"mcc2 minimum frozen credit not specified.  Using 1000.\n");
                min_frozen = malloc(strlen("1000") + 1);
                if (min_frozen != NULL) {
                        min_frozen_alloc = 1;
			//strncpy(pgdbport, tmp, strlen(tmp));
			strcpy(min_frozen,"1000");
                } else {
                        ast_log(LOG_ERROR,"Out of memory error.\n");
                        return -1;
                }
        }

        tmp = ast_variable_retrieve(cfg,"global","frozen_time");
        if (tmp) {
                frozen_time = malloc(strlen(tmp) + 1);
                if (frozen_time != NULL) {
                        frozen_time_alloc = 1;
			//strncpy(pgdbport, tmp, strlen(tmp));
			strcpy(frozen_time,tmp);
                } else {
                        ast_log(LOG_ERROR,"Out of memory error.\n");
                        return -1;
                }
        } else {
                if (SHOW_WARNING) ast_log(LOG_WARNING,"mcc2 frozen time not specified.  Using 20 minutes.\n");
                frozen_time = malloc(strlen("20") + 1);
                if (frozen_time != NULL) {
                        frozen_time_alloc = 1;
			//strncpy(pgdbport, tmp, strlen(tmp));
			strcpy(frozen_time,"20");
                } else {
                        ast_log(LOG_ERROR,"Out of memory error.\n");
                        return -1;
                }
        }

        tmp = ast_variable_retrieve(cfg,"global","round_sec");
        if (tmp) {
                pround_sec = malloc(strlen(tmp) + 1);
                if (pround_sec != NULL) {
                        pround_sec_alloc = 1;
			//strncpy(pgdbport, tmp, strlen(tmp));
			strcpy(pround_sec,tmp);
                } else {
                        ast_log(LOG_ERROR,"Out of memory error.\n");
                        return -1;
                }
        } else {
                if (SHOW_WARNING) ast_log(LOG_WARNING,"mcc2 round seconds not specified. Using 6 seconds.\n");
                pround_sec = malloc(strlen("6") + 1);
                if (pround_sec != NULL) {
                        pround_sec_alloc = 1;
			//strncpy(pgdbport, tmp, strlen(tmp));
			strcpy(pround_sec,"6");
                } else {
                        ast_log(LOG_ERROR,"Out of memory error.\n");
                        return -1;
                }
        }

	//-------------- activating prompts from config file -------------------

        tmp = ast_variable_retrieve(cfg,"global","show_notice");
        if (tmp) {
	    SHOW_NOTICE=atoi(tmp);
        } else {
            ast_log(LOG_WARNING,"mcc2 SHOW_NOTICE not specified in config file. Notices will be hidden.\n");
    	    SHOW_NOTICE=0;
        }


        tmp = ast_variable_retrieve(cfg,"global","show_warning");
        if (tmp) {
	    SHOW_WARNING=atoi(tmp);
        } else {
            ast_log(LOG_WARNING,"mcc2 SHOW_WARNING not specified in config file. Warnings will be shown.\n");
    	    SHOW_WARNING=1;
        }


        tmp = ast_variable_retrieve(cfg,"global","show_error");
        if (tmp) {
	    SHOW_ERROR=atoi(tmp);
        } else {
            ast_log(LOG_WARNING,"mcc2 SHOW_ERROR not specified in config file. Errors will be shown.\n");
    	    SHOW_ERROR=1;
        }

        tmp = ast_variable_retrieve(cfg,"global","round_time");
        if (tmp) {
	    ROUND_TIME=atoi(tmp);
        } else {
            ast_log(LOG_WARNING,"mcc2 ROUND_TIME not specified in config file. Default = 0.\n");
    	    ROUND_TIME=0;
        }

        tmp = ast_variable_retrieve(cfg,"global","round_to");
        if (tmp) {
	    ROUND_TO=atoi(tmp);
        } else {
            ast_log(LOG_WARNING,"mcc2 ROUND_TO not specified in config file. Default = 0.\n");
    	    ROUND_TO=0;
        }



	//-------------------------------------------------------------------------

	//+++++ Post 1.2 +++++++++++
        ast_config_destroy(cfg);
	//++++++ Prior 1.2 +++++++++++
        //ast_destroy(cfg);
	//+++++++++++++++++++++++++

        ast_log(LOG_DEBUG,"app_mcc2: got hostname of %s\n",pghostname);
        ast_log(LOG_DEBUG,"app_mcc2: got port of %s\n",pgdbport);
        if (pgdbsock)
                ast_log(LOG_DEBUG,"app_mcc2: got sock file of %s\n",pgdbsock);
        ast_log(LOG_DEBUG,"app_mcc2: got user of %s\n",pgdbuser);
        ast_log(LOG_DEBUG,"app_mcc2: got dbname of %s\n",pgdbname);
        ast_log(LOG_DEBUG,"app_mcc2: got password of %s\n",pgpassword);

        ast_log(LOG_DEBUG,"app_mcc2: got min_frozen of %s\n",min_frozen);

        conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword);
        if (PQstatus(conn) != CONNECTION_BAD) {
                ast_log(LOG_DEBUG,"app_mcc2: Successfully connected to mcc2 database.\n");
                connected = 1;
        } else {
                ast_log(LOG_ERROR, "app_mcc2: cannot connect to database server %s.  Calls will not be logged\n", pghostname);
                connected = 0;
        }
	ast_mutex_init(&postgreslock);

        res = ast_register_application(app, mcc2_exec, synopsis, descrip);
        if (res) {
                ast_log(LOG_ERROR, "Unable to register mcc2 Application\n");
        }

        return res;
}

char *description(void)
{
	return tdesc;
}

int usecount(void)
{
	int res;
	STANDARD_USECOUNT(res);
	return res;
}

char *key()
{
	return ASTERISK_GPL_KEY;
}