Integrazione Asterisk & Google Contacts - Seconda parte | Ing. Eugenio Bonifacio
Tags: applicazioni sms, applicazioni web, cataloghi elettronici, commercio elettronico, consulenza agenzie web, consulenza opensource, consulenza oscommerce, consulenza Drupal, consulenza Wordpress, consulenza Zend Framework, e-commerce, portali web, sistemi di prenotazione, sistemi informativi, siti web comiso, siti web ragusa, siti web sicilia, software personalizzati, sviluppo firmware, programmatore php freelance, sviluppatore zend framework, sviluppatore doctrine, programmatore zend framework, programmatore doctrine, sviluppatore cakephp
30
Dic 10

Integrazione Asterisk & Google Contacts - Seconda parte

 

 Riprendo l'articolo pubblicato quando ancora ero preso dall'entusiasmo di aver fatto funzionare l'accoppiata Asterisk-Google Contacts. Non nascondo che vorrei anche implementare un bridge Google Contacts - LDAP per poter visualizzare la rubrica nei telefoni VOIP, tipo gli SNOM 300, che la supportano.

Colgo l'occasione di rispondere a diverse richieste pervenutemi per completare l'articolo con dei dettagli tecnici e dei sorgenti da poter impiegare come esempio.

Per prima cosa affrontiamo il modo in cui il tutto funziona.

  1. Uno script PHP (google_contacts.php), eseguito come cron job, si occupa di accedere all'account di Google, leggere i dati dei contatti e creare un DB di facile accesso. Per semplicità mi sono creato un indice con un array, che serializzato viene salvato nel file contacts.db. Ovviamente essendo un test mi va più che bene, magari si potrebbe sostituire con un DB SQLite.
  2. Un altro script PHP (cli.php), richiamato dall'estensione Asterisk che gestisce le chiamate entranti, dialoga tramite AGI con Asterisk e si occupa di recuperare il caller ID a partire dal numero di telefono dal DB ed impostarlo in una variabile Asterisk.
  3. L'estensione per le chiamate in ingresso di Asterisk, richiama lo script cli.php e imposta il caller ID sulla variabile in uscita dallo script.

Il file google_contacts.php

 Premetto che utilizzo le librerie Zend_GData per l'accesso all'account di Google e che alcuni pezzi di codice sono presi da esempi sparsi nelle varie documentazioni.

<?php
// caricamento delle librerie Zend necessarie
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Http_Client');
Zend_Loader::loadClass('Zend_Gdata_Query');
Zend_Loader::loadClass('Zend_Gdata_Feed');
 
// impostazione delle credenziali di accesso a GMail
$user = "utente [at] gmail [dot] com";
$pass = "password";
 
try {
  // login all'account
  $client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, 'cp');
 
  $gdata = new Zend_Gdata($client);
  $gdata->setMajorProtocolVersion(3);
 
  // query dei dati, da notare il max-results, altrimenti pagina i dati
  $query = new Zend_Gdata_Query('http://www.google.com/m8/feeds/contacts/default/full?max-results=10000');
  $feed = $gdata->getFeed($query);
 
  // per motivi di debug salvo l'XML
  file_put_contents('dump.txt', $feed->getXML());
 
  $n = 0;
  $names = array();
  $phones = array();
  foreach($feed as $entry){
    // creazione dell'oggetto SimpleXML
    $xml = simplexml_load_string($entry->getXML());
 
    $title = array();
    $org = (string)$xml->organization->orgName;
    if(!empty($org)) {
      $title[] = $org;
    }
 
    $name = (string)$entry->title;
    if(!empty($name)) {
      $title[] = $name;
    }
 
    if(count($title) > 0 && count($xml->phoneNumber)) {	
      foreach ($xml->phoneNumber as $p) {
	// normalizzo il numero togliendo il prefisso internazionale, dove esiste
        $tel = preg_replace('/^\+39/','',(string)$p);
 
	// prendo l'etichetta del numero, se personalizzata es. "Ufficio", "Casa", ecc... Altrimenti prendo quella di sistema
	$key = isset($p['label']) ? $p['label'] : preg_replace('/^((?:.*)#)/', '', $p['rel']);
 
	// creazione dell'indice sulla base del numero
	$phones[$tel] = array('key' => (string)$key, 'value' => (string) $p, 'contact' => $n);
      }
 
      // creazione dell'indice dei nomi, sarebbe una specie di relazione di tabella, così da recuperare velocemente il nome del chiamante
      $names[$n] = implode(' - ', $title);
 
      $n++;
    }
  }
 
  // serializzo l'array e lo scrivo su file
  file_put_contents('contacts.db', serialize(array('contacts' => $names, 'index' => $phones)));
 
  // essendo eseguito all'interno di un cron job tutto l'output mi verrà inviato nella mail
  echo 'Completato';
 
} catch (Exception $e) {
  die('ERROR:' . $e->getMessage());  
}

 

Il file cli.php

Il file deve iniziare con questa dicitura perchè così vuole Asterisk, per trovare l'interprete PHP.

#!/usr/bin/php -q
<?php
  // impostazioni PHP
  set_time_limit(60);
  ob_implicit_flush(false);
  error_reporting(0);
 
  if (!defined('STDIN')) {
    define('STDIN', fopen('php://stdin', 'r'));
  }
 
  if (!defined('STDOUT')) {
    define('STDOUT', fopen('php://stdout', 'w'));
  }
 
  if (!defined('STDERR')) {
    define('STDERR', fopen('php://stderr', 'w'));
  }
 
  function checkresult($res)
  {
    trim($res);
    if (preg_match('/^200/',$res))
    {
      if (! preg_match('/result=(-?\d+)/',$res,$matches))
      {
        fwrite(STDERR,"FAIL ($res)\n");
	fflush(STDERR);
	return 0;
      }
      else {
	fwrite(STDERR,"PASS (".$matches[1].")\n");
	fflush(STDERR);
	return $matches[1];
      }
    }
    else {
      fwrite(STDERR,"FAIL (unexpected result '$res')\n");
      fflush(STDERR);
      return -1;
    }
  }
 
  # recupero delle variabili AGI da Asterisk
  while (!feof(STDIN)) {
    $temp = trim(fgets(STDIN,4096));
    if (($temp == "") || ($temp == "\n")) {
      break;
    }
 
    $s = split(":",$temp);
    $name = str_replace("agi_", "", $s[0]);
    $agi[$name] = trim($s[1]);
  }
 
  # stampa delle variabili AGI per debug, dalla console Asterisk è possibile visualizzare questi dati
  foreach($agi as $key => $value) {
    fwrite(STDERR,"-- $key = $value\n");
    fflush(STDERR);
  }
 
  // numero chiamante
  $number = $argv[1];
 
  // normalizzazione del numero
  $number = $tel = preg_replace('/^\+39/','',(string)$number);
 
  $caller = $number;
 
  // lettura del DB
  $data = unserialize(file_get_contents('contacts.db'));
 
  // vedo se il numero è nel DB
  if(isset($data['index'][$number])) {
    // imposto il caller come NOME (ETICHETTA DEL NUMERO), es. "Pinco Pallino (Cellulare)"
    $caller = $data['contacts'][$data['index'][$number]['contact']] . ' (' . $data['index'][$number]['key'] . ')';
  }
 
  $callerid = $caller . '<' . $number . '>';
 
  // chiamo il comando AGI "SET VARIABLE" per impostare una variabile AGI
  fwrite($STDOUT,"SET VARIABLE google_cid $callerid\n");
  fflush(STDOUT);
  $result = trim(fgets(STDIN,4096));
  checkresult($result);

 

L'estensione Asterisk in extensions.conf

[ufficio-in]
; chiamo lo script cli.php che imposta la variabile google_cid
exten => _X.,1,AGI(/var/asterisk/cli.php)
 
; uso la variabile per impostare il caller ID
exten => _X.,n,Set(CALLERID(name)=${google_cid})
 
; proseguo secondo lo schema desiderato
exten => _X.,n,Dial(SIP/53&SIP/52)
exten => _X.,n,Dial(SIP/51)
exten => _X.,n,Hangup

Ovviamente questa è un'implementazione sperimentale, tutto dovrà essere ottimizzato e implementato a regola d'arte. Per chi vuole iniziare è comunque una buona base.