function RenderContent()
    {
        echo '<div class="content">' . "\n";
        if (isset($this->contentString)) {
            echo $this->contentString;
        }
        if (!empty($this->successScript)) {
            ?>
	<script language="JavaScript" type="text/JavaScript">
	<?php 
            echo $this->successScript;
            ?>
	</script>
	<?php 
        }
        if (isset($this->rowString)) {
            while ($row = $this->qryres->fetchRow()) {
                echo str_alparams($this->rowString, $row);
            }
        }
        if (isset($this->afterContentString)) {
            echo $this->afterContentString;
        }
        echo '</div>' . "\n";
    }
Example #2
0
 private function genContentElems(&$outstream, &$resr, array $crd, $nnum = NULL)
 {
     $n = '';
     $line = '';
     if (!empty($nnum)) {
         $n = '_' . $nnum . '_';
     }
     while ($row = $resr->fetchRow()) {
         $line = '<' . $row['name'] . $n . ' ';
         if ($row['options'] & 0x1) {
             $line .= 'ua="rw" ';
         } else {
             $line .= 'ua="na"';
         }
         $line .= '> ';
         $line .= htmlspecialchars(str_alparams($row['valuef'], $crd));
         $line .= '</' . $row['name'] . $n . ">\n";
         fwrite($outstream, $line);
     }
 }
Example #3
0
 public function genContent(&$outstream)
 {
     fwrite($outstream, "; Generated content\n\n");
     while ($crd = $this->itemres->fetchRow()) {
         foreach ($this->grprows as $grp) {
             $line = '';
             $qry = str_dbparams($this->dbhandle, "SELECT * FROM provisions " . "WHERE grp_id = %#1 ORDER BY metric;", array($grp['id']));
             $this->out(LOG_DEBUG, "Query: {$qry}");
             $pres = $this->dbhandle->Execute($qry);
             if (!$pres) {
                 $this->out(LOG_ERR, $this->dbhandle->ErrorMsg());
                 throw new Exception("Cannot locate provision");
             } elseif ($itemres->EOF) {
                 $this->out(LOG_WARNING, 'No rows for cc_card');
                 continue;
             }
             // Write a header like [name] ..
             $line = '[';
             if (!empty($grp['sub_name'])) {
                 $line .= str_alparams($grp['sub_name'], $crd);
             } else {
                 $line .= $grp['name'];
             }
             $line .= "]\n";
             fwrite($outstream, $line);
             while ($row = $pres->fetchRow()) {
                 $line = '';
                 if (!empty($row['sub_name'])) {
                     $line = str_alparams($row['sub_name'], $crd);
                 } else {
                     $line = $row['name'];
                 }
                 $line .= '=';
                 $line .= str_alparams($row['valuef'], $crd);
                 $line .= "\n";
                 fwrite($outstream, $line);
             }
             fwrite($outstream, "\n");
         }
     }
 }
Example #4
0
 } elseif (!$dialstr) {
     $last_prob = 'no-dialstring';
     continue;
 } elseif ($dialstr === true) {
     if (dialSpecial($dialnum, $route, $card, $card_money, $last_prob, $agi, $attempt)) {
         break;
     } else {
         continue;
     }
 }
 if ($special_only) {
     break;
 }
 // Callerid
 if ($route['clidreplace'] !== NULL) {
     $new_clid = str_alparams($route['clidreplace'], array('useralias' => $card['useralias'], 'nplan' => $card['numplan'], 'callernum' => $agi->request['agi_callerid']));
 } else {
     $new_clid = $agi->request['agi_callerid'];
 }
 if ($route['trunkfmt'] == 15) {
     // Auto-answer feature for SIP
     if ($route['providertech'] == 'SIP') {
         $tmp_add_head = getAGIconfig('auto_answer_' . $route['trunkid'], 'Call-Info: answer-after=0');
         //Hack: agi->exec doesn't like spaces, so we include the string into quotes
         if (strpos($tmp_add_head, ' ') !== FALSE) {
             $tmp_add_head = '"' . $tmp_add_head . '"';
         }
         if (!empty($tmp_add_head)) {
             $agi->exec('SIPAddHeader', $tmp_add_head);
         }
     } else {
Example #5
0
function formatDialstring_peer($dialn, &$route, &$card, $do_param = true)
{
    global $a2b;
    global $agi;
    $dbhandle = $a2b->DBHandle();
    if ($route['stripdigits'] > 0) {
        $dialnum = substr($route['dialstring'], $route['stripdigits']);
    } else {
        $dialnum = $route['dialstring'];
    }
    $bind_str = '%dialtech/%dialname';
    switch ($route['trunkfmt']) {
        case 4:
            $qry = str_dbparams($dbhandle, 'SELECT dialtech, dialname FROM cc_dialpeer_local_v ' . 'WHERE useralias = %1', array($dialnum));
            $bind_str = '%dialtech/%dialname';
            if (strlen($route['providertech'])) {
                $qry .= str_dbparams($dbhandle, ' AND dialtech = %1', array($route['providertech']));
            }
            // If the trunk specifies an "ip", aliases among the corresponding numplan will be queried
            // else, the numplan *must* be the same with that of the card.
            // It would be wrong not to specify a numplan, since aliases accross them are not unique!
            if (strlen($route['providerip'])) {
                $qry .= str_dbparams($dbhandle, ' AND numplan_name = %1', array($route['providerip']));
            } else {
                $qry .= str_dbparams($dbhandle, ' AND numplan = %#1', array($card['numplan']));
            }
            break;
        case 6:
            // hardcode search into same numplan!
            $qry = str_dbparams($dbhandle, 'SELECT * FROM cc_dialpeer_remote_v ' . 'WHERE useralias = %1 AND numplan = %#2', array($dialnum, $card['numplan']));
            $bind_str = $route['providertech'] . '/' . $route['providerip'];
            break;
        case 7:
        case 15:
            $dnum = explode('-', $dialnum);
            if ($dnum[0] == 'L') {
                $dnum[0] = $card['numplan'];
            }
            $qry = str_dbparams($dbhandle, 'SELECT dialtech, dialname FROM cc_dialpeer_local_v ' . 'WHERE useralias = %2 AND numplan = %#1 ', $dnum);
            if (strlen($route['providertech'])) {
                $qry .= str_dbparams($dbhandle, ' AND dialtech = %1', array($route['providertech']));
            }
            $bind_str = '%dialtech/%dialname';
            $agi->conlog("Query: {$qry}", 3);
            break;
        case 8:
            $dnum = explode('-', $dialnum);
            if ($dnum[0] == 'L') {
                $dnum[0] = $card['numplan'];
            }
            $qry = str_dbparams($dbhandle, 'SELECT * FROM cc_dialpeer_remote_v ' . 'WHERE useralias = %2 AND numplan = %#1', $dnum);
            $agi->conlog("Query: {$qry}", 3);
            $bind_str = $route['providertech'] . '/' . $route['providerip'];
            break;
    }
    $qry .= ';';
    //$agi->conlog("Find peer from ". $qry,4);
    if (!$bind_str) {
        return false;
    }
    $res = $dbhandle->Execute($qry);
    if (!$res) {
        $agi->verbose('Cannot dial peer: ' . $dbhandle->ErrorMsg());
        if (getAGIconfig('say_errors', true)) {
            $agi->stream_file('allison2', '#');
        }
        return false;
    }
    if ($res->EOF) {
        $agi->verbose("Peer dial: cannot find peer " . $dialnum, 2);
        //$agi-> stream_file("prepaid-dest-unreachable",'#');
        return null;
    }
    // Feature! If more than one registrations exist, call all of them in
    // parallel!
    $peer_rows = array();
    while ($row = $res->fetchRow()) {
        $peer_rows[] = str_alparams($bind_str, $row);
    }
    $str = '';
    if ($do_param) {
        if ($agi->astmajor == "1.6") {
            $str .= getAGIconfig('dialcommand_param', ',60,iL(%timeout)%param');
        } else {
            $str .= getAGIconfig('dialcommand_param', '|60|iL(%timeout)%param');
        }
        $str = str_alparams($str, array('dialnum' => $dialnum, 'dialnumber' => $dialn, 'dialstring' => $route['dialstring'], 'destination' => $route['destination'], 'trunkprefix' => $route['trunkprefix'], 'tech' => $route['providertech'], 'providerip' => $route['providerip'], 'prefix' => $route['prefix'], 'param' => $route['trunkparm'], 'cardnum' => $card['username'], 'stimeout' => $route['tmout'], 'timeout' => 1000 * $route['tmout']));
    }
    return implode('&', $peer_rows) . $str;
}
 protected function performSumQuery(&$summ, &$form, &$dbhandle, &$robj)
 {
     $robj->debug("ncols:" . $this->ncols);
     if ($form->FG_DEBUG > 3) {
         $robj->debug("SumMultiView! Building Sum query..");
     }
     if (empty($summ['fns'])) {
         $robj->debug("No sum functions!");
         return;
     }
     $query_fields = array();
     $query_outerfields = array();
     $query_clauses = array();
     $query_grps = array();
     $query_table = $form->model_table;
     $query_outertable = '';
     $need_raw = $robj->NeedRaw();
     foreach ($form->model as $fld) {
         $fld->buildSumQuery($dbhandle, $summ['fns'], $query_fields, $query_outerfields, $query_table, $query_outertable, $query_clauses, $query_grps, $form);
     }
     if (!strlen($query_table)) {
         $robj->debug("No sum table!");
         return;
     }
     $QUERY = 'SELECT ';
     if (count($query_fields) == 0) {
         $robj->debug("No sum query fields!");
         return;
     }
     if (isset($summ['clauses'])) {
         $query_clauses = array_merge($query_clauses, $summ['clauses']);
     }
     $QUERY .= implode(', ', $query_fields);
     $QUERY .= ' FROM ' . $query_table;
     if (count($query_clauses)) {
         $QUERY .= ' WHERE ' . implode(' AND ', $query_clauses);
     }
     if (!empty($query_grps) && (!isset($summ['group']) || $summ['group'] != false)) {
         $QUERY .= ' GROUP BY ' . implode(', ', $query_grps);
     }
     //Try to see if we can order
     if (!empty($form->order)) {
         if (empty($query_grps) || in_array($form->order, $query_grps)) {
             $ordert = $form->order;
         } else {
             // search again for expressions
             foreach ($form->model as $fld) {
                 if ($fld->fieldname == $form->order) {
                     if (in_array($fld->fieldexpr, $query_grps)) {
                         $ordert = $fld->fieldexpr;
                     }
                     break;
                 }
             }
         }
     } elseif (!empty($summ['order'])) {
         $ordert = $summ['order'];
     } else {
         $ordert = null;
     }
     if (!empty($ordert)) {
         $QUERY .= " ORDER BY {$ordert}";
         if (!empty($form->sens)) {
             if (strtolower($form->sens) == 'desc') {
                 $QUERY .= " DESC";
             }
         } elseif (!empty($summ['sens']) && strtolower($summ['sens']) == 'desc') {
             $QUERY .= " DESC";
         }
     }
     if (!empty($summ['limit'])) {
         $QUERY .= ' LIMIT ' . $summ['limit'];
     }
     $needouter = false;
     if (!empty($query_outertable)) {
         $needouter = true;
     } else {
         foreach ($query_outerfields as $qof) {
             if (!is_string($qof)) {
                 $needouter = true;
                 break;
             }
         }
     }
     if ($needouter) {
         $qf2 = array();
         foreach ($query_outerfields as $qof) {
             if (is_string($qof)) {
                 $qf2[] = $qof;
             } elseif (is_array($qof)) {
                 if ($need_raw) {
                     $qf2[] = $qof[1] . ' AS ' . $qof[1] . '_raw';
                 }
                 $qf2[] = $qof[0] . ' AS ' . $qof[1];
             }
         }
         $QUERY = 'SELECT ' . implode(', ', $qf2) . ' FROM ' . '(' . $QUERY . ') AS innerfoo ' . $query_outertable;
     }
     $QUERY .= ';';
     if ($form->FG_DEBUG > 3) {
         $robj->debug("SUM QUERY: {$QUERY}");
     }
     if (!empty($this->queryreplace)) {
         $rrep = false;
         if (isset($this->queryreplace['query'])) {
             $REPQRY = str_alparams($this->queryreplace['query'], array(clauses => implode(' AND ', $query_clauses), fields => implode(', ', $query_fields), grps => $query_grps, table => $query_table));
             if ($form->FG_DEBUG > 3) {
                 $robj->debug("REP QUERY: {$REPQRY}");
             }
             $resRep = $dbhandle->Execute($REPQRY);
             if (!$resRep) {
                 $robj->debug("RepQuery Failed: " . nl2br(htmlspecialchars($dbhandle->ErrorMsg())));
             } else {
                 $rrep = $resRep->fetchRow();
             }
         }
         if (!$rrep) {
             $rrep = $this->queryreplace['default'];
         }
         $QUERY = str_aldbparams($dbhandle, $QUERY, $rrep);
         if ($form->FG_DEBUG > 3) {
             $robj->debug("SUM QUERY after rep: {$QUERY}");
         }
     }
     // Perform the query
     $res = $dbhandle->Execute($QUERY);
     if (!$res) {
         $robj->debug("Query Failed: " . nl2br(htmlspecialchars($dbhandle->ErrorMsg())));
         return;
     }
     return $res;
 }
Example #7
0
function Send_Mails($dbg = 1, $dry = false)
{
    $dbhandle = A2Billing::DBHandle();
    if ($dbg > 2) {
        echo "Mailer: start\n";
    }
    $sqlTimeFmt = _("YYYY-MM-DD HH24:MI:SS TZ");
    // TODO: not only select, but lock mails in 'sending' state.
    $qry = "SELECT cc_mailings.id AS id, mtype, fromname, fromemail, subject, \n\t\tmessage, defargs, tomail, args, to_char(tstamp,'{$sqlTimeFmt}') AS mdate\n\t\tFROM cc_templatemail, cc_mailings\n\t\tWHERE cc_mailings.tmail_id = cc_templatemail.id\n\t\tAND (state = 1 OR state = 5);";
    $res = $dbhandle->Execute($qry);
    if (!$res) {
        if ($dbg > 0) {
            echo "Query Failed: " . $dbhandle->ErrorMsg() . "\n";
        }
        return false;
    } elseif ($res->EOF) {
        if ($dbg > 2) {
            echo "No mails need to be sent.\n";
        }
        return true;
    }
    try {
        while ($row = $res->fetchRow()) {
            if ($dbg > 2) {
                echo "Sending " . $row['mtype'] . " to " . $row['tomail'] . "\n";
            }
            if (empty($row['tomail'])) {
                if ($dbg > 2) {
                    echo "No recepient specified!\n";
                }
                continue;
            }
            $mai = new Mailer();
            $mai->setTo('', $row['tomail']);
            $mai->setFrom($row['fromname'], $row['fromemail']);
            // Format parameters
            $defargs = array();
            parse_str($row['defargs'], $defargs);
            $defargs['mdate'] = $row['mdate'];
            $toargs = array();
            parse_str($row['args'], $toargs);
            $args = array_merge($defargs, $toargs);
            if ($dbg > 2) {
                echo "Arguments:";
                print_r($args);
                echo "\n";
            }
            $mai->setSubject(str_alparams($row['subject'], $args), "UTF-8");
            $mai->body = new Mailer_TextBody(str_alparams($row['message'], $args));
            if ($dry) {
                $mai->PrintMail();
                continue;
            }
            try {
                if ($dbg > 2) {
                    echo "Sending mail..";
                }
                $mai->SendMail();
                if ($dbg > 2) {
                    echo " done.\n";
                }
                update_mailing($dbhandle, $row['id'], true, $dbg);
            } catch (Exception $ex) {
                if ($dbg > 2) {
                    echo " failed.\n";
                }
                update_mailing($dbhandle, $row['id'], false, $dbg);
                throw $ex;
            }
        }
    } catch (Exception $ex) {
        if ($dbg > 1) {
            echo "Exception: " . $ex->getMessage();
        }
    }
    return true;
}
Example #8
0
 public function DispList(array &$qrow, &$form)
 {
     if (empty($this->href)) {
         return parent::DispList($qrow, $form);
     }
     $msg = '';
     if (!empty($this->message)) {
         $msg = ' title="' . htmlspecialchars($this->message) . '"';
     }
     $href = str_alparams($this->href, $qrow);
     echo '<a href="' . $href . '"' . $msg . '>';
     parent::DispList($qrow, $form);
     echo '</a>';
 }
 public function DispList(array &$qrow, &$form)
 {
     $act = $form->getAction();
     $url = null;
     $url_tooltip = null;
     if ($act == 'list' && $this->list_url) {
         $url = str_alparams($this->list_url, $qrow);
     } elseif ($act == 'details' && $this->detail_url) {
         $url = str_alparams($this->detail_url, $qrow);
     }
     if ($url) {
         echo '<a href="' . $url . '" >';
     }
     echo htmlspecialchars($qrow[$this->fieldname . '_' . $this->refname]);
     if ($this->list_ref && $act == 'list' || $this->detail_ref && $act == 'details') {
         echo " (" . htmlspecialchars($qrow[$this->fieldname]) . ")";
     } else {
         if ($form->FG_DEBUG > 3) {
             echo " (Ref:" . htmlspecialchars($qrow[$this->fieldname]) . ")";
         }
     }
     if ($url) {
         echo '</a>';
     }
     if ($act == 'list' && $this->tooltip_url) {
         $url_tooltip = str_alparams($this->tooltip_url, $qrow);
         echo ' <a href="' . $url_tooltip . '&width=' . $this->width_tooltip . '" ';
         echo ' class="jTip" id="' . $this->fieldname . '_' . $this->tooltip_id++ . '" name="' . $this->caption_tooltip . '"><b>?</b></a>';
     }
 }
Example #10
0
 } elseif (!$dialstr) {
     $last_prob = 'no-dialstring';
     continue;
 } elseif ($dialstr === true) {
     if ($did_clidname != $agi->request['agi_calleridname']) {
         $agi->set_variable('CALLERID(name)', $did_clidname);
     }
     if (dialSpecial($didrow['dialstring'], $route, $card, $card_money, $last_prob, $agi, $attempt)) {
         break;
     } else {
         continue;
     }
 }
 // Callerid
 if ($did_clidreplace !== NULL) {
     $new_clid = str_alparams($did_clidreplace['repl'], array(useralias => $card['useralias'], nplan => $card['numplan'], callernum => $agi->request['agi_callerid'], callern => substr($agi->request['agi_callerid'], $did_clidreplace['find_len'])));
 } else {
     $new_clid = $agi->request['agi_callerid'];
 }
 // we always reset the clid, because the previous rate
 // engine may have changed it.
 $agi->conlog("Setting clid to : \"{$did_clidname}\" <{$new_clid}>", 3);
 if ($did_clidname != $agi->request['agi_calleridname']) {
     $agi->set_variable('CALLERID(name)', $did_clidname);
 }
 $agi->set_variable('CALLERID(num)', $new_clid);
 $res = $a2b->DBHandle()->Execute('INSERT INTO cc_call (cardid, attempt, cmode, ' . 'sessionid, uniqueid, nasipaddress, src, ' . 'calledstation, destination, ' . 'srid, brid, tgid, trunk) ' . 'VALUES( ?,?,?,?,?,?,?,?,?,?,?,?,?) RETURNING id;', array($card['id'], $attempt, 'did', $agi->request['agi_channel'], $uniqueid, NULL, $agi->request['agi_callerid'], $did_extension, $route['destination'], $route['srid'], $route['brid'], $didrow['tgid'], $route['trunkid']));
 if ($notice = $a2b->DBHandle()->NoticeMsg()) {
     $agi->verbose('DB:' . $notice, 2);
 }
 if (!$res) {
Example #11
0
function groupDial($dialnum, $route, $card, $card_money, &$last_prob, $agi, $attempt)
{
    global $a2b, $mode;
    // First, parse *our* string, so that we can form the
    // destinations.
    $gstr = $route['providerip'];
    //TODO: need to combine providerIP & dialstring?
    if (empty($gstr)) {
        $gstr = $dialnum;
    }
    $agi->conlog("Group dialnum: \"{$gstr}\"", 5);
    $gdests = groupstr_analyze($gstr);
    // Then, find all rateengine results for each destination
    $QRY = str_dbparams($a2b->DBHandle(), 'SELECT * FROM RateEngine2(%#1, ?, %#2, now(), %3);', array($card['tgid'], $card['numplan'], $card_money['base']));
    $all_routes = array();
    foreach ($gdests as $gdest) {
        $agi->conlog($QRY . " [?= {$gdest}]", 4);
        $res = $a2b->DBHandle()->Execute($QRY, array($gdest));
        // If the rate engine has anything to Notice/Warn, display that..
        if ($notice = $a2b->DBHandle()->NoticeMsg()) {
            $agi->verbose('DB:' . $notice, 2);
        }
        if (!$res) {
            $agi->verbose('Rate engine: query error!', 2);
            $agi->conlog($a2b->DBHandle()->ErrorMsg(), 3);
            break;
        } elseif ($res->EOF) {
            $agi->verbose('Rate engine: no result.', 3);
            continue;
        }
        $routes = $res->GetArray();
        // now, find the first route that might work
        foreach ($routes as $aroute) {
            if ($aroute['tmout'] < getAGIconfig('min_duration_2call', 30)) {
                $agi->conlog('Call will be too short: ', $aroute['tmout'], 4);
                $last_prob = 'min-length';
                continue;
            }
            if ($aroute['tmout'] > getAGIconfig('max_call_duration', 604800)) {
                $aroute['tmout'] = getAGIconfig('max_call_duration', 604800);
                $agi->conlog('Call truncated to: ', $aroute['tmout'], 4);
            }
            // Check if trunk needs a feature subscription
            if (!empty($aroute['trunkfeat'])) {
                // This field comes as a string, convert to array..
                if (!empty($card['features']) && !is_array($card['features'])) {
                    $card['features'] = sql_decodeArray($card['features']);
                }
                if (empty($card['features']) || !in_array($aroute['trunkfeat'], $card['features'])) {
                    if (empty($last_prob)) {
                        $last_prob = 'no-feature';
                    }
                    $agi->conlog("Call is missing feature \"" . $aroute['trunkfeat'] . "\", skipping route.", 3);
                    $agi->conlog("Features: " . print_r($card['features'], true), 4);
                    continue;
                }
                // feature found!
                $agi->conlog('Call using feature: ' . $aroute['trunkfeat'], 5);
            }
            $dialstr = formatDialstring($dialnum, $aroute, $card, false);
            if ($dialstr === null) {
                $last_prob = 'unreachable';
                continue;
            } elseif (!$dialstr) {
                $last_prob = 'no-dialstring';
                continue;
            } elseif ($dialstr === true) {
                // We cannot use other special trunks in group.
                continue;
            }
            if ($aroute['clidreplace'] !== NULL && $mode != 'did') {
                $new_clid = str_alparams($aroute['clidreplace'], array('useralias' => $card['useralias'], 'nplan' => $card['numplan'], 'callernum' => $agi->request['agi_callerid']));
            } else {
                $new_clid = $agi->request['agi_callerid'];
            }
            // add this route to the available ones
            $all_routes[] = array('r' => $aroute, 'str' => $dialstr, 'clid' => $new_clid);
            //but then, discard all other possibilities for this destination.
            break;
        }
    }
    //$agi->conlog("Group dialing routes: ".print_r($all_routes,true),4);
    if (empty($all_routes)) {
        $last_prob = 'call-fail';
        return false;
    }
    // Now, iterate over all the routes to find some useful stuff
    $agg_route = array();
    $agg_strs = array();
    foreach ($all_routes as $aroute) {
        // Try to have a common CLID.
        if (!isset($agg_route['clid'])) {
            $agg_route['clid'] = $aroute['clid'];
        } elseif ($agg_route['clid'] != $aroute['clid']) {
            $agg_route['clid'] = '';
        }
        if (!isset($agg_route['tmout'])) {
            $agg_route['tmout'] = $aroute['r']['tmout'];
        } elseif ($agg_route['tmout'] > $aroute['r']['tmout']) {
            $agg_route['tmout'] = $aroute['r']['tmout'];
        }
        $agg_strs[] = $aroute['str'];
    }
    $agg_route['str'] = implode('&', $agg_strs);
    //$agi->conlog("Group dialing routes: ".print_r($agg_route,true),4);
    $dialstr = $agg_route['str'] . str_alparams(getAGIconfig('dialcommand_group_param', '|60|iL(%timeout)%param'), array('dialstring' => $agg_route['str'], 'trunkprefix' => $route['trunkprefix'], 'tech' => $route['providertech'], 'providerip' => $route['providerip'], 'prefix' => $route['prefix'], 'param' => $route['trunkparm'], 'cardnum' => $card['username'], 'stimeout' => $route['tmout'], 'timeout' => 1000 * $route['tmout']));
    // Place the call!
    $agi->conlog("Setting clid to : " . $agg_route['clid'], 3);
    $agi->set_variable('CALLERID(num)', $agg_route['clid']);
    if (!empty($route['call_uniqueid'])) {
        $uniqueid = $route['call_uniqueid'];
    } else {
        // Construct a unique id with .. + trunkid.
        $uniqueid = $agi->request['agi_uniqueid'] . '-' . $route['trunkid'];
    }
    $res = $a2b->DBHandle()->Execute('INSERT INTO cc_call (cardid, attempt, cmode, ' . 'sessionid, uniqueid, nasipaddress, src, ' . 'calledstation, destination, ' . 'srid, brid, tgid, trunk) ' . 'VALUES( ?,?,?,?,?,?,?,?,?,?,?,?,?) RETURNING id;', array($card['id'], $attempt, $mode, $agi->request['agi_channel'], $uniqueid, NULL, $card['username'], $dialnum, $route['destination'], $route['srid'], $route['brid'], $route['tgid'], $route['trunkid']));
    if ($notice = $a2b->DBHandle()->NoticeMsg()) {
        $agi->verbose('DB:' . $notice, 2);
    }
    if (!$res) {
        $agi->verbose('Cannot mark call start in db!');
        $agi->conlog($a2b->DBHandle()->ErrorMsg(), 2);
        // This error may mean that trunk is in use etc.
        // If call cannot be billed, we'd better abort it.
        $last_prob = 'call-insert';
        return false;
    } elseif ($res->EOF) {
        $agi->verbose('Cannot mark call start in db: EOF!');
        $last_prob = 'call-insert';
        return null;
    }
    $call_id = $res->fetchRow();
    $agi->conlog('Start call ' . $call_id['id'], 4);
    $agi->conlog("Dial group@" . $route['trunkcode'] . " : {$dialstr}", 3);
    $attempt++;
    $call_res = $agi->exec('Dial', $dialstr);
    //TODO: if record, stop
    $hangupcause = $agi->get_variable('HANGUPCAUSE');
    $answeredtime = $agi->get_variable("ANSWEREDTIME");
    if (empty($answeredtime['data']) || $answeredtime['result'] == 0) {
        $answeredtime['data'] = 0;
    }
    $dialstatus = $agi->get_variable("DIALSTATUS");
    $dialedtime = $agi->get_variable("DIALEDTIME");
    if ($dialedtime['result'] == 0) {
        $dialedtime['data'] = 0;
    }
    // We are special, we need to learn who answered here!
    $dialedpeer = $agi->get_variable("DIALEDPEERNUMBER");
    $agi->conlog("Group result: " . $dialstatus['data'] . '@' . $dialedpeer['data'] . '(' . $hangupcause['data'] . ') after ' . $answeredtime['data'] . 'sec.', 2);
    //$agi->conlog("After dial, answertime: ".print_r($answeredtime,true));
    //TODO: SIP, ISDN extended status
    $can_continue = false;
    $cause_ext = '';
    switch ($dialstatus['data']) {
        case 'BUSY':
            $last_prob = 'busy';
            break;
        case 'ANSWERED':
        case 'ANSWER':
        case 'CANCEL':
            // Now, try to see who answered
            if (!empty($dialedpeer['data'])) {
                $agi->conlog("Searching who answered..", 4);
                foreach ($all_routes as $aroute) {
                    $pos = strpos($aroute['str'], '/');
                    if ($pos === false) {
                        $str2 = $aroute['str'];
                    } else {
                        $str2 = substr($aroute['str'], $pos + 1);
                    }
                    if ($dialedpeer['data'] == $str2) {
                        $agi->conlog("Found: " . $aroute['str'], 4);
                        $route = $aroute['r'];
                        break;
                    }
                }
            }
            $last_prob = '';
            break;
        case 'CONGESTION':
        case 'CHANUNAVAIL':
            $last_prob = 'call-fail';
            $can_continue = true;
            break;
        case 'NOANSWER':
            $last_prob = 'no-answer';
            $can_continue = true;
            break;
        default:
            $agi->verbose("Unknown status: " . $dialstatus['data'], 2);
    }
    $res = $a2b->DBHandle()->Execute('UPDATE cc_call SET ' . 'stoptime = now(), sessiontime = ?, tcause = ?, hupcause = ?, ' . 'cause_ext =?, startdelay =?, ' . 'destination =?, srid =?, brid = ?, trunk =? ' . 'WHERE id = ? ;', array($answeredtime['data'], $dialstatus['data'], $hangupcause['data'], $cause_ext, $dialedtime['data'] - $answeredtime['data'], $route['destination'], $route['srid'], $route['brid'], $route['trunkid'], $call_id['id']));
    if ($notice = $a2b->DBHandle()->NoticeMsg()) {
        $agi->verbose('DB:' . $notice, 2);
    }
    if (!$res) {
        $agi->verbose('Cannot mark call end in db! (will NOT bill)', 0);
        $agi->conlog($a2b->DBHandle()->ErrorMsg(), 2);
    }
    return !$can_continue;
}