From cee52889a0216ce9e14c04fb9f3e427b101a1694 Mon Sep 17 00:00:00 2001 From: mattf Date: Fri, 9 Jun 2017 20:13:55 +0000 Subject: [PATCH] Added basic one-way Cross-Cluster-Communication feature Added ccc_lead_info API function If phone entry fullname and cidnumber are empty, don't populate a callerid conf line in ADMIN_keepalive_ALL.pl script git-svn-id: svn://192.168.202.10@2776 3d104415-ff17-0410-8863-d5cf3c621b8a --- UPGRADE | 4 + agi/cm_sc_ccc_lookup_insert.agi | 504 +++++++++++++++++++++++++++ bin/ADMIN_keepalive_ALL.pl | 23 +- docs/CROSS_CLUSTER_COMMUNICATION.txt | 66 +++- docs/NON-AGENT_API.txt | 34 +- www/vicidial/admin.php | 7 +- www/vicidial/help.php | 4 +- www/vicidial/non_agent_api.php | 210 ++++++++++- 8 files changed, 827 insertions(+), 25 deletions(-) create mode 100644 agi/cm_sc_ccc_lookup_insert.agi diff --git a/UPGRADE b/UPGRADE index 8b2ceab5..c04ba5c2 100644 --- a/UPGRADE +++ b/UPGRADE @@ -165,6 +165,10 @@ OTHER CHANGES: 36. Added Add-to-hopper options to update_lead function in the Non-Agent API +37. Added basic one-way Cross-Cluster-Communication feature. Allowing for lead + information to pass from one VICIdial system to another with a call. + See the CROSS_CLUSTER_COMMUNICATION.txt document for more information. + diff --git a/agi/cm_sc_ccc_lookup_insert.agi b/agi/cm_sc_ccc_lookup_insert.agi new file mode 100644 index 00000000..7fdef1ad --- /dev/null +++ b/agi/cm_sc_ccc_lookup_insert.agi @@ -0,0 +1,504 @@ +#!/usr/bin/perl +# +# cm_sc_ccc_lookup_insert.agi version 2.14 +# +# Designed to work with Call Menus to send a URL defined in a Settings Container +# for a call with a call_id associated with it for calls coming from an external +# VICIdial system on a private IAX trunk so that the lead information can be +# copied to this destination cluster. +# +# If container is not found, call will go to the 'C' option in the call menu +# If call_id is not defined, call will go to the 'D' option in the call menu +# If lead is not found on external system, call will go to the 'B' option in the call menu +# If lead is found on external system, call will go to the 'A' option in the call menu +# +# Flag Options: (separated by triple-pipe: "---") +# 1- container_id for settings container with URL to send +# 2- local list_id to insert lead into(if not populated, will use external list_id) +# +# example of what to set in the Call Menu: +# Set the prompt to "wait-moment|cm_sc_ccc_lookup_insert.agi,ccc_test---8199" +# +# The URL that you define in the Settings Container will need to be sent to you +# by the administrator of the external system. It should look something like this: +# http://server/vicidial/non_agent_api.php?user=6666&pass=1234&source=test&function=ccc_lead_info&call_id=--A--call_id--B-- +# +# Copyright (C) 2017 Matt Florell LICENSE: AGPLv2 +# +# changes: +# 170609-1326 - First build +# + +$script = 'cm_sc_ccc_lookup_insert.agi'; + +($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); +$year = ($year + 1900); +$mon++; +if ($mon < 10) {$mon = "0$mon";} +if ($mday < 10) {$mday = "0$mday";} +if ($hour < 10) {$hour = "0$hour";} +if ($min < 10) {$min = "0$min";} +if ($sec < 10) {$sec = "0$sec";} + +$secX = time(); +$now_date_epoch = time(); +$now_date = "$year-$mon-$mday $hour:$min:$sec"; +$start_time=$now_date; +$CIDdate = "$mon$mday$hour$min$sec"; +$tsSQLdate = "$year$mon$mday$hour$min$sec"; +$SQLdate = "$year-$mon-$mday $hour:$min:$sec"; +$SQLdateBEGIN = $SQLdate; +$state=''; +$CIDlead_id=''; +$US='_'; +$AGILOG=1; + while (length($CIDdate) > 9) {$CIDdate =~ s/^.//gi;} # 0902235959 changed to 902235959 + + +# default path to astguiclient configuration file: +$PATHconf = '/etc/astguiclient.conf'; + +open(conf, "$PATHconf") || die "can't open $PATHconf: $!\n"; +@conf = ; +close(conf); +$i=0; +foreach(@conf) + { + $line = $conf[$i]; + $line =~ s/ |>|\n|\r|\t|\#.*|;.*//gi; + if ( ($line =~ /^PATHhome/) && ($CLIhome < 1) ) + {$PATHhome = $line; $PATHhome =~ s/.*=//gi;} + if ( ($line =~ /^PATHlogs/) && ($CLIlogs < 1) ) + {$PATHlogs = $line; $PATHlogs =~ s/.*=//gi;} + if ( ($line =~ /^PATHagi/) && ($CLIagi < 1) ) + {$PATHagi = $line; $PATHagi =~ s/.*=//gi;} + if ( ($line =~ /^PATHweb/) && ($CLIweb < 1) ) + {$PATHweb = $line; $PATHweb =~ s/.*=//gi;} + if ( ($line =~ /^PATHsounds/) && ($CLIsounds < 1) ) + {$PATHsounds = $line; $PATHsounds =~ s/.*=//gi;} + if ( ($line =~ /^PATHmonitor/) && ($CLImonitor < 1) ) + {$PATHmonitor = $line; $PATHmonitor =~ s/.*=//gi;} + if ( ($line =~ /^VARserver_ip/) && ($CLIserver_ip < 1) ) + {$VARserver_ip = $line; $VARserver_ip =~ s/.*=//gi;} + if ( ($line =~ /^VARDB_server/) && ($CLIDB_server < 1) ) + {$VARDB_server = $line; $VARDB_server =~ s/.*=//gi;} + if ( ($line =~ /^VARDB_database/) && ($CLIDB_database < 1) ) + {$VARDB_database = $line; $VARDB_database =~ s/.*=//gi;} + if ( ($line =~ /^VARDB_user/) && ($CLIDB_user < 1) ) + {$VARDB_user = $line; $VARDB_user =~ s/.*=//gi;} + if ( ($line =~ /^VARDB_pass/) && ($CLIDB_pass < 1) ) + {$VARDB_pass = $line; $VARDB_pass =~ s/.*=//gi;} + if ( ($line =~ /^VARDB_port/) && ($CLIDB_port < 1) ) + {$VARDB_port = $line; $VARDB_port =~ s/.*=//gi;} + $i++; + } + +if (!$VARDB_port) {$VARDB_port='3306';} +if (!$AGILOGfile) {$AGILOGfile = "$PATHlogs/agiout.$year-$mon-$mday";} + +### find wget binary +$exit_no_wget=0; +$wgetbin = ''; +if ( -e ('/bin/wget')) {$wgetbin = '/bin/wget';} +else + { + if ( -e ('/usr/bin/wget')) {$wgetbin = '/usr/bin/wget';} + else + { + if ( -e ('/usr/local/bin/wget')) {$wgetbin = '/usr/local/bin/wget';} + else + { + if ($AGILOG) {$agi_string = "Can't find wget binary! Exiting..."; &agi_output;} + $exit_no_wget=1; + } + } + } + +use DBI; +use Asterisk::AGI; +$AGI = new Asterisk::AGI; + + +$|=1; +while() + { + chomp; + last unless length($_); + if ($AGILOG) + { + if (/^agi_(\w+)\:\s+(.*)$/) + { + $AGI{$1} = $2; + } + } + + if (/^agi_context\:\s+(.*)$/) {$context = $1;} + if (/^agi_uniqueid\:\s+(.*)$/) {$unique_id = $1; $uniqueid = $unique_id;} + if (/^agi_channel\:\s+(.*)$/) {$channel = $1;} + if (/^agi_extension\:\s+(.*)$/) {$extension = $1;} + if (/^agi_type\:\s+(.*)$/) {$type = $1;} + if (/^agi_callerid\:\s+(.*)$/) {$callerid = $1;} + if (/^agi_calleridname\:\s+(.*)$/) {$calleridname = $1;} + } +foreach $i (sort keys %AGI) + { + if ($AGILOG) {$agi_string = " -- $i = $AGI{$i}"; &agi_output;} + } + +$callerid =~ s/\'|\\\\|\\\|\\|\\;|\\\;|\;|;//gi; +$calleridname =~ s/\'|\\\\|\\\|\\|\\;|\\\;|\;|;//gi; +$extension =~ s/\'|\"|\\\\|\\\|\\|\\;|\\\;|\;|;//gi; + +$blind_xfer=0; +$three_way=0; + +if ($calleridname =~ /^V\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d|^Y\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d|^M\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d|^J\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d/) + { + $blind_xfer=1; + } +elsif ($calleridname =~ /^DC\d\d\d\d\d\dW\d\d\d\d\d\d\d\d\d\dW/) + { + $three_way=1; + } +else + { + if ($AGILOG) {$agi_string = "call_id not set($calleridname), exiting the cm_sc_ccc_lookup_insert.agi app, transferring call to D @ $context"; &agi_output;} + print "SET CONTEXT $context\n"; + $result = ; + checkresult($result); + print "SET EXTENSION D\n"; + $result = ; + checkresult($result); + print "SET PRIORITY 1\n"; + $result = ; + checkresult($result); + + exit; + } + +if ($exit_no_wget > 0) + { + if ($AGILOG) {$agi_string = "wget not found, exiting the cm_sc_ccc_lookup_insert.agi app, transferring call to D @ $context"; &agi_output;} + print "SET CONTEXT $context\n"; + $result = ; + checkresult($result); + print "SET EXTENSION D\n"; + $result = ; + checkresult($result); + print "SET PRIORITY 1\n"; + $result = ; + checkresult($result); + + exit; + } + +if ($AGILOG) {$agi_string = "AGI Variables: |$unique_id|$channel|$extension|$blind_xfer|$three_way|$callerid|"; &agi_output;} + +$AGI->stream_file('sip-silence'); +$AGI->stream_file('sip-silence'); +$AGI->stream_file('sip-silence'); + + +$dbhA = DBI->connect("DBI:mysql:$VARDB_database:$VARDB_server:$VARDB_port", "$VARDB_user", "$VARDB_pass") + or die "Couldn't connect to database: " . DBI->errstr; + +### Grab Server values from the database +$stmtA = "SELECT agi_output FROM servers where server_ip = '$VARserver_ip';"; +$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; +$sthA->execute or die "executing: $stmtA ", $dbhA->errstr; +$sthArows=$sthA->rows; +$rec_count=0; +while ($sthArows > $rec_count) + { + $AGILOG = '0'; + @aryA = $sthA->fetchrow_array; + $DBagi_output = $aryA[0]; + if ($DBagi_output =~ /STDERR/) {$AGILOG = '1';} + if ($DBagi_output =~ /FILE/) {$AGILOG = '2';} + if ($DBagi_output =~ /BOTH/) {$AGILOG = '3';} + $rec_count++; + } +$sthA->finish(); + + +### begin parsing run-time options ### +if (length($ARGV[0])>1) + { + if ($AGILOG) {$agi_string = "Perl Environment Dump:"; &agi_output;} + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + if ($AGILOG) {$agi_string = "$i|$ARGV[$i]"; &agi_output;} + $i++; + } + + ### list of command-line array arguments: + @ARGV_vars = split(/---/, $ARGV[0]); + + $container_id = $ARGV_vars[0]; + $local_list_id = $ARGV_vars[1]; + } + +$no_container=0; +if (length($container_id) < 1) + {$no_container=1;} +else + { + $stmtA= "SELECT container_entry from vicidial_settings_containers where container_id='$container_id';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + if ($AGILOG) {$agi_string = "$sthArows|$stmtA|"; &agi_output;} + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $sc_call_url = $aryA[0]; + } + else + {$no_container=2;} + $sthA->finish(); + } + +if ($no_container > 0) + { + if ($AGILOG) {$agi_string = "container_id not set($container_id|$no_container), exiting the cm_sc_ccc_lookup_insert.agi app, transferring call to C @ $context"; &agi_output;} + print "SET CONTEXT $context\n"; + $result = ; + checkresult($result); + print "SET EXTENSION C\n"; + $result = ; + checkresult($result); + print "SET PRIORITY 1\n"; + $result = ; + checkresult($result); + + exit; + } + + + +$sc_call_url =~ s/--A--call_id--B--/$calleridname/gi; +$sc_call_url =~ s/ /+/gi; +$sc_call_url =~ s/&/\\&/gi; + +$external_found=0; + +### insert a new url log entry +$SQL_log = "$sc_call_url"; +$SQL_log =~ s/;|\||\\//gi; +$stmtA = "INSERT INTO vicidial_url_log SET uniqueid='$uniqueid',url_date='$now_date',url_type='ccc_look',url='$SQL_log',url_response='';"; +$affected_rows = $dbhA->do($stmtA); +$stmtB = "SELECT LAST_INSERT_ID() LIMIT 1;"; +$sthA = $dbhA->prepare($stmtB) or die "preparing: ",$dbhA->errstr; +$sthA->execute or die "executing: $stmtA ", $dbhA->errstr; +$sthArows=$sthA->rows; +if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $url_id = $aryA[0]; + } +$sthA->finish(); + +$url = $sc_call_url; +$url =~ s/'/\\'/gi; +$url =~ s/"/\\"/gi; + +$secW = time(); + +`$wgetbin --no-check-certificate --output-document=/tmp/ASUBtmpD$US$url_id$US$secX --output-file=/tmp/ASUBtmpF$US$url_id$US$secX $url `; + +$secY = time(); +$response_sec = ($secY - $secW); + +open(Wdoc, "/tmp/ASUBtmpD$US$url_id$US$secX") || die "can't open /tmp/ASUBtmpD$US$url_id$US$secX: $!\n"; +@Wdoc = ; +close(Wdoc); +$i=0; +$Wdocline_cat=''; +foreach(@Wdoc) + { + $Wdocline = $Wdoc[$i]; + $Wdocline =~ s/\n|\r//gi; + $Wdocline =~ s/\t|\`|\"//gi; + $Wdocline_cat .= "$Wdocline"; + $i++; + } +if (length($Wdocline_cat) < 1) + { + $external_found=0; + $Wdocline_cat=''; + } + +if ( (length($Wdocline_cat) > 29) && ($Wdocline_cat !~ /ERROR: ccc_lead_info /) ) + { + @lead_data = split(/\|/, $Wdocline_cat); + $LEADstatus = $lead_data[0]; + $LEADuser = $lead_data[1]; + $LEADvendor_lead_code = $lead_data[2]; + $LEADsource_id = $lead_data[3]; + $LEADlist_id = $lead_data[4]; + $LEADgmt_offset_now = $lead_data[5]; + $LEADphone_code = $lead_data[6]; + $LEADphone_number = $lead_data[7]; + $LEADtitle = $lead_data[8]; + $LEADfirst_name = $lead_data[9]; + $LEADmiddle_initial = $lead_data[10]; + $LEADlast_name = $lead_data[11]; + $LEADaddress1 = $lead_data[12]; + $LEADaddress2 = $lead_data[13]; + $LEADaddress3 = $lead_data[14]; + $LEADcity = $lead_data[15]; + $LEADstate = $lead_data[16]; + $LEADprovince = $lead_data[17]; + $LEADpostal_code = $lead_data[18]; + $LEADcountry_code = $lead_data[19]; + $LEADgender = $lead_data[20]; + $LEADdate_of_birth = $lead_data[21]; + $LEADalt_phone = $lead_data[22]; + $LEADemail = $lead_data[23]; + $LEADsecurity_phrase = $lead_data[24]; + $LEADcomments = $lead_data[25]; + $LEADcalled_count = $lead_data[26]; + $LEADlast_local_call_time = $lead_data[27]; + $LEADrank = $lead_data[28]; + $LEADowner = $lead_data[29]; + + if (length($LEADlist_id) < 2) + {$external_found=0;} + else + { + # insert lead into local system + if (length($local_list_id) > 1) + {$LEADlist_id = $local_list_id;} + + $stmtA = "INSERT INTO vicidial_list SET status=\"$LEADstatus\",user=\"$LEADuser\",vendor_lead_code=\"$LEADvendor_lead_code\",source_id=\"$LEADsource_id\",list_id=\"$LEADlist_id\",gmt_offset_now=\"$LEADgmt_offset_now\",phone_code=\"$LEADphone_code\",phone_number=\"$LEADphone_number\",title=\"$LEADtitle\",first_name=\"$LEADfirst_name\",middle_initial=\"$LEADmiddle_initial\",last_name=\"$LEADlast_name\",address1=\"$LEADaddress1\",address2=\"$LEADaddress2\",address3=\"$LEADaddress3\",city=\"$LEADcity\",state=\"$LEADstate\",province=\"$LEADprovince\",postal_code=\"$LEADpostal_code\",country_code=\"$LEADcountry_code\",gender=\"$LEADgender\",date_of_birth=\"$LEADdate_of_birth\",alt_phone=\"$LEADalt_phone\",email=\"$LEADemail\",security_phrase=\"$LEADsecurity_phrase\",comments=\"$LEADcomments\",called_count=\"$LEADcalled_count\",last_local_call_time=\"$LEADlast_local_call_time\",rank=\"$LEADrank\",owner=\"$LEADowner\";"; + $affected_rows = $dbhA->do($stmtA); + $stmtB = "SELECT LAST_INSERT_ID() LIMIT 1;"; + $sthA = $dbhA->prepare($stmtB) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + if ($sthArows > 0) + { + @aryA = $sthA->fetchrow_array; + $new_lead_id = $aryA[0]; + } + $sthA->finish(); + + $PADlead_id = sprintf("%010s", $new_lead_id); while (length($PADlead_id) > 10) {chop($PADlead_id);} + # YmmddhhmmssLLLLLLLLL + $YqueryCID = "Y$CIDdate$PADlead_id"; + $callerid = $YqueryCID; + $VCcallerid = $YqueryCID; + ### set the callerid + $Ynewcallerid = "\"$YqueryCID <$LEADphone_number>\""; + $AGI->set_callerid($Ynewcallerid); + if ($AGILOG) {$agi_string = "callerID changed: $Ynewcallerid"; &agi_output;} + + $external_found=1; + } + } + + +open(Wfile, "/tmp/ASUBtmpF$US$url_id$US$secX") || die "can't open /tmp/ASUBtmpF$US$url_id$US$secX: $!\n"; +@Wfile = ; +close(Wfile); +$i=0; +$Wfileline_cat=''; +foreach(@Wfile) + { + $Wfileline = $Wfile[$i]; + $Wfileline =~ s/\n|\r/!/gi; + $Wfileline =~ s/\"|\`/'/gi; + $Wfileline =~ s/ |\t|\`//gi; + $Wfileline_cat .= "$Wfileline"; + $i++; + } +if (length($Wfileline_cat)<1) + {$Wfileline_cat='
';} + + +### update url log entry +$stmtA = "UPDATE vicidial_url_log SET url_response=\"$Wdocline_cat|$Wfileline_cat\",response_sec='$response_sec' where url_log_id='$url_id';"; +$affected_rows = $dbhA->do($stmtA); +if ($AGILOG) {$agi_string = "$affected_rows|$stmtA"; &agi_output;} + + + +if ($external_found < 1) + { + if ($AGILOG) {$agi_string = "call_id not found on external system, exiting the cm_sc_ccc_lookup_insert.agi app, transferring call to B @ $context"; &agi_output;} + print "SET CONTEXT $context\n"; + $result = ; + checkresult($result); + print "SET EXTENSION B\n"; + $result = ; + checkresult($result); + print "SET PRIORITY 1\n"; + $result = ; + checkresult($result); + } +else + { + if ($AGILOG) {$agi_string = "call_id found, new lead ID($new_lead_id), exiting the cm_sc_ccc_lookup_insert.agi app, transferring call to A @ $context"; &agi_output;} + print "SET CONTEXT $context\n"; + $result = ; + checkresult($result); + print "SET EXTENSION A\n"; + $result = ; + checkresult($result); + print "SET PRIORITY 1\n"; + $result = ; + checkresult($result); + } + +exit; + + + + +##### SUBROUTINES ##### + +sub agi_output +{ +if ($AGILOG >=2) + { + ### open the log file for writing ### + open(Lout, ">>$AGILOGfile") + || die "Can't open $AGILOGfile: $!\n"; + print Lout "$now_date|$script|$agi_string\n"; + close(Lout); + } + ### send to STDERR writing ### +if ( ($AGILOG == '1') || ($AGILOG == '3') ) + {print STDERR "$now_date|$script|$agi_string\n";} +$agi_string=''; +} + + +sub checkresult + { + my ($res) = @_; + my $retval; + $tests++; + chomp $res; + if ($res =~ /^200/) + { + $res =~ /result=(-?\d+)/; + if (!length($1)) + { + # print STDERR "FAIL ($res)\n"; + $fail++; + } + else + { + # print STDERR "PASS ($1)\n"; + $pass++; + } + } + else + { + # print STDERR "FAIL (unexpected result '$res')\n"; + $fail++; + } + } diff --git a/bin/ADMIN_keepalive_ALL.pl b/bin/ADMIN_keepalive_ALL.pl index 464089cc..169e6bd4 100644 --- a/bin/ADMIN_keepalive_ALL.pl +++ b/bin/ADMIN_keepalive_ALL.pl @@ -118,9 +118,10 @@ # 170320-1338 - Added conf_qualify phones option for IAX # 170327-0847 - Added drop list triggering code # 170513-1728 - Added alternative uptime counter in seconds +# 170609-1601 - If phone entry fullname and cidnumber are empty, don't populate a callerid conf line # -$build = '170513-1728'; +$build = '170609-1601'; $DB=0; # Debug flag $teodDB=0; # flag to log Timeclock End of Day processes to log file @@ -2358,7 +2359,10 @@ if ( ($active_asterisk_server =~ /Y/) && ($generate_vicidial_conf =~ /Y/) && ($r $Piax .= "username=$extension[$i]\n"; $Piax .= "secret=$conf_secret[$i]\n"; $Piax .= "accountcode=$extension[$i]\n"; - $Piax .= "callerid=\"$fullname[$i]\" <$outbound_cid[$i]>\n"; + if ( (length($fullname[$i])>0) || (length($outbound_cid[$i])>0) ) + { + $Piax .= "callerid=\"$fullname[$i]\" <$outbound_cid[$i]>\n"; + } $Piax .= "mailbox=$voicemail[$i]\n"; if ($conf_qualify[$i] =~ /Y/) {$Piax .= "qualify=yes\n";} @@ -2383,7 +2387,10 @@ if ( ($active_asterisk_server =~ /Y/) && ($generate_vicidial_conf =~ /Y/) && ($r $Piax .= "username=$extension[$i]\n"; $Piax .= "secret=$conf_secret[$i]\n"; $Piax .= "accountcode=$extension[$i]\n"; - $Piax .= "callerid=\"$fullname[$i]\" <$outbound_cid[$i]>\n"; + if ( (length($fullname[$i])>0) || (length($outbound_cid[$i])>0) ) + { + $Piax .= "callerid=\"$fullname[$i]\" <$outbound_cid[$i]>\n"; + } $Piax .= "mailbox=$voicemail[$i]\n"; $Piax .= "requirecalltoken=no\n"; $Piax .= "context=$phone_context[$i]\n"; @@ -2515,7 +2522,10 @@ if ( ($active_asterisk_server =~ /Y/) && ($generate_vicidial_conf =~ /Y/) && ($r $Psip .= "username=$extension[$i]\n"; $Psip .= "secret=$conf_secret[$i]\n"; $Psip .= "accountcode=$extension[$i]\n"; - $Psip .= "callerid=\"$fullname[$i]\" <$outbound_cid[$i]>\n"; + if ( (length($fullname[$i])>0) || (length($outbound_cid[$i])>0) ) + { + $Psip .= "callerid=\"$fullname[$i]\" <$outbound_cid[$i]>\n"; + } $Psip .= "mailbox=$voicemail[$i]\n"; if ($codecs_with_template[$i] > 0) {$Psip .= "$Pcodec";} @@ -2538,7 +2548,10 @@ if ( ($active_asterisk_server =~ /Y/) && ($generate_vicidial_conf =~ /Y/) && ($r $Psip .= "username=$extension[$i]\n"; $Psip .= "secret=$conf_secret[$i]\n"; $Psip .= "accountcode=$extension[$i]\n"; - $Psip .= "callerid=\"$fullname[$i]\" <$outbound_cid[$i]>\n"; + if ( (length($fullname[$i])>0) || (length($outbound_cid[$i])>0) ) + { + $Psip .= "callerid=\"$fullname[$i]\" <$outbound_cid[$i]>\n"; + } $Psip .= "mailbox=$voicemail[$i]\n"; $Psip .= "context=$phone_context[$i]\n"; $Psip .= "$Pcodec"; diff --git a/docs/CROSS_CLUSTER_COMMUNICATION.txt b/docs/CROSS_CLUSTER_COMMUNICATION.txt index 979a41f9..5d2a3815 100644 --- a/docs/CROSS_CLUSTER_COMMUNICATION.txt +++ b/docs/CROSS_CLUSTER_COMMUNICATION.txt @@ -1,7 +1,59 @@ -CROSS-CLUSTER COMMUNICATION Started: 2011-05-27 Updated: 2017-01-01 +CROSS-CLUSTER COMMUNICATION Started: 2011-05-27 Updated: 2017-06-09 -!!!!! THIS FEATURE DOES NOT EXIST, THIS IS FOR PLANNING PURPOSES ONLY !!!!! +-------------------------------- + SIMPLER IMPLEMENTED OPTION: implemented in SVN/trunk revision 2776 +-------------------------------- +Below is a description of a simple cross-cluster option, which is to send lead data in one direction from one cluster to another as a phone call is sent over. + + +- A call to be sent from one cluster to another should leave its callerIDname as the Caller Code, the 20-character code that includes the lead_id + +- This call will go through an IAX trunk between the two systems into an internal DID on the destination cluster + Set up an IAX "carrier" on the originating cluster and an IAX "phone" on the destination cluster to link the two together. + (Note: the phone entry on the destination cluster must have the Outbound CallerID and Fullname fields blank) + The destination phone entry needs to use "trunkinbound" as it's phone and exten context + +- At the DID, the call will get sent to a Call Menu where the call will go through an AGI script + Set the prompt to "wait-moment|cm_sc_ccc_lookup_insert.agi,ccc_test---8199" + # Flag Options: (separated by triple-pipe: "---") + # 1- container_id for settings container with URL to send + # 2- local list_id to insert lead into(if not populated, will use external system's list_id for the lead) + +- The AGI script will use parameters defined in a Settings Container for the URL of the originating system's Non-Agent API and credentials + The originating server will need to set up a user of level 8 with view reports and Agent API abilities, and the ccc_lead_info API function enabled + You will need to add a Settings Container to hold the URL for the originating system to look up the lead data, something like this: + http://server/vicidial/non_agent_api.php?user=6666&pass=1234&source=test&function=ccc_lead_info&call_id=--A--call_id--B-- + +- That AGI script will look up the lead on the originating system using the Non-Agent API and credentials set in a Settings Container + +- The originating system will validate that the caller_code was a valid recent call before sending any data(within last 10 hours) + +- If there is a match, then the AGI script will gather the default lead information, insert the information into the new system and change the callerIDname with the destination system's lead_id included + +- The call will then go to option "A" and should probably be routed to an In-Group with the handle method set to "CLOSER" so it can go to an agent + + +NOTES: + # If lead is not found on external system, call will go to the 'B' option in the call menu + # If container is not found, call will go to the 'C' option in the call menu + # If call_id is not defined, call will go to the 'D' option in the call menu + + + + + + + + + + + + + +BELOW THIS LINE ARE THE OLD PLANNING NOTES FOR A MUCH MORE COMPLEX CROSS-CLUSTER SETUP DESIGN +--------------------------------------------------------------------------------------------------------------------------------------------- +!!!!! THIS FEATURE DOES NOT EXIST AS DESCRIBED BELOW, THIS IS FOR PLANNING PURPOSES ONLY !!!!! This is a planning document for how different vicidial clusters can communicate @@ -103,13 +155,3 @@ cluster_server_status: --------------------------------- - SIMPLER ALTERNATIVE OPTION: --------------------------------- -Below is a description of a more simple option, which is to send lead data from one cluster to another as the lead is sent over. -- A call to be sent from one cluster to another should leave its callerIDname as the Caller Code, the 20-character code that includes the lead_id -- This call will go into an internal DID on the other cluster through an IAX trunk between the two -- At the DID, the call will get sent to a Call Menu where the call will go through an AGI script -- That AGI script will look up the lead_id on the originating system using the Non-Agent API and credentials set in a Settings Container -- If there is a match, then the AGI script will gather the default lead information, insert the information into the new system and change the callerIDname with the new system's lead_id included -- The call will then go to an In-Group with that lead_id set so it can then go on to an agent diff --git a/docs/NON-AGENT_API.txt b/docs/NON-AGENT_API.txt index dcd8ae29..ef273dee 100644 --- a/docs/NON-AGENT_API.txt +++ b/docs/NON-AGENT_API.txt @@ -1,4 +1,4 @@ -NON-AGENT API DOCUMENT Started: 2008-07-24 Updated: 2017-06-01 +NON-AGENT API DOCUMENT Started: 2008-07-24 Updated: 2017-06-09 This document describes the functions of an API(Application Programming Interface) for all functions NOT directly relating to the VICIDIAL Agent screen. @@ -42,6 +42,7 @@ check_phone_number - allows you to check if a phone number is valid and dialable logged_in_agents - list of agents that are logged in to the system update_campaign - updates campaign settings in the system phone_number_log - exports list of calls placed to one of more phone numbers +ccc_lead_info - outputs lead data for cross-cluster-communication call New scripts: @@ -126,6 +127,7 @@ Changes: 170508-1048 - Added blind_monitor logging 170527-2254 - Fix for rare inbound logging issue #1017 170601-0747 - Added add_to_hopper options to update_lead function +170609-1107 - Added ccc_lead_info function API Functions use the 'function' variable @@ -575,6 +577,36 @@ A SUCCESS response will not show "SUCCESS", but instead will just print the valu +-------------------------------------------------------------------------------- +ccc_lead_info - outputs lead data for cross-cluster-communication call + +NOTE: api user for this function must have user_level set to 7 or higher and "view reports" enabled + +REQUIRED FIELDS- +source - description of what originated the API call (maximum 20 characters) +call_id - 16-40 characters + +SETTINGS FIELDS- +stage - the format of the exported data: csv, tab, newline, pipe(default) +header - include a header(YES) or not(NO). This is optional, default is not to include a header + +Example URL strings for API calls: +http://server/vicidial/non_agent_api.php?source=test&user=6666&pass=1234&function=ccc_lead_info&call_id=M4050908070000012345&stage=csv&header=YES + +Example responses: +ERROR: ccc_lead_info USER DOES NOT HAVE PERMISSION TO GET LEAD INFO - 6666|0 +ERROR: ccc_lead_info INVALID SEARCH PARAMETERS - 6666|| +ERROR: ccc_lead_info CALL NOT FOUND - 6666|| +ERROR: ccc_lead_info LEAD NOT FOUND - 6666|| + +A SUCCESS response will not show "SUCCESS", but instead will just print the results in the following format: +status|user|vendor_lead_code|source_id|list_id|gmt_offset_now|phone_code|phone_number|title|first_name|middle_initial|last_name|address1|address2|address3|city|state|province|postal_code|country_code|gender|date_of_birth|alt_phone|email|security_phrase|comments|called_count|last_local_call_time|rank|owner +TD|6666|554443||501|-4.00|1|9998887112|Mr|Billy'Oj|U|O'Reillyo|ad1|ad2|ad3|city next|FL|U|33777||U|0000-00-00|bobo'brien|test@test.com||2017-06-01 18:38:41|79|2017-06-09 14:53:27|0|4646 + + + + + -------------------------------------------------------------------------------- update_log_entry - updates the status of a vicidial_log or vicidial_closer_log entry diff --git a/www/vicidial/admin.php b/www/vicidial/admin.php index deb56edb..af60cca2 100644 --- a/www/vicidial/admin.php +++ b/www/vicidial/admin.php @@ -126,7 +126,7 @@ $UGreports = 'ALL REPORTS, NONE, Real-Time Main Report, Real-Time Campaign Summa $Vtables = 'NONE,log_noanswer,did_agent_log,contact_information'; -$APIfunctions = 'ALL_FUNCTIONS add_group_alias add_lead add_list add_phone add_phone_alias add_user agent_ingroup_info agent_stats_export agent_status audio_playback blind_monitor call_agent callid_info change_ingroups check_phone_number did_log_export external_add_lead external_dial external_hangup external_pause external_status in_group_status logout moh_list park_call pause_code preview_dial_action ra_call_control recording recording_lookup send_dtmf server_refresh set_timer_action sounds_list st_get_agent_active_lead st_login_log transfer_conference update_fields update_lead update_list update_log_entry update_phone update_phone_alias update_user user_group_status vm_list webphone_url webserver logged_in_agents update_campaigns lead_field_info phone_number_log switch_lead'; +$APIfunctions = 'ALL_FUNCTIONS add_group_alias add_lead add_list add_phone add_phone_alias add_user agent_ingroup_info agent_stats_export agent_status audio_playback blind_monitor call_agent callid_info change_ingroups check_phone_number did_log_export external_add_lead external_dial external_hangup external_pause external_status in_group_status logout moh_list park_call pause_code preview_dial_action ra_call_control recording recording_lookup send_dtmf server_refresh set_timer_action sounds_list st_get_agent_active_lead st_login_log transfer_conference update_fields update_lead update_list update_log_entry update_phone update_phone_alias update_user user_group_status vm_list webphone_url webserver logged_in_agents update_campaigns lead_field_info phone_number_log switch_lead ccc_lead_info'; ###################################################################################################### ###################################################################################################### @@ -4134,12 +4134,13 @@ else # 170516-0632 - Added Real-Time Monitoring Log Report # 170527-0041 - Added filtering of browser details before logging # 170529-2320 - Added agent events push settings +# 170609-1529 - Added ccc_lead_info API function # # make sure you have added a user to the vicidial_users MySQL table with at least user_level 9 to access this page the first time -$admin_version = '2.14-617a'; -$build = '170529-2320'; +$admin_version = '2.14-618a'; +$build = '170609-1529'; $STARTtime = date("U"); $SQLdate = date("Y-m-d H:i:s"); diff --git a/www/vicidial/help.php b/www/vicidial/help.php index ad1a12c1..aa691118 100644 --- a/www/vicidial/help.php +++ b/www/vicidial/help.php @@ -730,9 +730,9 @@ if ($SSqc_features_active > 0) -
- +
- - + -
diff --git a/www/vicidial/non_agent_api.php b/www/vicidial/non_agent_api.php index a228c6fd..00945ecf 100644 --- a/www/vicidial/non_agent_api.php +++ b/www/vicidial/non_agent_api.php @@ -120,10 +120,11 @@ # 170508-1048 - Added blind_monitor logging # 170527-2254 - Fix for rare inbound logging issue #1017 # 170601-0747 - Added add_to_hopper options to update_lead function +# 170609-1107 - Added ccc_lead_info function # -$version = '2.14-96'; -$build = '170601-0747'; +$version = '2.14-97'; +$build = '170609-1107'; $api_url_log = 0; $startMS = microtime(); @@ -6364,6 +6365,211 @@ if ($function == 'callid_info') +################################################################################ +### ccc_lead_info - outputs lead data for cross-cluster-communication call +################################################################################ +if ($function == 'ccc_lead_info') + { + if(strlen($source)<2) + { + $result = 'ERROR'; + $result_reason = "Invalid Source"; + echo "$result: $result_reason - $source\n"; + api_log($link,$api_logging,$api_script,$user,$agent_user,$function,$value,$result,$result_reason,$source,$data); + echo "ERROR: Invalid Source: |$source|\n"; + exit; + } + else + { + if ( (!preg_match("/ $function /",$api_allowed_functions)) and (!preg_match("/ALL_FUNCTIONS/",$api_allowed_functions)) ) + { + $result = 'ERROR'; + $result_reason = "auth USER DOES NOT HAVE PERMISSION TO USE THIS FUNCTION"; + echo "$result: $result_reason: |$user|$function|\n"; + $data = "$allowed_user"; + api_log($link,$api_logging,$api_script,$user,$agent_user,$function,$value,$result,$result_reason,$source,$data); + exit; + } + $stmt="SELECT count(*) from vicidial_users where user='$user' and vdc_agent_api_access='1' and view_reports='1' and user_level > 6 and active='Y';"; + $rslt=mysql_to_mysqli($stmt, $link); + $row=mysqli_fetch_row($rslt); + $allowed_user=$row[0]; + if ($allowed_user < 1) + { + $result = 'ERROR'; + $result_reason = "ccc_lead_info USER DOES NOT HAVE PERMISSION TO GET LEAD INFO"; + echo "$result: $result_reason: |$user|$allowed_user|\n"; + $data = "$allowed_user"; + api_log($link,$api_logging,$api_script,$user,$agent_user,$function,$value,$result,$result_reason,$source,$data); + exit; + } + else + { + $call_search_SQL=''; + $search_ready=0; + $call_id = preg_replace("/\n|\r|\t| /",'',$call_id); + + if ( (strlen($call_id)>17) and (strlen($call_id)<40) and (preg_match("/^Y|^J|^V|^M|^DC|^S|^LP|^VH|^XL/",$call_id)) ) + { + $tenhoursago = date("Y-m-d H:i:s", mktime(date("H")-10,date("i"),date("s"),date("m"),date("d"),date("Y"))); + $call_search_SQL .= "where caller_code='$call_id' and call_date > \"$tenhoursago\""; + $search_ready++; + } + if ($search_ready < 1) + { + $result = 'ERROR'; + $result_reason = "ccc_lead_info INVALID SEARCH PARAMETERS"; + $data = "$user|$call_id"; + echo "$result: $result_reason: $data\n"; + api_log($link,$api_logging,$api_script,$user,$agent_user,$function,$value,$result,$result_reason,$source,$data); + exit; + } + else + { + $stmt="SELECT admin_viewable_groups,allowed_campaigns from vicidial_user_groups where user_group='$LOGuser_group';"; + if ($DB) {$MAIN.="|$stmt|\n";} + $rslt=mysql_to_mysqli($stmt, $link); + $row=mysqli_fetch_row($rslt); + $LOGadmin_viewable_groups = $row[0]; + $LOGallowed_campaigns = $row[1]; + + $LOGallowed_campaignsSQL=''; + if ( (!preg_match("/ALL-CAMPAIGNS/i",$LOGallowed_campaigns)) ) + { + $LOGallowed_campaignsSQL = preg_replace('/\s-/i','',$LOGallowed_campaigns); + $LOGallowed_campaignsSQL = preg_replace('/\s/i',"','",$LOGallowed_campaignsSQL); + $LOGallowed_campaignsSQL = "and campaign_id IN('$LOGallowed_campaignsSQL')"; + } + + $k=0; + $output=''; + $DLset=0; + if ($stage == 'csv') + {$DL = ','; $DLset++;} + if ($stage == 'tab') + {$DL = "\t"; $DLset++;} + if ($stage == 'newline') + {$DL = "\n"; $DLset++;} + if ($stage == 'pipe') + {$DL = '|'; $DLset++;} + if ($DLset < 1) + {$DL='|'; $stage='pipe';} + if (strlen($time_format) < 1) + {$time_format = 'HF';} + if ($header == 'YES') + { + $output .= 'status' . $DL . 'user' . $DL . 'vendor_lead_code' . $DL . 'source_id' . $DL . 'list_id' . $DL . 'gmt_offset_now' . $DL . 'phone_code' . $DL . 'phone_number' . $DL . 'title' . $DL . 'first_name' . $DL . 'middle_initial' . $DL . 'last_name' . $DL . 'address1' . $DL . 'address2' . $DL . 'address3' . $DL . 'city' . $DL . 'state' . $DL . 'province' . $DL . 'postal_code' . $DL . 'country_code' . $DL . 'gender' . $DL . 'date_of_birth' . $DL . 'alt_phone' . $DL . 'email' . $DL . 'security_phrase' . $DL . 'comments' . $DL . 'called_count' . $DL . 'last_local_call_time' . $DL . 'rank' . $DL . 'owner' . "\n"; + } + + $stmt="SELECT uniqueid,call_date,lead_id from vicidial_log_extended $call_search_SQL;"; + if (preg_match("/^DC/",$call_id)) + {$stmt="SELECT uniqueid,call_date,lead_id from vicidial_dial_log $call_search_SQL;";} + $rslt=mysql_to_mysqli($stmt, $link); + if ($DB) {echo "$stmt\n";} + $vle_to_list = mysqli_num_rows($rslt); + if ($vle_to_list > 0) + { + $row=mysqli_fetch_row($rslt); + $uniqueid = $row[0]; + $call_date = $row[1]; + $lead_id = $row[2]; + + $stmt="SELECT status,user,vendor_lead_code,source_id,list_id,gmt_offset_now,phone_code,phone_number,title,first_name,middle_initial,last_name,address1,address2,address3,city,state,province,postal_code,country_code,gender,date_of_birth,alt_phone,email,security_phrase,comments,called_count,last_local_call_time,rank,owner from vicidial_list where lead_id=$lead_id;"; + $rslt=mysql_to_mysqli($stmt, $link); + if ($DB) {echo "$stmt\n";} + $lead_to_list = mysqli_num_rows($rslt); + if ($lead_to_list > 0) + { + $row=mysqli_fetch_row($rslt); + $LEADstatus = $row[0]; + $LEADuser = $row[1]; + $LEADvendor_lead_code = $row[2]; + $LEADsource_id = $row[3]; + $LEADlist_id = $row[4]; + $LEADgmt_offset_now = $row[5]; + $LEADphone_code = $row[6]; + $LEADphone_number = $row[7]; + $LEADtitle = $row[8]; + $LEADfirst_name = $row[9]; + $LEADmiddle_initial = $row[10]; + $LEADlast_name = $row[11]; + $LEADaddress1 = $row[12]; + $LEADaddress2 = $row[13]; + $LEADaddress3 = $row[14]; + $LEADcity = $row[15]; + $LEADstate = $row[16]; + $LEADprovince = $row[17]; + $LEADpostal_code = $row[18]; + $LEADcountry_code = $row[19]; + $LEADgender = $row[20]; + $LEADdate_of_birth = $row[21]; + $LEADalt_phone = $row[22]; + $LEADemail = $row[23]; + $LEADsecurity_phrase = $row[24]; + $LEADcomments = $row[25]; + $LEADcalled_count = $row[26]; + $LEADlast_local_call_time = $row[27]; + $LEADrank = $row[28]; + $LEADowner = $row[29]; + + if ( (strlen($LOGallowed_campaignsSQL) > 3) and ($api_list_restrict > 0) ) + { + $stmt="SELECT count(*) from vicidial_lists where list_id='$LEADlist_id' $LOGallowed_campaignsSQL;"; + $rslt=mysql_to_mysqli($stmt, $link); + $row=mysqli_fetch_row($rslt); + $allowed_list=$row[0]; + if ($allowed_list < 1) + { + $result = 'ERROR'; + $result_reason = "ccc_lead_info LEAD NOT FOUND"; + echo "$result: $result_reason: |$user|$allowed_user|\n"; + $data = "$allowed_user"; + api_log($link,$api_logging,$api_script,$user,$agent_user,$function,$value,$result,$result_reason,$source,$data); + exit; + } + } + + $output .= "$LEADstatus$DL$LEADuser$DL$LEADvendor_lead_code$DL$LEADsource_id$DL$LEADlist_id$DL$LEADgmt_offset_now$DL$LEADphone_code$DL$LEADphone_number$DL$LEADtitle$DL$LEADfirst_name$DL$LEADmiddle_initial$DL$LEADlast_name$DL$LEADaddress1$DL$LEADaddress2$DL$LEADaddress3$DL$LEADcity$DL$LEADstate$DL$LEADprovince$DL$LEADpostal_code$DL$LEADcountry_code$DL$LEADgender$DL$LEADdate_of_birth$DL$LEADalt_phone$DL$LEADemail$DL$LEADsecurity_phrase$DL$LEADcomments$DL$LEADcalled_count$DL$LEADlast_local_call_time$DL$LEADrank$DL$LEADowner\n"; + + echo "$output"; + + $result = 'SUCCESS'; + $data = "$user|$call_id|$stage"; + $result_reason = "ccc_lead_info $output"; + + api_log($link,$api_logging,$api_script,$user,$agent_user,$function,$value,$result,$result_reason,$source,$data); + } + else + { + $result = 'ERROR'; + $result_reason = "ccc_lead_info LEAD NOT FOUND"; + $data = "$user|$agent_user"; + echo "$result: $result_reason: $data\n"; + api_log($link,$api_logging,$api_script,$user,$agent_user,$function,$value,$result,$result_reason,$source,$data); + exit; + } + } + else + { + $result = 'ERROR'; + $result_reason = "ccc_lead_info CALL NOT FOUND"; + $data = "$user|$agent_user"; + echo "$result: $result_reason: $data\n"; + api_log($link,$api_logging,$api_script,$user,$agent_user,$function,$value,$result,$result_reason,$source,$data); + exit; + } + } + } + } + exit; + } +################################################################################ +### ccc_lead_info - outputs lead data for cross-cluster-communication call +################################################################################ + + + + ################################################################################ ### lead_field_info - pulls the value of one field of a lead ################################################################################