/* * GnuDialer - Complete, free predictive dialer * * Complete, free predictive dialer for contact centers. * * Copyright (C) 2007, GnuDialer Project * * Heath Schultz * Richard Lyman * Jamerson Medley * * This program is free software, distributed under the terms of * the GNU General Public License. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "queue.h" #include "Socket.h" #include "tzfilter.h" #include "tzpopulate.h" #include "statepopulate.h" #include "exceptions.h" #include "asterisk.h" #include "call.h" #include "evaluate.h" #include "etcinfo.h" #include "itos.h" #include "stoi.h" #include "dtos.h" #include "ltos.h" #include "ftos.h" #include "log.h" #include "dispo.h" #include "settings.h" #include "adminwork.h" #include "abnhelper.h" #include "color.h" #define CRASH do { fprintf(stderr, "!! Forcing immediate crash a-la abort !!\n"); *((int *)0) = 0; } while(0) const bool debugPos = false; #define HERE(x) if (debugPos) { std::cout << "Here:" << #x << std::endl; } const bool debugCampaignSettings = false; const int & selectLessorOf(const int & lhs, const int & rhs) { if (lhs < rhs) { return lhs; } else { return rhs; } } bool safeMode; void sig_handler(int sig) { if (sig == SIGSEGV) { if (safeMode == true) { std::cout << ((doColorize) ? fg_light_white : "") << " [" << getppid() << ":" << getpid() << "] " << ((doColorize) ? fg_light_red : "") << "FATAL ERROR! Segmentation Fault!" << ((doColorize) ? normal : "") << std::endl; std::cout << "You are running in safe mode, so GnuDialer will attempt to restart itself!" << std::endl << std::endl; std::system("sleep 1 && gnudialer &"); } else { CRASH; std::cout << ((doColorize) ? fg_light_white : "") << " [" << getppid() << ":" << getpid() << "] " << ((doColorize) ? fg_light_red : "") << "FATAL ERROR! Segmentation Fault!" << ((doColorize) ? normal : "") << std::endl; std::cout << "Please report this to the GnuDialer project." << std::endl; std::cout << "Please also be advised that you can start gnudialer in \"safe\" mode which will" << std::endl; std::cout << "automatically restart GnuDialer if you receive a fatal error." << std::endl; std::cout << "Type: \"gnudialer --help\" for more information." << std::endl << std::endl; } exit(0); } if (sig == SIGCHLD) { int stat; while (waitpid (-1, &stat, WNOHANG) > 0); } return; } void doRedirect(const std::string & channel, \ const std::string & agent, \ const std::string & campaign, \ const std::string & leadid, \ const std::string & managerUser, \ const std::string & managerPass, \ const bool & doChangeCallerId) { std::string response; if (atoi(agent.c_str()) || agent == "699" && doChangeCallerId) { std::cout << campaign << ": " << ((doColorize) ? fg_light_white : "") << " [" << getppid() << ":" << getpid() << "] " << ((doColorize) ? fg_light_magenta : "") << "Transferring - " << channel << " to Agent: " << agent << ((doColorize) ? normal : "") << std::endl; writeGnudialerLog(campaign + ": Transferring - " + channel + " to Agent: " + agent + ""); ClientSocket AsteriskRedir(getMainHost(),5038); AsteriskRedir >> response; AsteriskRedir << "Action: Login\r\nUserName: " + managerUser + "\r\nSecret: " + managerPass + "\r\nEvents:off\r\n\r\n"; AsteriskRedir >> response; AsteriskRedir << "Action: Redirect\r\n"; AsteriskRedir << "Channel: " + channel + "\r\n"; AsteriskRedir << "Exten: " + agent + "\r\n"; if (!doChangeCallerId) { AsteriskRedir << "Context: agent\r\n"; } else { AsteriskRedir << "Context: closerloop\r\n"; } AsteriskRedir << "Priority: 1\r\n\r\n"; AsteriskRedir >> response; AsteriskRedir << "Action: Logoff\r\n\r\n"; AsteriskRedir >> response; usleep(10000000); } } void doTailLogs(const std::string & theBlock) { std::cout << ((doColorize) ? fg_light_white : "") << " [" << getppid() << ":" << getpid() << "] " << ((doColorize) ? fg_light_magenta : "") << "doTailLogs - (PARSE ERROR) - " << theBlock << ((doColorize) ? normal : "") << std::endl; std::system("/usr/bin/tail -30 /var/log/asterisk/debug /var/log/asterisk/messages /var/log/asterisk/gnudialer.log >>/tmp/parse.log"); } void doPrintSale(const std::string & theText, \ const std::string & theCampaign, \ const std::string & theLeadid) { usleep(3000000); std::cout << theCampaign << ": " << ((doColorize) ? fg_light_white : "") << " [" << getppid() << ":" << getpid() << "] " << ((doColorize) ? fg_light_magenta : "") << "writeCampaignSale - " << theLeadid << ((doColorize) ? normal : "") << std::endl; writeCampaignSale(theText,theCampaign,theLeadid); } void doSetVarTransfer(const std::string & channel, \ const std::string & agent, \ const std::string & managerUser, \ const std::string & managerPass) { std::string response; std::cout << ((doColorize) ? fg_light_white : "") << " [" << getppid() << ":" << getpid() << "] " << ((doColorize) ? fg_light_magenta : "") << "doSetVarTransfer - " << channel << ((doColorize) ? normal : "") << std::endl; //writeGnudialerLog(campaign + ": doSetVarTransfer - " + channel + " from Agent: " + agent + ""); ClientSocket AsteriskRedir(getMainHost(),5038); AsteriskRedir >> response; AsteriskRedir << "Action: Login\r\nUserName: " + managerUser + "\r\nSecret: " + managerPass + "\r\nEvents:off\r\n\r\n"; AsteriskRedir >> response; AsteriskRedir << "Action: SetVar\r\n"; AsteriskRedir << "Channel: " + channel + "\r\n"; AsteriskRedir << "Variable: ISTRANSFER=TRANSFER\r\n\r\n"; AsteriskRedir >> response; AsteriskRedir << "Action: Logoff\r\n\r\n"; AsteriskRedir >> response; if (response == "Success") { std::cout << "doSetVarTransfer - SUCCESSFUL " << channel << std::endl; } AsteriskRedir >> response; } void doHangupCall(const std::string & channel, \ const std::string & agent, \ const std::string & managerUser, \ const std::string & managerPass) { std::string response; std::cout << ((doColorize) ? fg_light_white : "") << " [" << getppid() << ":" << getpid() << "] " << ((doColorize) ? fg_light_magenta : "") << "doHangupCall - " << channel << ((doColorize) ? normal : "") << std::endl; writeGnudialerLog("doHangupCall - " + channel + " from Agent: " + agent + ""); ClientSocket AsteriskRedir(getMainHost(),5038); AsteriskRedir >> response; AsteriskRedir << "Action: Login\r\nUserName: " + managerUser + "\r\nSecret: " + managerPass + "\r\nEvents:off\r\n\r\n"; AsteriskRedir >> response; AsteriskRedir << "Action: Hangup\r\n"; AsteriskRedir << "Channel: " + channel + "\r\n\r\n"; AsteriskRedir >> response; AsteriskRedir << "Action: Logoff\r\n\r\n"; AsteriskRedir >> response; } void doSendLoggedIn(const std::string & agent, \ const std::string & paused, \ const std::string & managerUser, \ const std::string & managerPass) { std::string response; std::cout << ((doColorize) ? fg_light_white : "") << " [" << getppid() << ":" << getpid() << "] " << ((doColorize) ? fg_light_magenta : "") << "doSendLoggedIn - " << agent << ((doColorize) ? normal : "") << std::endl; writeGnudialerLog("doSendLoggedIn - Agent: " + agent + ""); ClientSocket AsteriskRedir(getMainHost(),5038); AsteriskRedir >> response; AsteriskRedir << "Action: Login\r\nUserName: " + managerUser + "\r\nSecret: " + managerPass + "\r\nEvents:off\r\n\r\n"; AsteriskRedir >> response; AsteriskRedir << "Action: SendEvent\r\n"; AsteriskRedir << "Event: AlreadyLoggedIn\r\n"; AsteriskRedir << "Body: Agent/" + agent + " Paused: " + paused + "\r\n\r\n"; AsteriskRedir >> response; AsteriskRedir << "Action: Logoff\r\n\r\n"; AsteriskRedir >> response; } void doMonitorStart(const std::string & channel, \ const std::string & agent, \ const std::string & campaign, \ const std::string & leadid, \ const std::string & managerUser, \ const std::string & managerPass) { std::string response; std::cout << "doMonitorStart - " << ((doColorize) ? fg_light_white : "") << " [" << getppid() << ":" << getpid() << "] " << channel << std::endl; writeGnudialerLog("doMonitorStart - " + channel + " from Agent: " + agent + ""); ClientSocket AsteriskRedir(getMainHost(),5038); AsteriskRedir >> response; AsteriskRedir << "Action: Login\r\nUserName: " + managerUser + "\r\nSecret: " + managerPass + "\r\nEvents:off\r\n\r\n"; AsteriskRedir >> response; AsteriskRedir << "Action: Monitor\r\n"; AsteriskRedir << "Channel: " + channel + "\r\n"; AsteriskRedir << "File: " + agent + "-" + campaign + "-" + leadid + "\r\n"; AsteriskRedir << "Mix: 1\r\n\r\n"; AsteriskRedir >> response; AsteriskRedir << "Action: Logoff\r\n\r\n"; AsteriskRedir >> response; } void doMonitorStop(const std::string & channel, \ const std::string & agent, \ const std::string & campaign, \ const std::string & leadid, \ const std::string & managerUser, \ const std::string & managerPass) { std::string response; std::cout << "doMonitorStop - " << ((doColorize) ? fg_light_white : "") << " [" << getppid() << ":" << getpid() << "] " << channel << std::endl; writeGnudialerLog("doMonitorStop - " + channel + " from Agent: " + agent + ""); ClientSocket AsteriskRedir(getMainHost(),5038); AsteriskRedir >> response; AsteriskRedir << "Action: Login\r\nUserName: " + managerUser + "\r\nSecret: " + managerPass + "\r\nEvents:off\r\n\r\n"; AsteriskRedir >> response; AsteriskRedir << "Action: StopMonitor\r\n"; AsteriskRedir << "Channel: " + channel + "\r\n\r\n"; AsteriskRedir >> response; AsteriskRedir << "Action: Logoff\r\n\r\n"; AsteriskRedir >> response; } void doAgentPause(const std::string & agent, \ const std::string & campaign, \ const std::string & paused, \ const std::string & managerUser, \ const std::string & managerPass) { std::string response; std::cout << "doAgentPause - " << ((doColorize) ? fg_light_white : "") << " [" << getppid() << ":" << getpid() << "] " << " Agent: " << agent << " Paused: " << paused << std::endl; writeGnudialerLog("doAgentPause - Agent: " + agent + " Paused: " + paused + ""); ClientSocket AsteriskRedir(getMainHost(),5038); AsteriskRedir >> response; AsteriskRedir << "Action: Login\r\nUserName: " + managerUser + "\r\nSecret: " + managerPass + "\r\nEvents:off\r\n\r\n"; AsteriskRedir >> response; AsteriskRedir << "Action: QueuePause\r\n"; AsteriskRedir << "Interface: Agent/" + agent + "\r\n"; AsteriskRedir << "Queue: " + campaign + "\r\n"; AsteriskRedir << "Paused: " + paused + "\r\n\r\n"; AsteriskRedir >> response; AsteriskRedir << "Action: Logoff\r\n\r\n"; AsteriskRedir >> response; } void sendMgrEvent(const std::string & eventname, const std::string & eventbody, const std::string & managerUser, const std::string & managerPass) { std::string response; std::cout << "sendMgrEvent - " << ((doColorize) ? fg_light_white : "") << " [" << getppid() << ":" << getpid() << "] " << " Event: " << eventname << " Body: " << eventbody << std::endl; ClientSocket AsteriskRedir(getMainHost(),5038); AsteriskRedir >> response; AsteriskRedir << "Action: Login\r\nUserName: " + managerUser + "\r\nSecret: " + managerPass + "\r\nEvents: off\r\n\r\n"; AsteriskRedir >> response; AsteriskRedir << "Action: SendEvent\r\n"; AsteriskRedir << "Event: " + eventname + "\r\n"; AsteriskRedir << "Body: " + eventbody + "\r\n\r\n"; AsteriskRedir >> response; AsteriskRedir << "Action: Logoff\r\n\r\n"; AsteriskRedir >> response; } int main(int argc, char** argv) { usleep(100000); safeMode = false; bool daemonMode = true; bool gDebug = false; bool gLog = false; signal(SIGCHLD,sig_handler); signal(SIGSEGV,sig_handler); //set default console color to white on black std::cout << ((doColorize) ? fg_light_white : "") << std::endl; for (int i = 1; i < argc; ++i) { const std::string arg(argv[i]); if (arg == "stop" || \ arg == "-stop" || \ arg == "--stop") { writeGnudialerLog("GnuDialer: Stopped"); std::cout << ((doColorize) ? fg_light_green : "") << "GnuDialer: Stopped" << ((doColorize) ? normal : "") << std::endl; std::system(("killall " + std::string(argv[0])).c_str()); exit(0); } if (arg == "--tzpopulate" || \ arg == "tzpopulate" || \ arg == "-tzpopulate") { if (i+1 < argc) { tzpopulate(argv[i+1]); statepopulate(argv[i+1]); return 0; } else { std::cout << "GnuDialer: tzpopulate - Error! Missing campaign name!" << std::endl; return 1; } } if (arg == "-h" || \ arg == "--help" || \ arg == "-help") { std::cout << std::endl << std::endl; std::cout << "Usage: gnudialer " << std::endl << std::endl; std::cout << "\t--safe Starts gnudialer in \"safe\" mode which makes in auto-restart on fatal error." << std::endl; std::cout << "\t--tzpopulate Will create and populate the fields necessary for a campaign." << std::endl; std::cout << "\t--help This help screen." << std::endl; std::cout << "\t--stop Unconditionally stop the dialer." << std::endl; std::cout << "\t--no-daemon Do not run as a daemon." << std::endl; std::cout << std::endl << std::endl; return 0; } if (arg == "-s" || \ arg == "--safe" || \ arg == "-safe") { std::cout << "GnuDialer: SAFE MODE enabled!" << std::endl; safeMode = true; } if (arg == "-nd" || arg == "--no-daemon" || arg == "-no-daemon") { daemonMode = false; } } if (daemonMode) { int daemonizer = 0; daemonizer = fork(); if (daemonizer<0) { std::cout << "GnuDialer: Error setting up daemon process... Aborting." << std::endl; exit(1); } if (daemonizer > 0) { exit(0); } } umask(017); chdir("/tmp"); int lfp = open("gnudialer.lock",O_RDWR|O_CREAT,0660); if (lfp<0) { std::cout << "GnuDialer: Error opening lock file!" << std::endl; exit(1); } if (lockf(lfp,F_TLOCK,0)<0) { std::cout << "GnuDialer: process already running!" << std::endl; exit(0); } char str[80]; sprintf(str,"%d\n",getpid()); int parentPID = getpid(); write(lfp,str,strlen(str)); bool isAHoliday; try { isAHoliday = isHoliday(); } catch(const xFileOpenError & e) { std::cout << "GnuDialer: Exception! Unable to open " << e.GetFilename() << "!" << std::endl; return 1; } // this creates a few placeholder campaigns if they // do not exist. // (recreates them if deleted and gnudialer restarted) if (!existsQueue("CLOSER")) { createQueue("CLOSER"); addBasicSettings("CLOSER"); reloadQueues(); } if (!existsQueue("INBOUND")) { createQueue("INBOUND"); addBasicSettings("INBOUND"); reloadQueues(); } if (!existsQueue("DNC")) { createQueue("DNC"); addBasicSettings("DNC"); reloadQueues(); } addGlobalSettings("general"); Queue TheQueueGlobals; TheQueueGlobals.ParseQueue("general"); try { gDebug = TheQueueGlobals.GetSetting("debug").GetBool(); gLog = TheQueueGlobals.GetSetting("log").GetBool(); } catch (xLoopEnd e) { std::cout << "Caught xLoopEnd while getting TheQueueGlobals..." << std::endl; std::cout << e.what(); std::cout << std::endl << std::endl; } std::string mainHost = getMainHost(); MYSQL *mysql = NULL; MYSQL_RES *result; MYSQL_ROW row; mysql = mysql_init(NULL); if(mysql == NULL) { std::cout << "GnuDialer: MySql init failed!" << std::endl; return 1; } if(!mysql_real_connect(mysql, getMySqlHost().c_str(), \ getMySqlUser().c_str(), \ getMySqlPass().c_str(), \ getDbName().c_str(), \ 3306, NULL, 0)) { std::cout << "GnuDialer: MySql connection failed!" << std::endl; return 1; } try { // Not nested for convenience. if (gLog) { writeGnudialerLog("GnuDialer: Started"); } if (gDebug) { std::cout << ((doColorize) ? fg_light_green : "") << "GnuDialer: Started" << ((doColorize) ? normal : "") << std::endl; std::cout << "GnuDialer: loading gdhosts.conf" << std::endl; } CallCache * TheCallCache; try { TheCallCache = new CallCache(); } catch(xTooFewFields) { std::cout << "Exception: Too few fields in gdhosts.conf!" << std::endl; return 1; } catch(xTooManyFields) { std::cout << "Exception: Too many fields in gdhosts.conf!" << std::endl; return 1; } catch(xInvalidWeightValue) { std::cout << "Exception: Invalid weight value in gdhosts.conf!" << std::endl; return 1; } catch(const xFileOpenError & e) { std::cout << "Exception: Error opening " << e.GetFilename() << "!" << std::endl; return 1; } catch(xNoHostsDefined) { std::cout << "Exception: No hosts defined in gdhosts.conf!" << std::endl; return 1; } if (gDebug) { std::cout << "GnuDialer: loading gdhosts.conf (done)" << std::endl; } std::string response, block, queue, mode, calltoday, usednc, query, tzearliest, tzlatest, callerid, channel; std::string tempagent, usecloser,closercam; std::string dspmode, trunk, dialprefix, extravars, transfer, filter, usecallback, usetzfilter; bool debug; // bool log; int skip; std::string f_areacode, f_areacode_prefix, f_zipcode, orderby; std::string managerUser = getManagerUsername(); std::string managerPass = getManagerPassword(); std::stringstream BlockStream; unsigned int maxlines = 0, timeout = 0, linesdialing = 0; unsigned int availagents = 0, onlineagents = 0, dialableagents = 0; unsigned int linestodial = 0, counter = 0; unsigned int pos = 0, end = 0, pos2 = 0, end2 = 0; unsigned long int calls = 0, agentcalls = 0, abandons = 0; int pid = 0; double maxratio = 0.0, maxabandons = 0.0, tmpAbnPerc = 0.0; ClientSocket AsteriskManager(getMainHost(),5038); AsteriskManager.setRecvTimeout(1000); AsteriskManager >> response; AsteriskManager << "Action: login\r\nUsername: " + managerUser + "\r\nSecret: " + managerPass + "\r\n\r\n"; AsteriskManager >> response; QueueList TheQueues; AgentList TheAgents; TheQueues.ParseQueues(); TheAgents.ParseAgentList(); if (gDebug) { std::cout << "GnuDialer: Querying Asterisk Agents" << std::endl; } TheAgents.Initialize(managerUser,managerPass); if (gDebug) { std::cout << "GnuDialer: Querying Asterisk Agents (done)" << std::endl; } std::string tempCheckCampaign; for (int i = 0; i < TheQueues.size(); i++) { tempCheckCampaign = TheQueues.at(i).GetName(); if (gDebug) { std::cout << tempCheckCampaign << ": Settings Pre-Check " << std::endl; } addBasicSettings(tempCheckCampaign); if (gDebug) { std::cout << tempCheckCampaign << ": Resetting Filters " << std::endl; } resetFilterSettings(tempCheckCampaign); } TheQueues.ParseQueues(); timeval tv; unsigned long int timeSinceLastQueueUpdate = 0, currentTime = 0, lastEvalSend = 0; for(unsigned long int t = 0; true; t++) { gettimeofday(&tv,NULL); currentTime = tv.tv_sec % 1000000; //if (t != 0 && t % 10 == 0 && currentTime - lastEvalSend > 15) { lastEvalSend = currentTime; } if ((t != 0 && t % 10 == 0 && currentTime - timeSinceLastQueueUpdate > 5) \ || (currentTime - timeSinceLastQueueUpdate > 20 && t != 0)) { if (gDebug) { std::cout << "GnuDialer: " << ((doColorize) ? fg_light_white : "")<< " [" << parentPID << ":" << getpid() << "] " << ((doColorize) ? fg_light_yellow : "") << "Updating Campaign Settings " << ((doColorize) ? fg_light_cyan : "") << "(" << currentTime << ")" << ((doColorize) ? normal : "") << std::endl; } TheAgents.ParseAgentList(); TheQueues.ParseQueues(); // Queue TheQueueGlobals; TheQueueGlobals.ParseQueue("general"); try { gDebug = TheQueueGlobals.GetSetting("debug").GetBool(); gLog = TheQueueGlobals.GetSetting("log").GetBool(); } catch (xLoopEnd e) { std::cout << "Caught exception while trying to get debug & log settings!" << std::endl; std::cout << e.what(); std::cout << std::endl << std::endl; } timeSinceLastQueueUpdate = currentTime; } response = ""; AsteriskManager >> response; if (response.empty()) { response = "Event: NoEvent\r\n\r\n"; } BlockStream.clear(); BlockStream.str(response); // TRIGGER LOOP for (std::string tempLine; std::getline(BlockStream,tempLine,'\n'); ) { tempLine = tempLine.substr(0,tempLine.length()-1); // strip '\r' if (tempLine.empty()) { pos = 0; end = 0; pos2 = 0; end2 = 0; // Begin block analysis //const std::string param(const std::string & block, const std::string & type) { // int pos = 0, len = 0; // if (block.find(type + ": ",0) == std::string::npos) { // return static_cast(""); // } else { // pos = block.find(type + ": ",0) + 2; // len = type.length(); // return block.substr(pos + len,block.find("\n",pos) - (pos + len)); // } // } //*********************************************************************************** // THIS CAUSES GNUDIALER TO BE KILLED WHEN ASTERISK WAS SHUTDOWN // THIS DOES NOT HANDLE OTHER ASTERISK EXITS, LIKE CORES if (block.find("Event: Shutdown",0) != std::string::npos) { if (gDebug) { std::cout << "GnuDialer: Asterisk Shutdown - GnuDialer Killed" <SetAnswered(theCampaign,theLeadid); pid = fork(); if (pid == 0) { if (isNone == false) { doRedirect(theChannel,tempQueueAgent,theCampaign,theLeadid,managerUser,managerPass, true); exit(0); } } if (pid == -1) { throw xForkError(); } } else { std::cout << theCampaign << ": " << ((doColorize) ? fg_light_white : "") << " [" << getppid() << ":" << getpid() << "] " << ((doColorize) ? fg_light_red : "") << " No available Closers! (QUEUE)" << ((doColorize) ? normal : "") << std::endl; } } catch (xLoopEnd e) { std::cout << "Caught xLoopEnd when getting closer leastrecent." << std::endl; std::cout << e.what(); std::cout << std::endl << std::endl; } } else { //****************************************************************************** //this section is where calls are handled for AGENTS try { tempQueueAgent = TheQueues.LeastRecent(theCampaign,theChannel,theLeadid,false,TheQueues.rWhere(theCampaign).GetSetting("closercam").Get(),TheAgents); if (atoi(tempQueueAgent.c_str())) { if (gDebug) { std::cout << theCampaign << ": " << ((doColorize) ? fg_light_green : "") << "Transfer - tempQueueAgent: " << tempQueueAgent << ((doColorize) ? normal : "") << std::endl; } TheQueues.rWhere(theCampaign).DecrementAnsmachs(); TheQueues.rWhere(theCampaign).WriteAbn(); TheCallCache->SetAnswered(theCampaign,theLeadid); pid = fork(); if (pid == 0) { if (isNone == false) { doRedirect(theChannel,tempQueueAgent,theCampaign,theLeadid,managerUser,managerPass, false); exit(0); } } if (pid == -1) { throw xForkError(); } } else { std::cout << theCampaign << ": " << ((doColorize) ? fg_light_red : "") << " No available Agents! (QUEUE)" << ((doColorize) ? normal : "") << std::endl; } } catch (xLoopEnd e) { std::cout << "Caught xLoopEnd when getting agent leastrecent." << std::endl; std::cout << e.what(); std::cout << std::endl << std::endl; } } } else { std::cout << theCampaign << ": " << ((doColorize) ? fg_light_red : "") << "Parse ERROR! (QUEUE)" << ((doColorize) ? normal : "") << std::endl; } } //*********************************************************************************** if (block.find("Event: ManagerUserEvent",0) != std::string::npos && \ block.find("Event: AgentPause",0) != std::string::npos) { std::string theEvent, theAgent; theEvent = "Pause"; if (block.find("Agent: ",0) != std::string::npos) { pos = block.find("Agent: ",0) + 7; end = block.find("\n",pos); theAgent = block.substr(pos,end-pos); } if (gDebug) { std::cout << "Asterisk: ManagerUserEvent - " << theEvent << " - " << theAgent<< std::endl; } if (gLog) { writeGnudialerLog("Asterisk: ManagerUserEvent - " + theEvent + " - " + theAgent); } if (TheAgents.exists(atoi(theAgent.c_str()))) { TheAgents.where(atoi(theAgent.c_str())).SetOnPause(); if (gDebug) { std::cout << "GnuDialer: SetOnPause - " << theAgent<< std::endl; } if (gLog) { writeGnudialerLog("GnuDialer: SetOnPause - " + theAgent); } } else { std::cout << "AgentPause: Error parsing agent number!" << std::endl; } } //*********************************************************************************** if (block.find("Event: ManagerUserEvent",0) != std::string::npos && \ block.find("Event: AgentUnPause",0) != std::string::npos) { std::string theEvent, theAgent; theEvent = "UnPause"; if (block.find("Agent: ",0) != std::string::npos) { pos = block.find("Agent: ",0) + 7; end = block.find("\n",pos); theAgent = block.substr(pos,end-pos); } if (gDebug) { std::cout << "Asterisk: ManagerUserEvent - " << theEvent << " - " << theAgent<< std::endl; } if (gLog) { writeGnudialerLog("Asterisk: ManagerUserEvent - " + theEvent + " - " + theAgent); } if (TheAgents.exists(atoi(theAgent.c_str()))) { // TheAgents.where(atoi(theAgent.c_str())).SetOnWait(false,false,TheAgents); TheAgents.where(atoi(theAgent.c_str())).SetInReady(); if (gDebug) { std::cout << "GnuDialer: SetInReady - " << theAgent<< std::endl; } if (gLog) { writeGnudialerLog("GnuDialer: SetInReady - " + theAgent); } } else { std::cout << "AgentUnPause: Error parsing agent number!" << std::endl; } } //*********************************************************************************** if (block.find("Event: QueueMemberPaused",0) != std::string::npos && \ block.find("Location:",0) != std::string::npos) { std::string theEvent, theAgent, theCampaign; theEvent = ""; bool pauseAgent = false; if (gDebug) { std::cout << "Asterisk: QueueMemberPaused -"; } // this is missing A for a reason // manager output has A and a // so we trigger off rest if (block.find("gent/",0) != std::string::npos) { pos = block.find("gent/",0) + 5; end = block.find("\n",pos); theAgent = block.substr(pos,end-pos); if (gDebug) { std::cout << " theAgent: " << theAgent; } } if (block.find("Queue: ",0) != std::string::npos) { pos = block.find("Queue: ",0) + 7; end = block.find("\n",pos); theCampaign = block.substr(pos,end-pos); if (gDebug) { std::cout << " theCampaign: " << theCampaign; } } if (block.find("Paused: ",0) != std::string::npos) { pos = block.find("Paused: ",0) + 8; end = block.find("\n",pos); theEvent = block.substr(pos,end-pos); if (theEvent.find("1",0) != std::string::npos) { theEvent = "Pause"; pauseAgent = true; } else { theEvent = "UnPause"; pauseAgent = false; } if (gDebug) { std::cout << " theEvent: " << theEvent; } } if (gDebug) { std::cout << " " << std::endl; } //if (gDebug) { // std::cout << "Asterisk: QueueMemberPaused - " << theEvent << " - " << theAgent << " for Queue - " << theCampaign << std::endl; //} if (gLog) { writeGnudialerLog("Asterisk: QueueMemberPaused - " + theEvent + " - " + theAgent + " for Queue - " + theCampaign + ""); } if (TheAgents.exists(atoi(theAgent.c_str()))) { if (pauseAgent) { TheAgents.where(atoi(theAgent.c_str())).SetOnPause(); if (gDebug) { std::cout << "GnuDialer: SetOnPause - " << theAgent << std::endl; } if (gLog) { writeGnudialerLog("GnuDialer: SetOnPause - " + theAgent); } } else { // TheAgents.where(atoi(theAgent.c_str())).SetOnWait(false,false,TheAgents); TheAgents.where(atoi(theAgent.c_str())).SetInReady(); if (gDebug) { std::cout << "GnuDialer: SetInReady - " << theAgent << std::endl; } if (gLog) { writeGnudialerLog("GnuDialer: SetOnReady - " + theAgent); } } } else { std::cout << "AgentPause: Error parsing agent number!" << std::endl; } } //*********************************************************************************** if (block.find("Event: ManagerUserEvent",0) != std::string::npos && \ block.find("Event: AgentMonitor",0) != std::string::npos) { std::string theEvent, theAgent, theCampaign, theLeadid, theChannel, theTempCampaign; theEvent = "Monitor"; if (gDebug) { std::cout << "ManagerUserEvent - " + theEvent + " - "; } if (block.find("Agent: ",0) != std::string::npos) { pos = block.find("Agent: ",0) + 7; end = block.find("|",pos); theAgent = block.substr(pos,end-pos); if (gLog) { writeGnudialerLog("ManagerUserEvent - " + theEvent + " - " + theAgent); } if (gDebug) { std::cout << " Agent: " << theAgent; } } if (block.find("Campaign: ",0) != std::string::npos) { pos = block.find("Campaign: ",0) + 10; end = block.find("|",pos); theCampaign = block.substr(pos,end-pos); //this is due to crm adding -isclosercam to campaign name if (theCampaign.find("-isclosercam",0) != std::string::npos) { end2 = theCampaign.find("-",0); theTempCampaign = theCampaign.substr(0,end2); theCampaign = theTempCampaign; } if (gDebug) { std::cout << " Campaign: " << theCampaign; } } if (block.find("Leadid: ",0) != std::string::npos) { pos = block.find("Leadid: ",0) + 8; end = block.find("|",pos); theLeadid = block.substr(pos,end-pos); if (gDebug) { std::cout << " Leadid: " << theLeadid; } } if (block.find("Channel: ",0) != std::string::npos) { pos = block.find("Channel: ",0) + 9; end = block.find("\n",pos); theChannel = block.substr(pos,end-pos); //if (gDebug) { // std::cout << " Channel: " << theChannel; //} } if (gDebug) { std::cout << std::endl; } if (gLog) { writeGnudialerLog("Asterisk: ManagerUserEvent - " + theEvent + " - " + theAgent); } pid = fork(); if (pid == 0) { doMonitorStart(theChannel,theAgent,theCampaign,theLeadid,managerUser,managerPass); exit(0); } if (pid == -1) { throw xForkError(); } } //*********************************************************************************** if (block.find("Event: ManagerUserEvent",0) != std::string::npos && \ block.find("Event: AgentUnMonitor",0) != std::string::npos) { std::string theEvent, theAgent, theCampaign, theLeadid, theChannel, theTempCampaign; theEvent = "UnMonitor"; if (gDebug) { std::cout << "ManagerUserEvent - " + theEvent + " - "; } if (block.find("Agent: ",0) != std::string::npos) { pos = block.find("Agent: ",0) + 7; end = block.find("|",pos); theAgent = block.substr(pos,end-pos); if (gLog) { writeGnudialerLog("ManagerUserEvent - " + theEvent + " - " + theAgent); } if (gDebug) { std::cout << " Agent: " << theAgent; } } if (block.find("Campaign: ",0) != std::string::npos) { pos = block.find("Campaign: ",0) + 10; end = block.find("|",pos); theCampaign = block.substr(pos,end-pos); //this is due to crm adding -isclosercam to campaign name if (theCampaign.find("-isclosercam",0) != std::string::npos) { end2 = theCampaign.find("-",0); theTempCampaign = theCampaign.substr(0,end2); theCampaign = theTempCampaign; } if (gDebug) { std::cout << " Campaign: " << theCampaign; } } if (block.find("Leadid: ",0) != std::string::npos) { pos = block.find("Leadid: ",0) + 8; end = block.find("|",pos); theLeadid = block.substr(pos,end-pos); if (gDebug) { std::cout << " Leadid: " << theLeadid; } } if (block.find("Channel: ",0) != std::string::npos) { pos = block.find("Channel: ",0) + 9; end = block.find("\n",pos); theChannel = block.substr(pos,end-pos); //if (gDebug) { // std::cout << " Channel: " << theChannel; //} } if (gDebug) { std::cout << std::endl; } if (gLog) { writeGnudialerLog("Asterisk: ManagerUserEvent - " + theEvent + " - " + theAgent); } pid = fork(); if (pid == 0) { doMonitorStop(theChannel,theAgent,theCampaign,theLeadid,managerUser,managerPass); exit(0); } if (pid == -1) { throw xForkError(); } } //*********************************************************************************** //this isn't used anymore, just left as a template incase we find something we want to //trigger off the Unlink event // // This block is to make sure that just in case an Unlink event fails // we still set the agent on wait so that they still get calls! //if (block.find("Event: Hangup",0) != std::string::npos && block.find("Channel: ",0) != std::string::npos) { // pos = block.find("Channel: ",0) + 9; // end = block.find("\n",pos); // std::string theChannel, theAgent; // theChannel = block.substr(pos,end-pos); // if (gDebug) { // std::cout << "theChannel: " << theChannel << " - hungup" << std::endl; // } // if (TheAgents.existsConnected(theChannel) && block.find("Agent/",0) != std::string::npos) { // TheAgents.whereConnected(theChannel).SetOnWait(false,false,TheAgents); // theAgent = TheAgents.whereConnected(theChannel).GetNumber(); // if (gDebug) { // std::cout << "theAgent: " << theAgent << " - on wait" << std::endl; // } // if (gLog) { // writeGnudialerLog("SetOnWait: " + theChannel); // } // } //} //*********************************************************************************** if (block.find("Event: ManagerUserEvent",0) != std::string::npos && \ block.find("Event: CRM_CallHangup",0) != std::string::npos) { std::string theEvent, theAgent, theChannel, theCampaign, theLeadid; std::string theTempCampaign, theAgentChannel; theEvent = "CallHangup"; if (gDebug) { std::cout << "UserEvent - CallHangup "; } if (block.find("Agent: ",0) != std::string::npos) { pos = block.find("Agent: ",0) + 7; end = block.find("|",pos); theAgent = block.substr(pos,end-pos); if (gLog) { writeGnudialerLog("ManagerUserEvent - " + theEvent + " - " + theAgent); } if (gDebug) { std::cout << " Agent: " << theAgent; } } if (block.find("Campaign: ",0) != std::string::npos) { pos = block.find("Campaign: ",0) + 10; end = block.find("|",pos); theCampaign = block.substr(pos,end-pos); //this is due to crm adding -isclosercam to campaign name if (theCampaign.find("-isclosercam",0) != std::string::npos) { end2 = theCampaign.find("-",0); theTempCampaign = theCampaign.substr(0,end2); theCampaign = theTempCampaign; } if (gDebug) { std::cout << " Campaign: " << theCampaign; } } if (block.find("Leadid: ",0) != std::string::npos) { pos = block.find("Leadid: ",0) + 8; end = block.find("|",pos); theLeadid = block.substr(pos,end-pos); if (gDebug) { std::cout << " Leadid: " << theLeadid; } } if (block.find("Channel: ",0) != std::string::npos) { pos = block.find("Channel: ",0) + 9; end = block.find("\n",pos); theChannel = block.substr(pos,end-pos); if (gDebug) { std::cout << " Channel: " << theChannel; } } if (TheAgents.exists(atoi(theAgent.c_str()))) { std::cout << " (agent exists) "; if (TheAgents.where(atoi(theAgent.c_str())).GetStatus() != -4) { std::cout << " (GetStatus ne -4) "; //crm is sending the campaign info back now //std::string itsCampaign = TheAgents.where(atoi(theAgent.c_str())).GetCampaign(); if (!theCampaign.empty() && theCampaign != "initialized") { std::cout << " (campaign not empty, nor equal initialized) "; // TheQueues.where(theCampaign).AddTalkTime(TheAgents.where(atoi(theAgent.c_str())).SetOnWait(false,false,TheAgents)); //TheQueues.where(theCampaign).AddTalkTime(TheAgents.where(atoi(theAgent.c_str())).SetInReady()); //TheQueues.where(TheAgents.where(atoi(theAgent.c_str())).GetCampaign()).AddTalkTime(TheAgents.where(atoi(theAgent.c_str())).SetOnWait(false,false,TheAgents)); //std::cout << " (added talktime) "; TheAgents.where(atoi(theAgent.c_str())).writeAgentLog(TheAgents); std::cout << " (writeAgentLog) "; TheAgents.where(atoi(theAgent.c_str())).SetInCloseout(); std::cout << std::endl; if (gDebug) { std::cout << theCampaign << ": SetInCloseout - " << theAgent << std::endl; } if (gLog) { writeGnudialerLog(theCampaign + ": SetInCloseout - " + theAgent); } } else { std::cout << theAgent << ": UserEvent - CallHangup - ERROR: Empty Campaign or 'initialized'" << std::endl; } } } else { std::cout << "CallHangup: Error parsing agent number! (CLOSEOUT)" << std::endl; } theAgentChannel = TheAgents.where(atoi(theAgent.c_str())).GetConnectedChannel(); TheAgents.where(atoi(theAgent.c_str())).SetConnectedChannel("hungup"); if (theChannel != theAgentChannel && theChannel != "hungup") { if (theCampaign == "initialized") { //set theChannel to empty so no hangup happens theChannel = ""; } else { theChannel = theAgentChannel; } } if (!theChannel.empty() && theChannel != "hungup") { pid = fork(); if (pid == 0) { doHangupCall(theChannel,theAgent,managerUser,managerPass); exit(0); } if (pid == -1) { throw xForkError(); } } else { std::cout << theAgent << ": UserEvent - CallHangup - ERROR: Empty Channel " << std::endl; } } //*********************************************************************************** if (block.find("Event: ManagerUserEvent",0) != std::string::npos && \ block.find("Event: CRM_LoginAgent",0) != std::string::npos) { std::string theEvent, theAgent, isPaused = "0"; int theStatus; theEvent = "CRM_LoginAgent"; if (gDebug) { std::cout << "UserEvent - CRM_LoginAgent "; } if (block.find("Agent: ",0) != std::string::npos) { pos = block.find("Agent: ",0) + 7; end = block.find("|",pos); theAgent = block.substr(pos,end-pos); if (gLog) { writeGnudialerLog("ManagerUserEvent - " + theEvent + " - " + theAgent); } if (gDebug) { std::cout << " Agent: " << theAgent; } } std::cout << std::endl; if (TheAgents.exists(atoi(theAgent.c_str()))) { //std::cout << " (agent exists) "; theStatus = TheAgents.where(atoi(theAgent.c_str())).GetStatus(); if (theStatus != -2) { //std::cout << " (agent logged in) "; if (theStatus == -3) { //std::cout << " (agent paused) "; isPaused = "1"; } pid = fork(); if (pid == 0) { doSendLoggedIn(theAgent,isPaused,managerUser,managerPass); exit(0); } if (pid == -1) { throw xForkError(); } } } else { std::cout << "CRM_LoginAgent: Error parsing agent number! " << std::endl; } } //*********************************************************************************** if (block.find("Event: ManagerUserEvent",0) != std::string::npos && \ block.find("Event: CRM_DispoRecord",0) != std::string::npos \ || (block.find("Event: UserEventDispo",0) != std::string::npos)) { std::string theEvent, theAgent, theDispo, theChannel, theCampaign, theLeadid; std::string theTransfer, theAgentCloser, theDispoColumn, theCloserCam; bool tempUseCloser = false, tempPrintAgentSales, tempPrintCloserSales, tempPrintCloserNoSales; std::string tempCloserCam, theTempCampaign, theAgentChannel; theEvent = "DispoRecord"; std::string tempStringAgent; int tempIntAgent; if (gDebug) { std::cout << "Manager/UserEvent - DispoRecord "; } if (block.find("Agent: ",0) != std::string::npos) { pos = block.find("Agent: ",0) + 7; end = block.find("|",pos); theAgent = block.substr(pos,end-pos); if (gLog) { writeGnudialerLog("Asterisk: ManagerUserEvent - " + theEvent + " - " + theAgent); } if (gDebug) { std::cout << " Agent: " << theAgent; } } if (block.find("Dispo: ",0) != std::string::npos) { pos = block.find("Dispo: ",0) + 7; end = block.find("|",pos); theDispo = block.substr(pos,end-pos); if (gDebug) { std::cout << " Dispo: " << theDispo; } } if (block.find("Transfer: ",0) != std::string::npos) { pos = block.find("Transfer: ",0) + 10; end = block.find("|",pos); theTransfer = block.substr(pos,end-pos); if (gDebug) { std::cout << " Transfer: " << theTransfer; } } if (block.find("Campaign: ",0) != std::string::npos) { pos = block.find("Campaign: ",0) + 10; end = block.find("|",pos); theCampaign = block.substr(pos,end-pos); //this is due to crm adding -isclosercam to campaign name if (theCampaign.find("-isclosercam",0) != std::string::npos) { end2 = theCampaign.find("-",0); theTempCampaign = theCampaign.substr(0,end2); theCampaign = theTempCampaign; } if (gDebug) { std::cout << " Campaign: " << theCampaign; } } if (block.find("Leadid: ",0) != std::string::npos) { pos = block.find("Leadid: ",0) + 8; end = block.find("|",pos); theLeadid = block.substr(pos,end-pos); if (gDebug) { std::cout << " Leadid: " << theLeadid; } } if (block.find("Channel: ",0) != std::string::npos) { pos = block.find("Channel: ",0) + 9; end = block.find("\n",pos); theChannel = block.substr(pos,end-pos); if (gDebug) { std::cout << " Channel: " << theChannel; } } if (TheQueues.exists(theCampaign)) { if (theTransfer == "TRANSFER") { try { tempUseCloser = TheQueues.rWhere(theCampaign).GetSetting("usecloser").GetBool(); } catch (xLoopEnd e) { std::cout << "Caught xLoopEnd while trying to get usecloser variable" << std::endl; std::cout << e.what(); std::cout << std::endl << std::endl; } tempCloserCam = TheQueues.rWhere(theCampaign).GetSetting("closercam").Get(); if (gDebug) { std::cout << " tempCloserCam: " << tempCloserCam; } } if (gDebug) { std::cout << std::endl; } if (TheAgents.exists(atoi(theAgent.c_str()))) { tempIntAgent = atoi(theAgent.c_str()); int tempAgentStatus = TheAgents.where(atoi(theAgent.c_str())).GetStatus(); if (tempAgentStatus != -4 && tempAgentStatus != -3) { //TheQueues.where(TheAgents.where(atoi(theAgent.c_str())).GetCampaign()).AddTalkTime(TheAgents.where(atoi(theAgent.c_str())).SetOnWait(false,false,TheAgents)); //theCampaign is passed by the call, do NOT use GetCampaign TheQueues.where(theCampaign).AddTalkTime(tempIntAgent); TheAgents.where(tempIntAgent).writeAgentLog(TheAgents); } // TheAgents.where(tempIntAgent).SetOnWait(false,false,TheAgents); TheAgents.where(tempIntAgent).SetInReady(); if (gDebug) { std::cout << "GnuDialer: SetInReady - " << theAgent << std::endl; } if (gLog) { writeGnudialerLog("GnuDialer: SetInReady - " + theAgent); } } else { std::cout << "DispoRecord: Error parsing agent number!" << std::endl; } if (theTransfer == "TRANSFER") { theDispoColumn = "disposition"; theAgentCloser = "agent"; } else { theDispoColumn = "closerdispo"; theAgentCloser = "closer"; } writeDBString(theCampaign,theLeadid,"" + theDispoColumn + "='" + theDispo + "'," + theAgentCloser + "='" + theAgent + "'"); if (theDispo == "8") { writeDBDNC(theCampaign,theLeadid); } if (gDebug) { std::cout << theCampaign << ": writeDBString - DispoRecord - " << theAgentCloser + ": " << theAgent << " theDispo: " << theDispo << std::endl; } writeDispo(theAgent,theCampaign,theDispo); if (gDebug) { std::cout << theCampaign << ": writeDispo - DispoRecord - theAgent: " << theAgent << " theDispo: " << theDispo << std::endl; } tempPrintAgentSales = TheQueues.rWhere(theCampaign).GetSetting("prn_agent_sales").GetBool(); tempPrintCloserSales = TheQueues.rWhere(theCampaign).GetSetting("prn_closer_sales").GetBool(); tempPrintCloserNoSales = TheQueues.rWhere(theCampaign).GetSetting("prn_closer_nosales").GetBool(); if (theTransfer == "TRANSFER" && theDispo == "12" && tempPrintAgentSales) { pid = fork(); if (pid == 0) { doPrintSale("Agent SALE NON-Verified",theCampaign,theLeadid); exit(0); } if (pid == -1) { throw xForkError(); } } if (theTransfer == "TRANSFER" && theDispo == "12" && tempUseCloser) { tempStringAgent = TheQueues.LeastRecent(theCampaign,theChannel,theLeadid,true,tempCloserCam,TheAgents); if (atoi(tempStringAgent.c_str())) { if (gDebug) { std::cout << theCampaign << ": Transfer - tempStringAgent: " << tempStringAgent << std::endl; } if (TheAgents.exists(atoi(tempStringAgent.c_str()))) { TheAgents.where(atoi(tempStringAgent.c_str())).SetConnectedChannel(theChannel); //testing here TheAgents.where(atoi(tempStringAgent.c_str())).SetCampaign(TheQueues.rWhere(theCampaign).GetSetting("closercam").Get()); TheAgents.where(atoi(tempStringAgent.c_str())).SetCampaign(theCampaign); TheAgents.where(atoi(tempStringAgent.c_str())).SetLeadId(theLeadid); //TheAgents.where(atoi(tempStringAgent.c_str())).SetOnWait(false,true,TheAgents); if (gDebug) { std::cout << theCampaign << ": theLeadid - " << theLeadid << std::endl; } pid = fork(); if (pid == 0) { doRedirect(theChannel,tempStringAgent,tempCloserCam,theLeadid,managerUser,managerPass, true); exit(0); } if (pid == -1) { throw xForkError(); } } else { std::cout << "DispoRecord: Closer no longer Exists (DISPO)!" << std::endl; } } else { std::cout << theCampaign << ": No available Closers! (DISPO)" << std::endl; pid = fork(); if (pid == 0) { doRedirect(theChannel,"699",tempCloserCam,theLeadid,managerUser,managerPass, true); exit(0); } if (pid == -1) { throw xForkError(); } } } else { if (theTransfer == "" && theDispo == "11" && tempPrintCloserNoSales) { pid = fork(); if (pid == 0) { doPrintSale("SALE Verification FAILED (for some reason)",theCampaign,theLeadid); exit(0); } if (pid == -1) { throw xForkError(); } } if (theDispo == "12" && tempPrintCloserSales) { pid = fork(); if (pid == 0) { doPrintSale("Agent SALE (Verified/or not Required)",theCampaign,theLeadid); exit(0); } if (pid == -1) { throw xForkError(); } } theAgentChannel = TheAgents.where(atoi(theAgent.c_str())).GetConnectedChannel(); TheAgents.where(atoi(theAgent.c_str())).SetConnectedChannel("hungup"); if (theChannel != theAgentChannel && theChannel != "hungup") { if (theCampaign == "initialized") { //set theChannel to empty so no hangup happens theChannel = ""; } else { theChannel = theAgentChannel; } } if (!theChannel.empty() && theChannel != "hungup") { pid = fork(); if (pid == 0) { doHangupCall(theChannel,theAgent,managerUser,managerPass); exit(0); } if (pid == -1) { throw xForkError(); } } else { if (theChannel == "hungup") { std::cout << "DispoRecord: Channel Empty (Already Hungup - Agent was InCloseout)!" << std::endl; } else { std::cout << "DispoRecord: Channel Empty (HANGUP)!" << std::endl; } } } } else { std::cout << theCampaign << ": Parse ERROR! (DISPO)" << std::endl; } } //*********************************************************************************** if (block.find("Event: UserEventAbandon",0) != std::string::npos) { std::string theCallerIDName, theCampaign, theAgent, theLeadid; if (gDebug) { std::cout << "UserEvent - Abandon "; } if (block.find("CallerIDName: ",0) != std::string::npos && block.find("~",0) != std::string::npos) { pos = block.find("CallerIDName: ",0) + 15; end = block.find("\n",pos); theCallerIDName = block.substr(pos,end-pos); pos = theCallerIDName.find("~",end) + 1; end = theCallerIDName.find("-",pos+1); pos2 = end + 1; end2 = theCallerIDName.find("-",pos2); theCampaign = theCallerIDName.substr(pos,end-pos); if (gDebug) { std::cout << " theCampaign: " << theCampaign; } theLeadid = theCallerIDName.substr(pos2,end2-pos2); if (gDebug) { std::cout << " theLeadid: " << theLeadid; } if (gDebug) { std::cout << std::endl; } if (!theCampaign.empty() && !theLeadid.empty() && TheQueues.exists(theCampaign)) { TheQueues.rWhere(theCampaign).IncrementAbandons(); TheQueues.rWhere(theCampaign).WriteAbn(); TheQueues.rWhere(theCampaign).WriteCalls(); writeDBString(theCampaign,theLeadid,"abandons=abandons+1"); if (gDebug) { std::cout << theCampaign << ": writeDBString - Abandon " << std::endl; } if (gLog) { writeGnudialerLog(theCampaign + ": theLeadid - " + theLeadid + " was abanadoned"); } } else { if (gDebug) { std::cout << "UserEventAbandon: Parse ERROR " << std::endl; } } } } //*********************************************************************************** if (block.find("Event: UserEventPickup",0) != std::string::npos) { std::string theCallerIDName, theCampaign, theAgent, theLeadid; if (gDebug) { std::cout << "UserEvent - Pickup "; } if (block.find("CallerIDName: ",0) != std::string::npos && block.find("~",0) != std::string::npos) { pos = block.find("CallerIDName: ",0) + 15; end = block.find("\n",pos); theCallerIDName = block.substr(pos,end-pos); pos = theCallerIDName.find("~",end) + 1; end = theCallerIDName.find("-",pos+1); pos2 = end + 1; end2 = theCallerIDName.find("-",pos2); theCampaign = theCallerIDName.substr(pos,end-pos); if (gDebug) { std::cout << " theCampaign: " << theCampaign; } theLeadid = theCallerIDName.substr(pos2,end2-pos2); if (gDebug) { std::cout << " theLeadid: " << theLeadid; } if (gDebug) { std::cout << std::endl; } if (!theCampaign.empty() && !theLeadid.empty() && TheQueues.exists(theCampaign)) { writeDBString(theCampaign,theLeadid,"pickups=pickups+1"); if (gDebug) { std::cout << theCampaign << ": writeDBString - Pickup " << std::endl; } if (gLog) { writeGnudialerLog(theCampaign + ": theLeadid - " + theLeadid + " was picked-up"); } } else { if (gDebug) { std::cout << "UserEventPickup: Parse ERROR " << std::endl; } } } } //*********************************************************************************** if (block.find("Event: UserEventFax",0) != std::string::npos) { std::string theCallerIDName, theCampaign, theAgent, theLeadid; if (gDebug) { std::cout << "UserEvent - Fax "; } if (block.find("CallerIDName: ",0) != std::string::npos && block.find("~",0) != std::string::npos) { pos = block.find("CallerIDName: ",0) + 15; end = block.find("\n",pos); theCallerIDName = block.substr(pos,end-pos); pos = theCallerIDName.find("~",end) + 1; end = theCallerIDName.find("-",pos+1); pos2 = end + 1; end2 = theCallerIDName.find("-",pos2); theCampaign = theCallerIDName.substr(pos,end-pos); if (gDebug) { std::cout << " theCampaign: " << theCampaign; } theLeadid = theCallerIDName.substr(pos2,end2-pos2); if (gDebug) { std::cout << " theLeadid: " << theLeadid; } if (gDebug) { std::cout << std::endl; } if (!theCampaign.empty() && !theLeadid.empty() && TheQueues.exists(theCampaign)) { writeDBString(theCampaign,theLeadid,"disposition='-6',pickups=pickups+1"); if (gDebug) { std::cout << theCampaign << ": writeDBString - Fax " << std::endl; } if (gLog) { writeGnudialerLog(theCampaign + ": theLeadid - " + theLeadid + " was a fax"); } } else { if (gDebug) { std::cout << "UserEventPickup: Parse ERROR " << std::endl; } } } } //*********************************************************************************** // End block analysis block = ""; } else { block += tempLine + "\n"; } } // DIALING LOOP for (int i = 0; i < TheQueues.size(); i++) { if (TheQueues.at(i).GetSetting("active").Get() == "true") { queue = TheQueues.at(i).GetName(); maxratio = TheQueues.at(i).GetSetting("maxratio").GetFloat(); maxlines = TheQueues.at(i).GetSetting("maxlines").GetInt(); maxabandons = TheQueues.at(i).GetSetting("maxabandons").GetFloat(); mode = TheQueues.at(i).GetSetting("function").Get(); calltoday = TheQueues.at(i).GetSetting("calltoday").Get(); usednc = TheQueues.at(i).GetSetting("usednc").Get(); callerid = TheQueues.at(i).GetSetting("callerid").Get(); filter = TheQueues.at(i).GetSetting("filter").Get(); timeout = TheQueues.at(i).GetSetting("timeout").GetInt(); usecloser = TheQueues.at(i).GetSetting("usecloser").Get(); closercam = TheQueues.at(i).GetSetting("closercam").Get(); dspmode = TheQueues.at(i).GetSetting("dspmode").Get(); trunk = TheQueues.at(i).GetSetting("trunk").Get(); dialprefix = TheQueues.at(i).GetSetting("dialprefix").Get(); usecallback = TheQueues.at(i).GetSetting("usecallback").Get(); usetzfilter = TheQueues.at(i).GetSetting("usetzfilter").Get(); debug = TheQueues.at(i).GetSetting("debug").GetBool(); skip = TheQueues.at(i).GetSetting("skip").GetInt(); f_areacode = TheQueues.at(i).GetSetting("f_areacode").Get(); f_areacode_prefix = TheQueues.at(i).GetSetting("f_areacode_prefix").Get(); f_zipcode = TheQueues.at(i).GetSetting("f_zipcode").Get(); orderby = TheQueues.at(i).GetSetting("orderby").Get(); for (int c = 0; c < TheQueues.at(c).OccurencesOf("chanvars"); c++) { std::string cnum = TheQueues.at(c).GetSetting(c,"chanvars").GetAttribute("number"); std::string cvar = TheQueues.at(c).GetSetting(c,"chanvars").GetAttribute("var"); std::string cstring = TheQueues.at(c).GetSetting(c,"chanvars").GetAttribute("string"); std::string cenabled = TheQueues.at(c).GetSetting(c,"chanvars").GetAttribute("enable"); if (cenabled == "true") { extravars += "Variable: __" + cvar + "=" + cstring + "\r\n"; } } unsigned int remaininglines = 0; //put these down here so that most important ones get processed last calls = atoi(TheQueues.at(i).GetCalls().c_str()); TheQueues.rWhere(queue).CalcAgentCalls(); agentcalls = atoi(TheQueues.at(i).GetAgentCalls().c_str()); if (agentcalls == 0) { agentcalls = calls; } abandons = atoi(TheQueues.at(i).GetAbandons().c_str()); linesdialing = TheCallCache->LinesDialing(queue); availagents = TheQueues.at(i).GetAvailAgents(TheAgents); onlineagents = TheQueues.at(i).GetOnlineAgents(TheAgents); dialableagents = TheQueues.at(i).GetDialableAgents(TheAgents); //old way was using campaign calls for abandon calcs (oopsie, amazingly noone but me noticed) //linestodial = evaluate(mode,linesdialing,availagents,maxratio,maxlines,maxabandons,calls,abandons); linestodial = evaluate(mode,linesdialing,onlineagents,availagents,dialableagents,maxratio,maxlines,maxabandons,agentcalls,abandons); remaininglines = maxlines - linestodial; if (agentcalls && abandons) { tmpAbnPerc = static_cast(abandons) / static_cast(agentcalls) * 100.0; } else { tmpAbnPerc = 0.0; } //***************************************************************************************** //testing area (this stuff happens every second) bool testing_trigger = false; bool testing2_trigger = false; if ( testing2_trigger && ( (parentPID == getpid()) ) && (currentTime - timeSinceLastQueueUpdate) == 5 ) { std::cout << "CampaignInfo - (" +ltos(currentTime)+") Camp: " << queue << \ " CLs: " << itos(calls) << \ " ACs: " << itos(agentcalls) << \ " ABs: " << itos(abandons) << \ " ABp: " << ftos(tmpAbnPerc) << \ " LDg: " << itos(linesdialing) << \ " MxR: " << ftos(maxratio) << \ " MxB: " << ftos(maxabandons) << \ " OAs: " << itos(onlineagents) << \ " AAs: " << itos(availagents) << \ " DAs: " << itos(dialableagents) << \ " L2D: " << itos(linestodial) << "" << std::endl; } if ( testing_trigger && ( (parentPID == getpid()) ) && (currentTime - timeSinceLastQueueUpdate) == 5 ) { pid = fork(); if (pid == 0) { sendMgrEvent("CampaignInfo", "(" +ltos(currentTime)+") Camp: " + queue + \ " CLs: " + itos(calls) + \ " ACs: " + itos(agentcalls) + \ " ABs: " + itos(abandons) + \ " ABp: " + dtos(tmpAbnPerc) + \ " LDg: " + itos(linesdialing) + \ " MxR: " + dtos(maxratio) + \ " MxB: " + dtos(maxabandons) + \ " OAs: " + itos(onlineagents) + \ " AAs: " + itos(availagents) + \ " DAs: " + itos(dialableagents) + \ " L2D: " + itos(linestodial) + \ "",managerUser,managerPass); //this is leftover, left in as something to accumulate time and space lastEvalSend = tv.tv_sec % 1000000; _exit(0); } if (pid == -1) { throw xForkError(); } } //put closer callbacks in front so they are taken care of right away if ((remaininglines && usecloser == "true" && closercam != "none" && TheQueues.exists(closercam) && true) && (currentTime - timeSinceLastQueueUpdate == 5)) { transfer = "TRANSFER"; int availclosers = TheQueues.rWhere(closercam).GetAvailAgents(TheAgents); if (debugCampaignSettings) { std::cout << currentTime << ":" << queue << ": " << "availclosers: " << availclosers << " - remaininglines: " << remaininglines << std::endl; query = "SELECT count(*) FROM " + queue + " WHERE "; query += " disposition = 12 AND closerdispo = 0 "; if(mysql_query(mysql, query.c_str()) != 0) { std::cout << "Error selecting records !" << std::endl; } else { result = mysql_use_result(mysql); row = mysql_fetch_row(result); int ccb_counter = stoi(std::string(row[0])); if (debug) { if (ccb_counter) { std::cout << queue << ": " << "Total Closer Callbacks Remaining: " << ccb_counter << std::endl; } } mysql_free_result(result); } } //std::cout << queue << ": Testing - got here " << std::endl; if (availclosers) { query = "SELECT id, phone FROM " + queue + " WHERE "; query += " disposition = 12 AND closerdispo = 0 AND ((lastupdated) < DATE_SUB(NOW(),INTERVAL 5 MINUTE)) "; query += " ORDER BY attempts + pickups ASC LIMIT 1"; //query += " ORDER BY attempts + pickups ASC LIMIT " + itos(selectLessorOf(remaininglines,availclosers)); if(mysql_query(mysql, query.c_str()) != 0) { std::cout << "Error selecting leads from mysql! (check table structures)" << std::endl; return 1; } else { result = mysql_use_result(mysql); query = "UPDATE " + queue + " SET attempts=attempts+1 WHERE "; for(counter = 0; (row = mysql_fetch_row(result)); counter++) { if (counter) { query += " OR "; } query += " id=" + std::string(row[0]); remaininglines--; TheCallCache->AddCall(row[1],queue,row[0],callerid,usecloser,dspmode,trunk,dialprefix,extravars,transfer,timeout); if (debug) { std::cout << queue << ": " << "Dialing Closer Callback Number: " << row[1] << std::endl; } } if(mysql_errno(mysql)) { std::cout << "Error fetching rows from mysql!" << std::endl; return 1; } mysql_free_result(result); if (counter) { TheQueues.rWhere(queue).AddCallsDialed(counter); TheQueues.rWhere(queue).WriteCalls(); if(mysql_query(mysql, query.c_str()) != 0) { std::cout << "Error updating leads in mysql!" << std::endl; return 1; } } } } } //callback section if ((remaininglines && usecallback == "true" && true) && (currentTime - timeSinceLastQueueUpdate == 5)) { transfer = ""; //int availclosers = TheQueues.rWhere(closercam).GetAvailAgents(TheAgents); //int availagents = TheQueues.rWhere(campaign).GetAvailAgents(TheAgents); if (debugCampaignSettings) { std::cout << currentTime << ":" << queue << ": availagents: " << availagents << " - remaininglines: " << remaininglines << std::endl; query = "SELECT count(*) FROM " + queue + " WHERE "; query += " disposition = 0 AND cb_datetime > '0000-00-00 00:00:00' AND cb_datetime < NOW()"; if(mysql_query(mysql, query.c_str()) != 0) { std::cout << "Error selecting records !" << std::endl; } else { result = mysql_use_result(mysql); row = mysql_fetch_row(result); int ccb_counter = stoi(std::string(row[0])); if (debug) { if (ccb_counter) { std::cout << queue << ": " << "Total Agent Callbacks Remaining: " << ccb_counter << std::endl; } } mysql_free_result(result); } } // create function to see if a particular agent/type is available if (availagents) { query = "SELECT id, phone FROM " + queue + " WHERE "; query += " disposition = 0 AND cb_datetime > '0000-00-00 00:00:00' AND cb_datetime < NOW()"; query += " AND ((lastupdated) < DATE_SUB(NOW(),INTERVAL 3 MINUTE)) "; query += " ORDER BY attempts + pickups ASC LIMIT 1"; if(mysql_query(mysql, query.c_str()) != 0) { std::cout << "Error selecting leads from mysql! (check table structures)" << std::endl; return 1; } else { result = mysql_use_result(mysql); query = "UPDATE " + queue + " SET cb_datetime='',attempts=attempts+1 WHERE "; for(counter = 0; (row = mysql_fetch_row(result)); counter++) { if (counter) { query += " OR "; } query += " id=" + std::string(row[0]); remaininglines--; TheCallCache->AddCall(row[1],queue,row[0],callerid,usecloser,dspmode,trunk,dialprefix,extravars,transfer,timeout); if (debug) { std::cout << queue << ": " << "Dialing Agent Callback Number: " << row[1] << std::endl; } } if(mysql_errno(mysql)) { std::cout << "Error fetching rows from mysql!" << std::endl; return 1; } mysql_free_result(result); if (counter) { TheQueues.rWhere(queue).AddCallsDialed(counter); TheQueues.rWhere(queue).WriteCalls(); if(mysql_query(mysql, query.c_str()) != 0) { std::cout << "Error updating leads in mysql!" << std::endl; return 1; } } } } } //end testing area //********************************************************************************************8 //MAIN DIALING AREA (reloading key data to maximize call potential) calls = atoi(TheQueues.at(i).GetCalls().c_str()); TheQueues.rWhere(queue).CalcAgentCalls(); agentcalls = atoi(TheQueues.at(i).GetAgentCalls().c_str()); if (agentcalls == 0) { agentcalls = calls; } abandons = atoi(TheQueues.at(i).GetAbandons().c_str()); linesdialing = TheCallCache->LinesDialing(queue); availagents = TheQueues.at(i).GetAvailAgents(TheAgents); onlineagents = TheQueues.at(i).GetOnlineAgents(TheAgents); dialableagents = TheQueues.at(i).GetDialableAgents(TheAgents); //old way was using campaign calls for abandon calcs (oopsie, amazingly noone but me noticed) //linestodial = evaluate(mode,linesdialing,availagents,maxratio,maxlines,maxabandons,calls,abandons); linestodial = evaluate(mode,linesdialing,onlineagents,availagents,dialableagents,maxratio,maxlines,maxabandons,agentcalls,abandons); remaininglines = maxlines - linestodial; if (calls && abandons) { tmpAbnPerc = static_cast(abandons) / static_cast(calls) * 100.0; } else { tmpAbnPerc = 0.0; } transfer = ""; if (linestodial >= 5000 || remaininglines >= 5000) { std::cout << queue << ": linestodial or remaininglines are greater than 5000, something is WRONG!" << std::endl; std::cout << queue << ": ldg: " << linesdialing << " aa: " << availagents << " mr: " << maxratio << " ml: " << maxlines << " ma: " << maxabandons << " mode: " << mode << " calls: " << calls << " abs: " << abandons << " l2d: " << linestodial << " rls: " << remaininglines << std::endl; } if (debugCampaignSettings) { std::cout << queue << ": ldg: " << linesdialing << " aa: " << availagents << " mr: " << maxratio << " ml: " << maxlines << " ma: " << maxabandons << " mode: " << mode << " calls: " << calls << " abs: " << abandons << " l2d: " << linestodial << " rls: " << remaininglines << std::endl; } //std::cout << queue << ": processing this campaign" << std::endl; //MAIN SECTION for dialing calls for a particular campaign if (linestodial && mode != "closer" && mode != "inbound" && true) { if (debug) { if (calls != 0) { std::cout << std::setprecision(4) << queue << ": " << ((doColorize) ? fg_light_cyan : "") << "ABANDON \% (this now reflects division by agentcalls): " << static_cast(abandons) / static_cast(agentcalls) * 100.0 << ((doColorize) ? normal : "") << std::endl; } else { // No div by 0 allowed! std::cout << queue << ": " << ((doColorize) ? fg_light_cyan : "") << "ABANDON \%: 0 (or less than zero)" << ((doColorize) ? normal : "") << std::endl; } } //this is just a base to get the building of the query string going query = "SELECT DISTINCT id, phone FROM " + queue + " WHERE 1 "; //this allows a record to be called back multiple times the same day //without needing to be a specific callback (like closer callback) //be careful, if your viable data is running low this will loop thru //and burn all your data (very fast), and piss off alot of people! if (calltoday != "true"){ query += " AND (LEFT(lastupdated,10) = LEFT(NOW(),10) AND disposition = 1)"; //timezone based filter (currently US only) if (usetzfilter == "true") { tzearliest = TheQueues.at(i).GetSetting("tzearliest").Get(); tzlatest = TheQueues.at(i).GetSetting("tzlatest").Get(); query += " AND " + getFilter(tzearliest,tzlatest,isAHoliday); if (debug) { std::cout << queue << ": " << ((doColorize) ? fg_green : "") << "tzFilter Enabled " << ((doColorize) ? normal : "") << std::endl; } } else { if (debug) { std::cout << queue << ": " << ((doColorize) ? fg_yellow : "") << "tzFilter Disabled " << ((doColorize) ? normal : "") << std::endl; } } query += " OR LEFT(lastupdated,10) <> LEFT(NOW(),10) "; } //this is an extra filter if you want to attempt to call a specific data subset //(this also lets you test a filter before adding it to the primary filters) if (filter.empty() == false && filter != "0" && filter != "None" && filter != "none") { if (debug) { std::cout << queue << ": " << ((doColorize) ? fg_yellow : "") << "filter - " << filter << ((doColorize) ? normal : "") << std::endl; } query += " AND " + filter; } query += " AND ("; //these are the primary filters, it will default to filter 0 on startup //so make sure that is your 'fresh + main' calling data int y = 0; for (int x = 0; x < TheQueues.at(i).OccurencesOf("filters"); x++) { std::string fnum,fstring,enabled; fnum = TheQueues.at(i).GetSetting(x,"filters").GetAttribute("number"); fstring = TheQueues.at(i).GetSetting(x,"filters").GetAttribute("string"); enabled = TheQueues.at(i).GetSetting(x,"filters").GetAttribute("enable"); if (enabled == "true") { y++; if (y > 1) { query += " OR "; } if (debug) { std::cout << queue << ": " << ((doColorize) ? fg_yellow : "") << "filter - " << fstring << ((doColorize) ? normal : "") << std::endl; } query += fstring; } } query += ") "; //areacode based filter if (f_areacode.empty() == false && f_areacode != "0") { if (debug) { std::cout << queue << ": " << ((doColorize) ? fg_yellow : "") << "f_areacode - " << f_areacode << ((doColorize) ? normal : "") << std::endl; } query += " AND LEFT(phone,3)='" + f_areacode + "'"; } //areacode + prefix based filter if (f_areacode_prefix.empty() == false && f_areacode_prefix != "0") { if (debug) { std::cout << queue << ": " << ((doColorize) ? fg_yellow : "") << "f_areacode_prefix - " << f_areacode_prefix << ((doColorize) ? normal : "") << std::endl; } query += " AND LEFT(phone,6)='" + f_areacode_prefix + "'"; } //zipcode based filter if (f_zipcode.empty() == false && f_zipcode != "0") { if (debug) { std::cout << queue << ": " << ((doColorize) ? fg_yellow : "") << "f_zipcode - " << f_zipcode << ((doColorize) ? normal : "") << std::endl; } query += " AND LEFT(zip,5)='" + f_zipcode + "'"; } //timezone based filter (currently US only) if (usetzfilter == "true") { tzearliest = TheQueues.at(i).GetSetting("tzearliest").Get(); tzlatest = TheQueues.at(i).GetSetting("tzlatest").Get(); query += " AND " + getFilter(tzearliest,tzlatest,isAHoliday); if (debug) { std::cout << queue << ": " << ((doColorize) ? fg_green : "") << "tzFilter Enabled " << ((doColorize) ? normal : "") << std::endl; } } else { if (debug) { std::cout << queue << ": " << ((doColorize) ? fg_yellow : "") << "tzFilter Disabled " << ((doColorize) ? normal : "") << std::endl; } } //this is a realtime 'do not call' filter that does a lookup against dialer.DNC table when calling //this is resource intensive so DO NOT load dialer.DNC with alot of numbers //i suggest you 'pre-process' your calling data against DNC numbers, as you dial, dispo 8's //will be added to dialer.DNC, so you can make sure this campaign you don't call them back //then at the end of a campaign, add them to your main set of DNC's to once again //'pre-process' against your main calling data for the next campaign. if (usednc == "true") { query += " AND phone NOT IN (SELECT phone FROM DNC) "; } //original order by line, keeping till i work all the bugs out of the multiple //order by methods below //query += " ORDER BY attempts + pickups ASC LIMIT " + itos(skip) + "," + itos(linestodial); //SELECT DISTINCT id,phone,lastupdated FROM 308CLD05 WHERE (id > 0) //AND (LEFT(lastupdated,10) = LEFT(NOW(),10) AND disposition = 1) //OR (LEFT(lastupdated,10) <> LEFT(NOW(),10)) AND //((disposition > -6 AND disposition < 6) AND attempts < 3) //ORDER BY id,id,lastupdated ASC LIMIT 0,3; if (orderby == "id" || orderby == "phone") { if (orderby == "id") { query += " ORDER BY id,id,lastupdated ASC "; } if (orderby == "phone") { query += " ORDER BY phone,id,lastupdated ASC "; } } else { query += " ORDER BY attempts+pickups,id,lastupdated ASC "; } // if (orderby == "id" || orderby == "phone") { // if (orderby == "id") { // query += " ORDER BY id ASC "; // } // if (orderby == "phone") { // query += " ORDER BY phone ASC "; // } // } else { // query += " ORDER BY attempts + pickups ASC "; // } //self explanitory query += " LIMIT " + itos(skip) + "," + itos(linestodial); if (debug) { std::cout << queue << ": " << ((doColorize) ? fg_white : "") << "query - " << query << ((doColorize) ? normal : "") << std::endl; } if (debug) { std::cout << queue << ": " << ((doColorize) ? fg_light_yellow : "") << "Dialing " << linestodial << " calls (" << skip << ") skipped" << ((doColorize) ? normal : "") << std::endl; } if(mysql_query(mysql, query.c_str()) != 0) { std::cout << "Error selecting leads from mysql! (check table structures)" << std::endl; //return 1; } else { result = mysql_use_result(mysql); query = "UPDATE " + queue + " SET attempts=attempts+1 WHERE "; for(counter = 0; (row = mysql_fetch_row(result)); counter++) { if (counter) { query += " OR "; } query += " id=" + std::string(row[0]); remaininglines--; TheCallCache->AddCall(row[1],queue,row[0],callerid,usecloser,dspmode,trunk,dialprefix,extravars,transfer,timeout); } if(mysql_errno(mysql)) { std::cout << "Error fetching rows from mysql!" << std::endl; return 1; } if (!counter) { std::cout << queue << ((doColorize) ? fg_light_red : "") << ": has ran out of leads! (CHECK YOUR FILTERS!!!)" << ((doColorize) ? normal : "") << std::endl; } else if (counter < linestodial) { std::cout << queue << ((doColorize) ? fg_light_red : "") << ": is running very low on leads!" << ((doColorize) ? normal : "") << std::endl; } mysql_free_result(result); if (counter) { TheQueues.rWhere(queue).AddCallsDialed(counter); TheQueues.rWhere(queue).WriteCalls(); if(mysql_query(mysql, query.c_str()) != 0) { std::cout << "Error updating leads in mysql!" << std::endl; return 1; } } } } } } try { TheCallCache->CallAll(mainHost); } catch(xOutOfHosts) { std::cout << "Exception: Ran out of hosts!" << std::endl; return 1; } catch(xForkError) { std::cout << "Exception: Unable to fork the parent process!" << std::endl; return 1; } } mysql_close(mysql); } // Not nested for convenience. catch(const std::exception & e) { std::cout << "Caught Exception: " << e.what() << std::endl; return 1; } catch(...) { std::cout << "Unhandled Exception: This is most likely a STL issue." << std::endl; return 1; } return 0; }