/* * GnuDialer - Complete, free predictive dialer * * Complete, free predictive dialer for contact centers. * * Copyright (C) 2005, GnuDialer Project * * Heath Schultz * Richard Lyman * * 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 "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 "log.h" #include "dispo.h" #include "settings.h" bool safeMode; void sig_handler(int sig) { if (sig == SIGSEGV) { if (safeMode == true) { std::cout << "FATAL ERROR! Segmentation Fault!" << 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 { std::cout << "FATAL ERROR! Segmentation Fault! 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); } } // signal(SIGSEGV,sig_handler); const bool debugPos = false; const bool debugLevel = 0; const bool debugLevel2 = true; const bool debugLevel3 = true; const bool debugCampaignSettings = false; #define HERE(x) if (debugPos) { std::cout << "Here:" << #x << std::endl; } 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())) { std::cout << "Transferring: " << channel << " to " << agent << " for " << campaign << "." << std::endl; writeGnudialerLog(campaign + ": Transferring - " + channel + " to " + agent + ""); ClientSocket AsteriskRedir("localhost",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: theagents\r\n"; } else { AsteriskRedir << "Context: theagents2\r\n"; } AsteriskRedir << "Priority: 1\r\n\r\n"; // buffer fix AsteriskRedir >> response; // usleep(3000000); AsteriskRedir << "Action: Logoff\r\n\r\n"; AsteriskRedir >> response; // end buffer fix usleep(10000000); } } int main(int argc, char** argv) { usleep(100000); safeMode = false; signal(SIGSEGV,sig_handler); if (argc > 1) { if (std::string(argv[1]) == "stop" || \ std::string(argv[1]) == "-stop" || \ std::string(argv[1]) == "--stop") { writeGnudialerLog("GnuDialer: Stopped"); std::cout << "GnuDialer: Stopped" << std::endl; std::system(("killall " + std::string(argv[0])).c_str()); exit(0); } if (std::string(argv[1]) == "--tzpopulate" || \ std::string(argv[1]) == "tzpopulate" || \ std::string(argv[1]) == "-tzpopulate") { if (argc > 2) { tzpopulate(argv[2]); statepopulate(argv[2]); return 0; } else { std::cerr << "GnuDialer: tzpopulate - Error! Missing campaign name!" << std::endl; return 1; } } if (std::string(argv[1]) == "-h" || \ std::string(argv[1]) == "--help" || \ std::string(argv[1]) == "-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::cout << std::endl << std::endl; return 0; } if (std::string(argv[1]) == "-s" || \ std::string(argv[1]) == "--safe" || \ std::string(argv[1]) == "-safe") { std::cout << "GnuDialer: SAFE MODE enabled!" << std::endl; safeMode = true; } } 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()); write(lfp,str,strlen(str)); bool isAHoliday; try { isAHoliday = isHoliday(); } catch(const xFileOpenError & e) { std::cerr << "GnuDialer: Exception! Unable to open " << e.GetFilename() << "!" << std::endl; return 1; } HERE(ABOUT TO INITIALIZE GLOBAL SETTINGS) bool gDebug, gLog; addGlobalSettings("general"); Queue TheQueueGlobals; TheQueueGlobals.ParseQueue("general"); gDebug = TheQueueGlobals.GetSetting("debug").GetBool(); gLog = TheQueueGlobals.GetSetting("log").GetBool(); std::string mainHost = getMainHost(); HERE(MYSQLBEGIN) MYSQL *mysql = NULL; MYSQL_RES *result; MYSQL_ROW row; HERE(MYSQLEND) mysql = mysql_init(NULL); if(mysql == NULL) { std::cerr << "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::cerr << "GnuDialer: MySql connection failed!" << std::endl; return 1; } try { // Not nested for convenience. if (gLog) { writeGnudialerLog("GnuDialer: Started"); } if (gDebug) { std::cout << "GnuDialer: Started" << std::endl; std::cout << "GnuDialer: loading gdhosts.conf" << std::endl; } CallCache * TheCallCache; try { TheCallCache = new CallCache(); } catch(xTooFewFields) { std::cerr << "Exception: Too few fields in gdhosts.conf!" << std::endl; return 1; } catch(xTooManyFields) { std::cerr << "Exception: Too many fields in gdhosts.conf!" << std::endl; return 1; } catch(xInvalidWeightValue) { std::cerr << "Exception: Invalid weight value in gdhosts.conf!" << std::endl; return 1; } catch(const xFileOpenError & e) { std::cerr << "Exception: Error opening " << e.GetFilename() << "!" << std::endl; return 1; } catch(xNoHostsDefined) { std::cerr << "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, query, tzearliest, tzlatest, callerid, channel, tempagent, usecloser, dspmode, filter, usecallback, usetzfilter; bool debug, log; int skip; std::string f_areacode, f_areacode_prefix, f_zipcode; std::string managerUser = getManagerUsername(); std::string managerPass = getManagerPassword(); std::stringstream BlockStream; unsigned int maxlines = 0, timeout = 0, linesdialing = 0, availagents = 0, linestodial = 0, counter = 0, pos = 0, end = 0, pos2 = 0, end2 = 0; unsigned long int calls = 0, abandons = 0; int pid = 0; double maxratio = 0.0, maxabandons = 0.0; ClientSocket AsteriskManager("localhost",5038); AsteriskManager.setRecvTimeout(2000); AsteriskManager >> response; AsteriskManager << "Action: login\r\nUsername: " + managerUser + "\r\nSecret: " + managerPass + "\r\n\r\n"; AsteriskManager >> response; HERE(ABOUT TO INITIALIZE QUEUES AND AGENTS) QueueList TheQueues; AgentList TheAgents; TheQueues.ParseQueues(); TheAgents.ParseAgentList(); TheAgents.Initialize(managerUser,managerPass); HERE(SETTINGS CHECK) std::string tempCampaign; for (int i = 0; i < TheQueues.size(); i++) { tempCampaign = TheQueues.at(i).GetName(); std::cout << tempCampaign << ": Settings Pre-Check " << std::endl; addBasicSettings(tempCampaign); } HERE(INITIALIZED QUEUES AND AGENTS) timeval tv; unsigned long int timeSinceLastQueueUpdate = 0, timeSinceLastCallbackCheck = 0, currentTime = 0; for(unsigned long int i = 0; true; i++) { gettimeofday(&tv,NULL); currentTime = tv.tv_sec % 1000000; if ((i != 0 && i % 10 == 0 && currentTime - timeSinceLastQueueUpdate > 5) \ || (currentTime - timeSinceLastQueueUpdate > 20 && i != 0)) { if (gDebug) { std::cout << "GnuDialer: Updating Campaign Settings" << std::endl; } TheAgents.ParseAgentList(); TheQueues.ParseQueues(); // this was commented // TheAgents.ParseAgentList(); timeSinceLastQueueUpdate = currentTime; } response = ""; HERE(10) AsteriskManager >> response; if (response.empty()) { response = "Event: NoEvent\r\n\r\n"; } BlockStream.clear(); BlockStream.str(response); 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); } signal(SIGCLD, SIG_IGN); if (TheQueues.exists(theCampaign)) { if (block.find("TRANSFER",0) == std::string::npos) { tempagent = TheQueues.LeastRecent(theCampaign,TheAgents); if (gDebug) { std::cout << theCampaign << ": Non-Transfer - tempagent: " << tempagent << std::endl; } } else { tempagent = TheQueues.LeastRecent(TheQueues.rWhere(theCampaign).GetSetting("closercam").Get(),TheAgents); if (gDebug) { std::cout << theCampaign << ": Transfer - tempagent: " << tempagent << std::endl; } } if (TheAgents.exists(atoi(tempagent.c_str()))) { TheAgents.where(atoi(tempagent.c_str())).SetConnectedChannel(channel); if (block.find("TRANSFER",0) == std::string::npos) { TheAgents.where(atoi(tempagent.c_str())).SetCampaign(theCampaign); } else { TheAgents.where(atoi(tempagent.c_str())).SetCampaign(TheQueues.rWhere(theCampaign).GetSetting("closercam").Get()); } if (gDebug) { std::cout << theCampaign << ": theLeadid - " << theLeadid << std::endl; } // std::cout << "Setting leadid to: " << theLeadid << std::endl; TheAgents.where(atoi(tempagent.c_str())).SetLeadId(theLeadid); } pid = fork(); if (pid == 0) { if (isNone == false) { if (block.find("TRANSFER",0) != std::string::npos) { doRedirect(channel,tempagent,block.substr(pos,end-pos),block.substr(pos2,end2-pos2),managerUser,managerPass, true); } else { doRedirect(channel,tempagent,block.substr(pos,end-pos),block.substr(pos2,end2-pos2),managerUser,managerPass, false); } exit(0); } } if (pid == -1) { throw xForkError(); } } } //exten => talk,4,UserEvent(Abandon|CallerIDName: ${CALLERIDNAME}) if (block.find("Event: UserEventAbandon",0) != std::string::npos) { std::string theCallerIDName, theCampaign, theAgent, theLeadid; 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); theLeadid = theCallerIDName.substr(pos2,end2-pos2); writeDBString(theCampaign,theLeadid,"abandons=abandons+1"); if (TheQueues.exists(block.substr(pos,end-pos))) { if (gDebug) { std::cout << theCampaign << ": theLeadid - " << theLeadid << " was abandoned" << std::endl; } if (gLog) { writeGnudialerLog(theCampaign + ": theLeadid - " + theLeadid + " was abanadoned"); } TheQueues.rWhere(theCampaign).IncrementAbandons(); TheQueues.rWhere(theCampaign).WriteCalls(); } } } //exten => s,3,UserEvent(Pickup|CallerIDName: ${CALLERIDNAME}) if (block.find("Event: UserEventPickup",0) != std::string::npos) { std::string theCallerIDName, theCampaign, theAgent, theLeadid; 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); theLeadid = theCallerIDName.substr(pos2,end2-pos2); writeDBString(theCampaign,theLeadid,"pickups=pickups+1"); } } //exten => s,3,UserEvent(Fax|CallerIDName: ${CALLERIDNAME}) if (block.find("Event: UserEventFax",0) != std::string::npos) { std::string theCallerIDName, theCampaign, theAgent, theLeadid; 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); theLeadid = theCallerIDName.substr(pos2,end2-pos2); writeDBString(theCampaign,theLeadid,"disposition='-6',pickups=pickups+1"); } } // exten => _X,3,UserEvent(Dispo|Dispo: ${EXTEN}|Agent: ${AGENTCALLED}|CallerIDName: ${CALLERIDNAME}) if (block.find("Event: UserEventDispo",0) != std::string::npos) { int iTheReason = 0; std::string theCallerIDName, theCampaign, theAgent, theLeadid, theDispo; std::string theTransfer, theAgentCloser, theDispoColumn; std::string usecloser, closercam; 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 (block.find("Agent: ",0) != std::string::npos) { pos = block.find("Agent: ",0) + 7; end = block.find("|",pos); theAgent = block.substr(pos,end-pos); } if (block.find("CallerIDName: ",0) != std::string::npos && block.find("~",0) != std::string::npos) { pos = block.find("CallerIDName: ",0) + 15; end = block.find("|",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); theLeadid = theCallerIDName.substr(pos2,end2-pos2); } if (block.find("Transfer: ",0) != std::string::npos) { usecloser = TheQueues.rWhere(theCampaign).GetSetting("usecloser").Get(); closercam = TheQueues.rWhere(theCampaign).GetSetting("closercam").Get(); pos = block.find("Transfer: ",0) + 10; end = block.find("\n",pos); theTransfer = block.substr(pos,end-pos); if (theTransfer == "TRANSFER") { theDispoColumn = "closerdispo"; theAgentCloser = "closer"; writeDispo(theAgent,closercam,theDispo); } else { theDispoColumn = "disposition"; theAgentCloser = "agent"; writeDispo(theAgent,theCampaign,theDispo); } } // writeDBString(theCampaign,theLeadid,"disposition='" + theDispo + "',agent='" + theAgent + "'"); writeDBString(theCampaign,theLeadid,"" + theDispoColumn + "='" + theDispo + "'," + theAgentCloser + "='" + theAgent + "'"); if (gDebug) { std::cout << theCampaign << ": UserEventDispo - theLeadid: " << theLeadid << " theDispo: " << theDispo << " theDispoColumn: " << theDispoColumn << " theAgentCloser: " << theAgentCloser <LinesDialing(queue); availagents = TheQueues.at(i).GetAvailAgents(TheAgents); 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(); 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(); dspmode = TheQueues.at(i).GetSetting("dspmode").Get(); usecallback = TheQueues.at(i).GetSetting("usecallback").Get(); usetzfilter = TheQueues.at(i).GetSetting("usetzfilter").Get(); calls = atoi(TheQueues.at(i).GetCalls().c_str()); abandons = atoi(TheQueues.at(i).GetAbandons().c_str()); linestodial = evaluate(mode,linesdialing,availagents,maxratio,maxlines,maxabandons,calls,abandons); 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(); unsigned int remaininglines = maxlines - linestodial; 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; } HERE(23) if (linestodial && mode != "closer" && mode != "inbound" && true) { if (debug) { if (calls != 0) { std::cout << std::setprecision(4) << queue << ": abn\%: " << static_cast(abandons) / static_cast(calls) * 100.0 << std::endl; } else { // No div by 0 allowed! std::cout << queue << ": abn\%: 0" << std::endl; } } // query = "SELECT id, phone FROM " + queue + " WHERE phone NOT IN (SELECT phone FROM DNC) "; query = "SELECT id, phone FROM " + queue + " WHERE 1 "; if (filter.empty() == false && filter != "0") { if (debug) { std::cout << queue << ": filter - " << filter << std::endl; } query += " AND " + filter; } 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") { if (debug) { std::cout << queue << ": filter - " << fstring << std::endl; } query += " AND " + fstring; } } if (f_areacode.empty() == false && f_areacode != "0") { if (debug) { std::cout << queue << ": f_areacode - " << f_areacode << std::endl; } query += " AND LEFT(phone,3)='" + f_areacode + "'"; } if (f_areacode_prefix.empty() == false && f_areacode_prefix != "0") { if (debug) { std::cout << queue << ": f_areacode_prefix - " << f_areacode_prefix << std::endl; } query += " AND LEFT(phone,6)='" + f_areacode_prefix + "'"; } if (f_zipcode.empty() == false && f_zipcode != "0") { if (debug) { std::cout << queue << ": f_zipcode - " << f_zipcode << std::endl; } query += " AND LEFT(zip,5)='" + f_zipcode + "'"; } 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 << ": tzFilter Enabled " << std::endl; } } else { if (debug) { std::cout << queue << ": tzFilter Disabled" << std::endl; } } //#ifdef MYSQLAGE query += " ORDER BY attempts + pickups ASC LIMIT " + itos(skip) + "," + itos(linestodial); //#else // query += " ORDER BY attempts + pickups ASC LIMIT " + itos(linestodial); //#endif if (debug) { std::cout << queue << ": query - " << query << std::endl; } if (debug) { std::cout << queue << ": Dialing " << linestodial << " calls (" << skip << ") skipped" << std::endl; } if(mysql_query(mysql, query.c_str()) != 0) { std::cerr << "Error selecting leads from mysql! Did you run --tzpopulate?" << 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]); TheCallCache->AddCall(row[1],queue,row[0],callerid,usecloser,dspmode,timeout); } if(mysql_errno(mysql)) { std::cerr << "Error fetching rows from mysql!" << std::endl; return 1; } if (!counter) { std::cerr << queue << ": has ran out of leads! (check your filters)" << std::endl; } else if (counter < linestodial) { std::cerr << queue << " is running very low on leads!" << 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::cerr << "Error updating leads in mysql!" << std::endl; return 1; } } } } if (remaininglines && usecallback == "true" && true) { if ((i != 0 && i % 10 == 0 && currentTime - timeSinceLastCallbackCheck > 5) \ || (currentTime - timeSinceLastCallbackCheck > 20 && i != 0)) { if (debug) { std::cout << "remaininglines: " << remaininglines << std::endl; } query = "SELECT id, phone FROM " + queue + " WHERE "; if (filter.empty() == false && filter != "0") { if (debug) { std::cout << queue << ": filter - " << filter << std::endl; } query += filter + " AND "; } if (usetzfilter == "true") { tzearliest = TheQueues.at(i).GetSetting("tzearliest").Get(); tzlatest = TheQueues.at(i).GetSetting("tzlatest").Get(); query += getFilter(tzearliest,tzlatest,isAHoliday) + " AND "; if (debug) { std::cout << queue << ": tzFilter Enabled " << std::endl; } } else { if (debug) { std::cout << queue << ": tzFilter Disabled" << std::endl; } } query += " disposition = 0 AND"; query += " cb_datetime > '0000-00-00 00:00:00' AND cb_datetime < now()"; query += " ORDER BY attempts + pickups ASC LIMIT " + itos(remaininglines); if(mysql_query(mysql, query.c_str()) != 0) { std::cerr << "Error selecting leads from mysql! Did you run --tzpopulate?" << std::endl; return 1; } result = mysql_use_result(mysql); query = "UPDATE " + queue + " SET attempts=attempts+1,cb_datetime='' WHERE "; for(counter = 0; row = mysql_fetch_row(result); counter++) { if (counter) { query += " OR "; } query += " id=" + std::string(row[0]); TheCallCache->AddCall(row[1],queue,row[0],callerid,usecloser,dspmode,timeout); std::cout << "Dialing Callback: " << row[1] << std::endl; } if(mysql_errno(mysql)) { std::cerr << "Error fetching rows from mysql!" << std::endl; return 1; } if (!counter) { std::cerr << queue << " has no Callbacks to make" << 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::cerr << "Error updating leads in mysql!" << std::endl; return 1; } } timeSinceLastCallbackCheck = currentTime; } } } } try { TheCallCache->CallAll(mainHost); } catch(xOutOfHosts) { std::cerr << "Exception: Ran out of hosts!" << std::endl; return 1; } catch(xForkError) { std::cerr << "Exception: Unable to fork the parent process!" << std::endl; return 1; } } mysql_close(mysql); } // Not nested for convenience. catch(...) { std::cerr << "Unhandled exception! Most likely something in the STL is getting messed up." << std::endl; std::cerr << "Please report this error to the gnudialer project immediately." << std::endl; return 1; } return 0; }