Personalizando el dialplan en Elastix: ext-queues


publicado por Víctor Villarreal en

1 comentario

Introduccion

Los usuarios de Elastix saben (o al menos, deberian saber) que existen formas de personalizar el dialplan en esta plataforma. Ya que gran parte del dialplan se genera de forma dinamica, es necesario atenerse a ciertas reglas establecidas, para evitar que nuestras modificaciones se pierdan o sean sobre-escritas por la interfaz web de Elastix.

La primera es utilizando el fichero extensions_custom.conf. Este archivo no se actualiza bajo ninguna circunstancia desde Elastix y en él podemos guardar toda la configuracion de forma segura, sin que sea sobre-escrita por algun script. Es el lugar ideal donde podemos escribir nuestros propios contextos y aplicaciones, que luego se utilizaran en la PBX. No solo puede contener contextos, si no tambien declaraciones de variables globales, macros, etc.

La segunda es utilizando el fichero extensions_override_freepbx.conf. Este fichero es para que el usuario pueda 'sobre-escribir' contextos o macros previamente declarados por Elastix, y poner en su lugar su propio codigo. Por ejemplo: Si el contexto [from-pstn] no cumple nuestras expectativas, lo unico que debemos hacer es crear en este archivo un contexto con el mismo nombre, que contenga todas las acciones que necesitemos. Asterisk usara nuestro contexto, en vez del de Elastix.

Pero ninguna de estas opciones nos permiten modificar dialplan generado dinamicamente por Elastix, como por ejemplo, el contexto [ext-queues] que es donde se declaran las colas y su logica. Aqui es donde propongo una tercera forma de modificar este tipo de contextos: Modificando directamente el codigo PHP que genera dicho dialplan.

Materiales

Para nuestro ejemplo, utilizaremos Elastix 1.6 aunque es aplicacble a otras versiones mas recientes, con algunos variaciones. Ademas se recomienda haber leido previamente nuestra anterior entrega sobre el dialplan de Elastix.

Procedimiento

Las extensiones y prioridades que componen el contexto [ext-queues] se generan por medio de una funcion PHP llamada queues_get_config() en el archivo /var/www/html/admin/modules/queues/functions.inc.php. Hechemos un vistazo:

/*  Generates dialplan for "queues" components (extensions & inbound routing)
 We call this with retrieve_conf
*/
function queues_get_config($engine) {
 global $ext;  // is this the best way to pass this?
 global $queues_conf;

 switch($engine) {
  case "asterisk":

   if (isset($queues_conf) && is_a($queues_conf, "queues_conf")) {
    $queues_conf->addQueuesGeneral('persistentmembers','yes');
   }

   /* queue extensions */
   $ext->addInclude('from-internal-additional','ext-queues');
   $qlist = queues_list(true);
   if (is_array($qlist)) {
    foreach($qlist as $item) {
     
     $exten = $item[0];
     $q = queues_get($exten);

     $grppre = (isset($q['prefix'])?$q['prefix']:'');
     $alertinfo = (isset($q['alertinfo'])?$q['alertinfo']:'');

     // Not sure why someone would ever have a ; in the regex, but since Asterisk has problems with them
     // it would need to be escaped
     //
     $qregex = (isset($q['qregex'])?$q['qregex']:'');
     str_replace(';','\;',$qregex);
     
     $ext->add('ext-queues', $exten, '', new ext_macro('user-callerid'));
     $ext->add('ext-queues', $exten, '', new ext_answer(''));

     // block voicemail until phone is answered at which point a macro should be called on the answering
     // line to clear this flag so that subsequent transfers can occur.
     //
     if ($q['queuewait']) {
      $ext->add('ext-queues', $exten, '', new ext_execif('$["${QUEUEWAIT}" = ""]', 'Set', '__QUEUEWAIT=${EPOCH}'));
     }
     $ext->add('ext-queues', $exten, '', new ext_setvar('__BLKVM_OVERRIDE', 'BLKVM/${EXTEN}/${CHANNEL}'));
     $ext->add('ext-queues', $exten, '', new ext_setvar('__BLKVM_BASE', '${EXTEN}'));
     $ext->add('ext-queues', $exten, '', new ext_setvar('DB(${BLKVM_OVERRIDE})', 'TRUE'));
     $ext->add('ext-queues', $exten, '', new ext_execif('$["${REGEX("(M[(]auto-blkvm[)])" ${DIAL_OPTIONS})}" != "1"]', 'Set', '_DIAL_OPTIONS=${DIAL_OPTIONS}M(auto-blkvm)'));

     // Inform all the children NOT to send calls to destinations or voicemail
     //
     $ext->add('ext-queues', $exten, '', new ext_setvar('__NODEST', '${EXTEN}'));

     // deal with group CID prefix
     // Use the same variable as ringgroups/followme so that we can manage chaines of calls
     // but strip only if you plan on setting a new one
     //
     if ($grppre != '') {
      $ext->add('ext-queues', $exten, '', new ext_gotoif('$["foo${RGPREFIX}" = "foo"]', 'REPCID'));
      $ext->add('ext-queues', $exten, '', new ext_gotoif('$["${RGPREFIX}" != "${CALLERID(name):0:${LEN(${RGPREFIX})}}"]', 'REPCID'));
      $ext->add('ext-queues', $exten, '', new ext_noop('Current RGPREFIX is ${RGPREFIX}....stripping from Caller ID'));
      $ext->add('ext-queues', $exten, '', new ext_setvar('CALLERID(name)', '${CALLERID(name):${LEN(${RGPREFIX})}}'));
      $ext->add('ext-queues', $exten, '', new ext_setvar('_RGPREFIX', ''));
      $ext->add('ext-queues', $exten, 'REPCID', new ext_noop('CALLERID(name) is ${CALLERID(name)}'));
      $ext->add('ext-queues', $exten, '', new ext_setvar('_RGPREFIX', $grppre));
      $ext->add('ext-queues', $exten, '', new ext_setvar('CALLERID(name)','${RGPREFIX}${CALLERID(name)}'));
     }

     // Set Alert_Info
     if ($alertinfo != '') {
      $ext->add('ext-queues', $exten, '', new ext_setvar('__ALERT_INFO', str_replace(';', '\;', $alertinfo)));
     }

     $ext->add('ext-queues', $exten, '', new ext_setvar('MONITOR_FILENAME','/var/spool/asterisk/monitor/q${EXTEN}-${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}-${UNIQUEID}'));
     $joinannounce_id = (isset($q['joinannounce_id'])?$q['joinannounce_id']:'');
     if($joinannounce_id) {
      $joinannounce = recordings_get_file($joinannounce_id);
      $ext->add('ext-queues', $exten, '', new ext_playback($joinannounce));
     }
     $options = 't';
     if ($q['rtone'] == 1) {
      $options .= 'r';
     }
     if ($q['retry'] == 'none'){
      $options .= 'n';
     }
     if (isset($q['music'])) {
       $ext->add('ext-queues', $exten, '', new ext_setvar('__MOHCLASS', $q['music']));
     }
     // Set CWIGNORE  if enabled so that busy agents don't have another line key ringing and
     // stalling the ACD.
     if ($q['cwignore']) {
       $ext->add('ext-queues', $exten, '', new ext_setvar('__CWIGNORE', 'TRUE'));
     }
     $agentannounce_id = (isset($q['agentannounce_id'])?$q['agentannounce_id']:'');
     if ($agentannounce_id) {
      $agentannounce = recordings_get_file($agentannounce_id);
     } else {
      $agentannounce = '';
     }
     $ext->add('ext-queues', $exten, '', new ext_queue($exten,$options,'',$agentannounce,$q['maxwait']));
 
     $ext->add('ext-queues', $exten, '', new ext_dbdel('${BLKVM_OVERRIDE}'));
      // If we are here, disable the NODEST as we want things to resume as normal
      //
      $ext->add('ext-queues', $exten, '', new ext_setvar('__NODEST', ''));
     if ($q['cwignore']) {
      $ext->add('ext-queues', $exten, '', new ext_setvar('__CWIGNORE', '')); 
     }
 
     // destination field in 'incoming' database is backwards from what ext_goto expects
     $goto_context = strtok($q['goto'],',');
     $goto_exten = strtok(',');
     $goto_pri = strtok(',');
     
     $ext->add('ext-queues', $exten, '', new ext_goto($goto_pri,$goto_exten,$goto_context));
     
     //dynamic agent login/logout
     if (trim($qregex) != '') {
       $ext->add('ext-queues', $exten."*", '', new ext_setvar('QREGEX', $qregex));
     }
     $ext->add('ext-queues', $exten."*", '', new ext_macro('agent-add',$exten.",".$q['password']));
     $ext->add('ext-queues', $exten."**", '', new ext_macro('agent-del',$exten.",".$exten));
    }
   }
  break;
 }
}

Lo primero que se hace en esta funcion es incluir una variable global llamada $ext, que en realidad es un objeto. Este objeto contiene todos los metodos y propiedades necesarias para generar dialplan en Elastix.

Esta rutina itera por cada una de las colas que tengamos configuradas en nuestra PBX. Como ejercicio, se propone al lector coparar el dialplan del contexto [ext-queues] con el codigo de esta funcion PHP para corroborar la correspondencia de lo que se genera dinamicamente.

Para modificar el comportamiento de las colas, solo debemos modificar el codigo de esta funcion, comentando algo que no deseamos que se genere, o agregar alguna prioridad a las extensiones de este contexto, invocando los metodos provistos por el objeto $ext. Por ejemplo, si configuramos una cola con extension '100' en nuestra instalacion Elastix, vemos que el contexto [ext-queues] correspondiente al fichero /etc/asterisk/extensions_additional.conf es como sigue:

[ext-queues]
include => ext-queues-custom
exten => 100,1,Macro(user-callerid,)
exten => 100,n,Answer
exten => 100,n,Set(__BLKVM_OVERRIDE=BLKVM/${EXTEN}/${CHANNEL})
exten => 100,n,Set(__BLKVM_BASE=${EXTEN})
exten => 100,n,Set(DB(${BLKVM_OVERRIDE})=TRUE)
exten => 100,n,ExecIf($["${REGEX("(M[(]auto-blkvm[)])" ${DIAL_OPTIONS})}" != "1"],Set,_DIAL_OPTIONS=${DIAL_OPTIONS}M(auto-blkvm))
exten => 100,n,Set(__NODEST=${EXTEN})
exten => 100,n,Set(MONITOR_FILENAME=/var/spool/asterisk/monitor/q${EXTEN}-${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}-${UNIQUEID})
exten => 100,n,Queue(100,t,,)
exten => 100,n,dbDel(${BLKVM_OVERRIDE})
exten => 100,n,Set(__NODEST=)
exten => 100,n,Goto(app-blackhole,hangup,1)
exten => 100*,1,Macro(agent-add,100,)
exten => 100**,1,Macro(agent-del,100,100)

; end of [ext-queues]

Si ahora deseamos, por ejemplo, agregar una instruccion Noop() a este contexto, solo debemos agregar la siguiente linea en la parte de la funcion anterior que necesitemos:

$ext->add('ext-queues', $exten, '' , new ext_noop('Este es un Noop agregado manualmente!'));

Luego guardamos los cambios en el archivo, vamos a la interfaz web de Elastix, guardamos cambios y relodeamos la configuracion. Ahora nuestro contexto [ext-queues] queda asi:

[ext-queues]
include => ext-queues-custom
exten => 100,1,Macro(user-callerid,)
exten => 100,n,Answer
exten => 100,n,Set(__BLKVM_OVERRIDE=BLKVM/${EXTEN}/${CHANNEL})
exten => 100,n,Set(__BLKVM_BASE=${EXTEN})
exten => 100,n,Set(DB(${BLKVM_OVERRIDE})=TRUE)
exten => 100,n,ExecIf($["${REGEX("(M[(]auto-blkvm[)])" ${DIAL_OPTIONS})}" != "1"],Set,_DIAL_OPTIONS=${DIAL_OPTIONS}M(auto-blkvm))
exten => 100,n,Set(__NODEST=${EXTEN})
exten => 100,n,Set(MONITOR_FILENAME=/var/spool/asterisk/monitor/q${EXTEN}-${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}-${UNIQUEID})
exten => 100,n,Noop(Este es un Noop agregado manualmente!)
exten => 100,n,Queue(100,t,,)
exten => 100,n,dbDel(${BLKVM_OVERRIDE})
exten => 100,n,Set(__NODEST=)
exten => 100,n,Goto(app-blackhole,hangup,1)
exten => 100*,1,Macro(agent-add,100,)
exten => 100**,1,Macro(agent-del,100,100)

; end of [ext-queues]

1 comentario

Deja un comentario