Ticket #3042: callme.patch

File callme.patch, 24.0 kB (added by sasargen, 4 years ago)

Patch to add Callme Feature to FreePBX ARI Framework 2.5.1.1

  • includes/callme.php

    old new  
     1<?php 
     2 
     3/*  
     4 * Call Me constants 
     5 */ 
     6define("CALLME_SUCCESS", "The call has been answered."); 
     7define("CALLME_FAILURE", "The call failed.  Perhaps the line was busy."); 
     8define("CALLME_ERROR", "System error."); 
     9 
     10/* 
     11 * 
     12 * Include admin/functions.inc.php for our call to parse_amportal_conf() 
     13 * Include admin/common/php-asmanager.php to use the AGI_AsteriskManager class for accessing the AMI 
     14 * 
     15 */ 
     16require_once('../admin/functions.inc.php'); 
     17require_once('../admin/common/php-asmanager.php'); 
     18 
     19$amp_conf   = parse_amportal_conf("/etc/amportal.conf"); 
     20$asm    = new AGI_AsteriskManager(); 
     21// attempt to connect to asterisk manager proxy 
     22if (!isset($amp_conf["ASTMANAGERPROXYPORT"]) || !$res = $asm->connect("127.0.0.1:".$amp_conf["ASTMANAGERPROXYPORT"], $amp_conf["AMPMGRUSER"] , $amp_conf["AMPMGRPASS"], 'off')) 
     23{ 
     24  // attempt to connect directly to asterisk, if no proxy or if proxy failed 
     25  if (!$res = $asm->connect("127.0.0.1:".$amp_conf["ASTMANAGERPORT"], $amp_conf["AMPMGRUSER"] , $amp_conf["AMPMGRPASS"], 'off')) 
     26  { 
     27    // couldn't connect at all 
     28    unset( $asm ); 
     29    $_SESSION['ari_error'] = 
     30    _("ARI does not appear to have access to the Asterisk Manager.") . " ($errno)<br>" . 
     31    _("Check the ARI 'main.conf.php' configuration file to set the Asterisk Manager Account.") . "<br>" . 
     32    _("Check /etc/asterisk/manager.conf for a proper Asterisk Manager Account") . "<br>" . 
     33    _("make sure [general] enabled = yes and a 'permit=' line for localhost or the webserver."); 
     34  } 
     35} 
     36 
     37function callme_close() 
     38{ 
     39  global $asm; 
     40  if (is_object($asm)) 
     41  { 
     42    $asm->logoff(); 
     43    $asm->disconnect(); 
     44  } 
     45  unset($asm); 
     46} 
     47/* 
     48 * Call Me functions 
     49 */ 
     50 /* Return the call me number stored in the database. */ 
     51function callme_getnum($exten) 
     52{ 
     53        global $asm; 
     54        $cmd    = "database get AMPUSER $exten/callmenum"; 
     55  $callme_num   = ''; 
     56        $results  = $asm->Command($cmd); 
     57 
     58  if (is_array($results)) 
     59  { 
     60    foreach ($results as $results_elem) 
     61    { 
     62      if (preg_match('/Value: [^\s]*/', $results_elem, $matches) != 0) 
     63      { 
     64        $parts = split(' ', trim($matches[0])); 
     65        $callme_num = $parts[1]; 
     66      } 
     67 
     68    } 
     69  } 
     70 
     71        return $callme_num; 
     72} 
     73 
     74/* Set the call me number to a new value.  No return value. */ 
     75function callme_setnum($exten, $callme_num) 
     76{ 
     77        global $asm; 
     78 
     79        $cmd = "database put AMPUSER $exten/callmenum $callme_num"; 
     80        $asm->Command($cmd); 
     81        return; 
     82} 
     83 
     84/* Perform the Originate action to the call me number for message playing. */ 
     85/* Return the result of the call (success/failure/error).                  */ 
     86function callme_startcall($to, $from, $new_path) 
     87{ 
     88  global $asm; 
     89  $channel  = "Local/$to@from-internal/n"; 
     90  $context  = "custom-callme"; 
     91  $extension  = "s"; 
     92  $priority = "1"; 
     93  $callerid = "VMAIL/$from"; 
     94  $variable = "MSG=$new_path|MBOX=$from"; 
     95  /* Arguments to Originate: channel, extension, context, priority, timeout, callerid, variable, account, application, data */ 
     96  $status = $asm->Originate($channel, $extension, $context, $priority, NULL, $callerid, $variable, NULL, NULL, NULL); 
     97  if (is_array($status)) 
     98  { 
     99    foreach ($status as $status_elem) 
     100    { 
     101      if (preg_match('/Originate successfully queued/', $status_elem, $matches) != 0) 
     102      { 
     103        return CALLME_SUCCESS; 
     104      } 
     105    } 
     106  }  
     107  return CALLME_FAILURE; 
     108} 
     109 
     110function callme_eventsoff() 
     111{ 
     112  global $asm; 
     113  $asm->Events("off"); 
     114  return; 
     115} 
     116 
     117/* Returns boolean value for a call's success status. */ 
     118function callme_succeeded($status) 
     119{ 
     120  if (strcmp($status, CALLME_SUCCESS) == 0) 
     121    return true; 
     122  else 
     123    return false; 
     124} 
     125 
     126/* Hangs up an existing channel $exten is associated with.  No return value. */ 
     127function callme_hangup($exten) 
     128{ 
     129  global $asm; 
     130  $cmd    = "local show channels"; 
     131        $chan_pat   = '/[\s]*Local\/' . trim($exten) . '@from\-internal\-[a-zA-Z0-9]*,(1|2)[\s]*/'; 
     132  $matches[0]   = ""; 
     133  $response   = ""; 
     134  $channel  = ""; 
     135  $local_channels = $asm->Command($cmd); 
     136 
     137  /* Look for our local channel. */ 
     138  if (is_array($local_channels)) 
     139  { 
     140    foreach ($local_channels as $local_channels_elem) 
     141    { 
     142      preg_match($chan_pat, $local_channels_elem, $matches); 
     143      if ($matches[0] != "") 
     144      { 
     145        $channel = $matches[0]; 
     146        break; 
     147      } 
     148    } 
     149  } else 
     150  { 
     151    $channel = ""; 
     152  } 
     153 
     154  /* If the channel was still up, hang it up. */  
     155  if ($channel != "") 
     156  { 
     157    $asm->Hangup(trim($channel)); 
     158  } 
     159  return;  
     160} 
     161?> 
  • includes/common.php

    old new  
    436436include_once("./includes/database.php"); 
    437437include_once("./includes/display.php");  
    438438include_once("./includes/ajax.php"); 
     439include_once("./includes/callme.php"); 
    439440 
    440441 
    441442?> 
  • misc/callme_page.php

    old new  
     1<?php 
     2 
     3/** 
     4 * @file 
     5 * for making call to play message 
     6 */ 
     7 
     8chdir(".."); 
     9include_once("./includes/bootstrap.php"); 
     10include_once("./includes/common.php"); 
     11 
     12?> 
     13 
     14<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
     15<html xmlns="http://www.w3.org/1999/xhtml"> 
     16  <head> 
     17    <TITLE>Voicemail Message Call Me Control</TITLE> 
     18    <link rel="stylesheet" href="../theme/main.css" type="text/css"> 
     19    <meta http-equiv="content-type" content="text/html; charset=UTF-8"> 
     20  </head> 
     21 
     22<?php 
     23  $path       = $_SESSION['ari_user']['recfiles'][$_REQUEST['recindex']]; 
     24  $pageaction = $_REQUEST['action']; 
     25  $to         = $_REQUEST['callmenum']; 
     26  $msgFrom    = $_REQUEST['msgFrom']; 
     27  $new_path   = substr($path, 0, -4);   /* Without the sound file extension. */ 
     28  $matches[0] = ''; /* init the $matches array. */ 
     29  /* Either start or end the call me call */ 
     30  switch($pageaction) 
     31  { 
     32    case "c": 
     33      /* Call me. */ 
     34      $call_status = callme_startcall($to, $msgFrom, $new_path); 
     35      echo("<table class='voicemail' style='width: 100%; height: 100%; margin: 0 0 0 0; border: 0px; padding: 0px'><tr><td valign='middle' style='border: 0px'>"); 
     36      /* if successful, display hang-up button */ 
     37      if (callme_succeeded($call_status)) 
     38      { 
     39        echo("<a href='callme_page.php?action=h&callmenum=" . $to . "'>Click here to hang up.</a>"); 
     40      } 
     41      echo("</td></tr></table>"); 
     42      echo("<script language='javascript'>parent.document.getElementById('callme_status').innerHTML = '" . _("$call_status") . "';</script>"); 
     43      echo("<script language='javascript'>parent.document.getElementById('pb_load_inprogress').value='false';</script>"); 
     44                  echo("<script language='javascript'>parent.document.getElementById('callme_status').parentNode.style.backgroundColor = 'white';</script>"); 
     45      break; 
     46    case "h": 
     47      /* Hang up. */ 
     48      /* Find the channel and hang it up if it still exists. */ 
     49      callme_hangup($to); 
     50      echo("<script language='javascript'>parent.document.getElementById('callme_status').innerHTML = '" . _("The call was terminated.") . "';</script>"); 
     51      break; 
     52  } 
     53?> 
     54  </body> 
     55</html> 
     56 
  • misc/play_page.php

    old new  
     1<?php 
     2 
     3/** 
     4 * @file 
     5 * page for playing recording 
     6 */ 
     7 
     8chdir(".."); 
     9include_once("./includes/bootstrap.php"); 
     10 
     11?> 
     12 
     13<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
     14<html xmlns="http://www.w3.org/1999/xhtml"> 
     15  <head> 
     16    <TITLE>ARI</TITLE> 
     17    <link rel="stylesheet" href="../theme/main.css" type="text/css"> 
     18    <meta http-equiv="content-type" content="text/html; charset=UTF-8"> 
     19  </head> 
     20  <body> 
     21 
     22<?php 
     23 
     24  $path = $_SESSION['ari_user']['recfiles'][$_REQUEST['recindex']]; 
     25 
     26  if (isset($path)) { 
     27 
     28    echo("<embed width='100%' src='audio.php?recindex=" . $_REQUEST['recindex'] . "' width=300, height=25 autoplay=true loop=false></embed><br>"); 
     29  } 
     30  echo("<script language='javascript'>parent.document.getElementById('pb_load_inprogress').value='false';</script>"); 
     31?> 
     32 
     33  </body> 
     34</html> 
     35 
  • misc/popup.css

    old new  
    1 /* 
    2  * popup 
    3  */ 
    4  
    5 .popup_download { 
    6   color: #105D90;  
    7   margin: 250px;  
    8   font-size: 12px;  
    9   text-align: right; 
    10 } 
  • misc/recording_popup.php

    old new  
    1 <?php 
    2  
    3 /** 
    4  * @file 
    5  * popup window for playing recording 
    6  */ 
    7  
    8 chdir(".."); 
    9 include_once("./includes/bootstrap.php"); 
    10  
    11 ?> 
    12  
    13 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
    14 <html xmlns="http://www.w3.org/1999/xhtml"> 
    15   <head> 
    16     <TITLE>ARI</TITLE> 
    17     <link rel="stylesheet" href="../theme/main.css" type="text/css"> 
    18     <link rel="stylesheet" href="popup.css" type="text/css"> 
    19     <meta http-equiv="content-type" content="text/html; charset=UTF-8"> 
    20   </head> 
    21   <body> 
    22  
    23 <?php 
    24  
    25   if (isset($_GET['recindex'])) { 
    26     $path = $_SESSION['ari_user']['recfiles'][$_GET['recindex']]; 
    27   } 
    28  
    29   if (isset($path)) { 
    30     if (isset($_GET['date'])) { 
    31       echo("<small>" . $_GET['date'] . "</small><br>"); 
    32     } 
    33     if (isset($_GET['time'])) { 
    34       echo("<small>" . $_GET['time'] . "</small><br>"); 
    35     } 
    36  
    37     echo("<br>"); 
    38     echo("<embed src='audio.php?recindex=".$_GET['recindex'] . "' width=300, height=25 autoplay=true loop=false></embed><br>"); 
    39     echo("<a class='popup_download' href=/recordings/misc/audio.php?recindex="  . $_GET['recindex'] . ">" . _("download") . "</a><br>"); 
    40   } 
    41  
    42 ?> 
    43  
    44   </body> 
    45 </html> 
    46  
  • modules/callmonitor.module

    old new  
    6767    if ($a=='delete') { 
    6868      if (count($files) > 0) { 
    6969        $this->deleteRecData($files); 
    70       } 
    71       else { 
     70      } else { 
    7271        $_SESSION['ari_error'] 
    7372          = _("One or more messages must be selected before clicking delete."); 
    7473      } 
     
    214214 
    215215    // table body 
    216216    unset($_SESSION['ari_user']['recfiles']); 
     217    // Index to keep track of where playback control rows should be inserted. 
     218    $playbackRow = 2; 
    217219    if (is_array($data)) foreach($data as $key=>$value) { 
    218220      $i++; 
    219221 
     
    225227      $date = $buf[0]; 
    226228      $time = $buf[1]; 
    227229 
    228  
    229230      $recordingLink = ''; 
    230       if (is_file($recordings[$value['uniqueid'] . $value['calldate']])) { 
     231      $downloadLink = ''; 
     232      if (is_file($recording)) { 
    231233        $_SESSION['ari_user']['recfiles'][$i] = $recording; 
    232         $recordingLink = "<a href='#' onClick=\"javascript:popUp('misc/recording_popup.php?recindex=" . $i . "&date=" . $date . "&time=" . $time . "'); return false;\">" . _("play") . "</a>"; 
    233        // recording delete checkbox 
     234        $recordingLink = "<a href='#' onClick=\"javascript:play($playbackRow, 'misc/play_page.php?recindex=" . $i . "'); return false;\"><img src='theme/images/sound.png' title=" . _("Play") . "></img></a>"; 
     235        $downloadLink = "<a href=/recordings/misc/audio.php?recindex=" . $i . "><img src='theme/images/drive_go.png' title=" . _("Download") . "></img></a>"; 
    234236        if ($CALLMONITOR_ALLOW_DELETE) { 
    235237          $recording_delete_checkbox = "<td class='checkbox'><input type=checkbox name='selected" . $i . "' value=" . $i . "></td>"; 
    236238        } 
     
    239241          $recording_delete_checkbox = "<td class='checkbox'></td>"; 
    240242        } 
    241243      } 
    242      
     244      $playbackRow++; 
    243245      $recording_body .= "<tr> 
    244246                       " . $recording_delete_checkbox . " 
    245247                 <td width=70>" . $date . "</td> 
     
    249251                 <td>" . $value[dst] . "</td> 
    250252                 <td>" . $value[dcontext] . "</td> 
    251253                 <td width=90>" . $value[duration] . " sec</td> 
    252                  <td>" . $recordingLink . "</td> 
     254          <td>" . $recordingLink . "&nbsp;&nbsp;" . $downloadLink . "</td> 
    253255               </tr>"; 
    254256    } 
    255257    if (!count($data)) { 
     
    284286 
    285287      $ret .= " 
    286288        <form  name='callmonitor_form' action='" . $_SESSION['ARI_ROOT'] . "' method='GET'> 
     289          <input type=hidden id='pb_load_inprogress' value='false'> 
    287290          <input type=hidden name=m value=" . $m . ">  
    288291          <input type=hidden name=f value=recAction> 
    289292          <input type=hidden name=a value=''> 
     
    296299 
    297300    $ret .= $display->displayInfoBarBlock($controls,$q,$start,$span,$record_count); 
    298301 
    299     // javascript for popup and message actions 
     302    // javascript for message actions 
    300303    $ret .= " 
    301304      <SCRIPT LANGUAGE='JavaScript'> 
    302305      <!-- Begin 
    303       function popUp(URL) { 
    304         eval(\"page = window.open(URL, 'play', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=1,width=324,height=110');\"); 
     306      function play(row_num, link) { 
     307  var i = 0; 
     308  var playbackId = \"CURRENT_MSG\"; 
     309  var cmTable = document.getElementById('callmonitor_table'); 
     310  // Only one playback row is allowed to be open at a time. 
     311  // If one is already open, close it. 
     312  for (i = 0; i < cmTable.rows.length; i++) { 
     313    if (cmTable.rows[i].id == playbackId) { 
     314      // Delete the row; it's a Playback control row. 
     315      cmTable.deleteRow(cmTable.rows[i].rowIndex); 
     316    } 
     317  } 
     318  // Make our Playback row. 
     319  playback_src = \"<iframe width='100%' height='25px' marginheight='0' marginwidth='0' frameborder='0' scrolling='no' src=\" + link + \"></iframe>\"; 
     320        newRow = cmTable.insertRow(row_num); 
     321        newRow.id = playbackId; 
     322  cell_left = newRow.insertCell(0); 
     323  cell_left.colSpan = 9; 
     324        cell_left.innerHTML = playback_src; 
    305325      } 
    306  
    307326      function checkAll(form,set) { 
    308327        var elem = 0; 
    309328        var i = 0; 
     
    339358 
    340359    // table 
    341360    $ret .= " 
    342       <table class='callmonitor'> 
     361      <table id='callmonitor_table' class='callmonitor'> 
    343362        <tr> 
    344363          " . $recording_delete_header . " 
    345364          " . $recording_header . " 
  • modules/settings.module

    old new  
    8989    $voicemail_audio_format   = getArgument($args,'voicemail_audio_format'); 
    9090    $record_in          = getArgument($args,'record_in'); 
    9191    $record_out         = getArgument($args,'record_out'); 
     92    $callme_num     = getArgument($args,'callme_number'); 
    9293     
    9394    if (isset($_SESSION['ari_user']['voicemail_email'])) { 
    9495      foreach (array_keys($_SESSION['ari_user']['voicemail_email']) as $key) { 
     
    100101    if ($a=='update') { 
    101102 
    102103    $exten = $_SESSION['ari_user']['extension']; 
     104    $old_callme = callme_getnum($exten); 
     105    // Update the Call Me number, if necessary. 
     106    if (strcmp($callme_num, $old_callme) != 0) { 
     107      callme_setnum($exten, $callme_num); 
     108    } 
     109 
    103110    if ($exten!=$ARI_ADMIN_USERNAME) { 
    104111       
    105112      // Make sure Follow-Me setup has not been deleted for this user since the last refresh 
     
    342349    // get data 
    343350    $data = $this->getRecordSettings($_SESSION['ari_user']['extension']); 
    344351 
     352    // get the Call Me number 
     353    $callme_num = callme_getnum($exten); 
     354 
    345355    // lang setting options 
    346356    if (extension_loaded('gettext')) {  
    347357      $setLangText = "<p class='lang'>" . _("Language:") . " " . $language->GetForm() . "</p>"; 
     
    473483      } 
    474484    } 
    475485     
     486    $set_voicemail_callme_text = " 
     487      <tr> 
     488      <td>" . _("Call Me Number:") . "</td> 
     489      <td> 
     490      <input type='text' id='callme_number' name='callme_number' 
     491      value='" . $callme_num . "'> 
     492      </input> 
     493      </td> 
     494      </tr>"; 
     495 
    476496    $wav_enable = 'selected'; 
    477497    if ($_COOKIE['ari_voicemail_audio_format']=='.gsm'||  
    478498    ($_COOKIE['ari_voicemail_audio_format']=='' && $ARI_VOICEMAIL_AUDIO_FORMAT_DEFAULT='.gsm')) { 
     
    498518      </tr> 
    499519      " . $set_voicemail_password_text . " 
    500520      " . $set_voicemail_email_text . " 
     521      " . $set_voicemail_callme_text . " 
    501522      " . $set_voicemail_audio_format_text . " 
    502523      </table>"; 
    503524  } 
  • modules/voicemail.module

    old new  
    99  * Class for voicemail 
    1010  */ 
    1111class Voicemail { 
     12  var $callme_num = ""; 
    1213 
    1314  /* 
    1415   * rank (for prioritizing modules) 
     
    2324   * init 
    2425   */ 
    2526  function init() { 
     27    $extension = $_SESSION['ari_user']['extension']; 
     28    $this->callme_num = callme_getnum($extension); 
     29    if (empty($this->callme_num)) { 
     30  $this->callme_num = $extension;   // callme_num defaults to user's extension. 
     31  callme_setnum($extension, $extension); 
     32    } 
    2633  } 
    2734 
    2835  /* 
     
    393400 
    394401      $i++; 
    395402    } 
    396     $recording_header .= "<th>" . _("Message") . "</th>"; 
     403    $recording_header .= "<th>" . _("Playback") . "</th>"; 
    397404 
     405    // Column to provide a download link for each message in voicemail. 
     406    $download_header .= "<th>" . _("Download"). "</th>"; 
    398407    // table body 
    399408    unset($_SESSION['ari_user']['recfiles']); 
    400409    if (isset($data)) { 
     410      $playbackRow = 2; // Index for where playback control rows used by javascript playback() should appear in the table.   
     411      // First control row would appear below row 1 (hence $playbackRow starts at 2); control rows are inserted/deleted as needed. 
    401412      foreach($data as $file=>$value) { 
    402413        $i++; 
    403         // recording popup link 
     414        // Playback links 
    404415        $voicemail_audio_format = $voicemail_audio_format=='' ? '.wav' : $voicemail_audio_format; 
    405416        $recording = preg_replace('/.txt/', $voicemail_audio_format, $file); 
    406417        $date = GetDateFormat($value['origtime']); 
     
    411422        $duration = $value[duration]; 
    412423        if (is_file($recording)) { 
    413424          $_SESSION['ari_user']['recfiles'][$i] = $recording; 
    414           $recordingLink = "<a href='#' onClick=\"javascript:popUp('misc/recording_popup.php?recindex=$i&date=" . $date . "&time=" . $time . "'); return false;\"> 
    415             " . _("play") . " 
    416           </a>"; 
     425    $recordingLink = "<a href='#' onClick=\"javascript:playback('play', $playbackRow, 'misc/play_page.php?recindex=" . $i . "'); return false;\"><img src='theme/images/sound.png' title=" . _("Play") . "></img></a>"; 
     426    $callmePage   = "'misc/callme_page.php?recindex=" . $i . "&callmenum=" . $this->callme_num . "&action=c&msgFrom=" . $extension . "'"; 
     427    $callme_tooltip = _("Play message at: ") . $this->callme_num; 
     428    $callmeLink = "<a href='#' onClick=\"javascript:playback('callme', $playbackRow, $callmePage); return false;\"><img src='theme/images/telephone.png' title='" . $callme_tooltip . "'></img></a>"; 
     429    $downloadLink = "<a href=/recordings/misc/audio.php?recindex=" . $i . "><img src='theme/images/drive_go.png' title=" . _("Download") . "></img></a>"; 
    417430        }  
    418431        else { 
    419432          $_SESSION['ari_error'] = _("Voicemail recording(s) was not found.") . "<br>" . 
    420433                                   sprintf(_("On settings page, change voicemail audio format.  It is currently set to %s"),$voicemail_audio_format); 
    421           $recordingLink = "<a href='#' onClick=\"javascript:popUp('misc/recording_popup.php?recindex=$i&date=" . $date . "&time=" . $time . "'); return false;\"> 
    422             " . _("play") . " 
    423           </a>"; 
    424434        } 
    425435 
    426436        $tableText .= " 
     
    432442            <td>" . $value[priority] . "</td> 
    433443            <td width=90>" . $to . "</td> 
    434444            <td>" . $duration . " sec</td> 
    435             <td>" . $recordingLink . "</td> 
     445            <td>" . $recordingLink . "&nbsp;&nbsp;" . $callmeLink . "</td> 
     446            <td>" . $downloadLink . "</td> 
    436447          </tr>"; 
     448 
     449  $playbackRow++; 
    437450      } 
    438451    }  
     452 
    439453    // options 
    440454    $url_opts = array(); 
    441455    $url_opts['folder'] = $folder; 
     
    472486    $ret .= $display->displayHeaderText(sprintf(_("Voicemail for %s (%s)"),$displayname,$extension)); 
    473487    $ret .= $display->displaySearchBlock('left',$m,$q,$url_opts,true); 
    474488 
     489    // pb_load_inprogress is a hidden element that is used by the javascript playback() 
     490    // as a boolean to keep track of whether or not a Playback (Call Me or Computer Play) from this page is in progress ("loading"). 
    475491    // start form 
    476492    $ret .= " 
    477493      <form name='voicemail_form' action='" . $_SESSION['ARI_ROOT'] . "' method='GET'> 
     494        <input type=hidden id='pb_load_inprogress' value='false'> 
    478495        <input type=hidden name=m value=" . $m . ">  
    479496        <input type=hidden name=f value=msgAction> 
    480497        <input type=hidden name=a value=''> 
     
    487504 
    488505    $ret .= $display->displayInfoBarBlock($controls,$q,$start,$span,$record_count); 
    489506 
    490     // add javascript for popup and message actions 
     507    // Variables used in generating playback() javascript. 
     508    $callme_status_msg0 = _("Calling: "); 
     509    $callme_status_msg1 = _(". Please wait patiently..."); 
     510 
     511    // add javascript for playback and message actions 
    491512    $ret .= " 
    492513      <SCRIPT LANGUAGE='JavaScript'> 
    493514      <!-- Begin 
    494       function popUp(URL) { 
    495         popup = window.open(URL, 'play', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=1,width=324,height=110'); 
    496       } 
    497  
    498515      function checkAll(form,set) { 
    499516        var elem = 0; 
    500517        var i = 0; 
     
    508525        } 
    509526        return true; 
    510527      } 
     528 
     529      // Playback function 
     530      function playback(mode, row_num, link) { 
     531  var playbackId = \"CURRENT__MSG\"; 
     532  var i = 0; 
     533  var vmTable = document.getElementById('vmail_table'); 
     534  var inprogress = document.getElementById('pb_load_inprogress').value; 
     535  // Only start a Playback control if another one is NOT in progress. 
     536  if (inprogress == \"false\") { 
     537    // Only one Playback control row can be open at a time. 
     538    // If one is already open (e.g. a call that is now over or a message already loaded for playback), close it. 
     539    for (i = 0; i < vmTable.rows.length; i++) { 
     540      if (vmTable.rows[i].id == playbackId) { 
     541        // Delete the row; it's a Playback control row. 
     542        vmTable.deleteRow(vmTable.rows[i].rowIndex); 
     543      } 
     544    } 
     545    // Make our Playback row. 
     546    playback_src = \"<iframe width='100%' height='25px' marginheight='0' marginwidth='0' frameborder='0' scrolling='no' src=\" + link + \"></iframe>\"; 
     547    document.getElementById('pb_load_inprogress').value = \"true\"; 
     548    newRow = vmTable.insertRow(row_num); 
     549    newRow.id = playbackId; 
     550    cell_left = newRow.insertCell(0); 
     551    if (mode == 'callme') { 
     552      cell_left.colSpan = 4; 
     553      cell_left.innerHTML = \"<div id='callme_status'>" . $callme_status_msg0 . $this->callme_num . $callme_status_msg1 . "</div>\"; 
     554      cell_right = newRow.insertCell(1); 
     555      cell_right.colSpan = 5; 
     556      cell_right.innerHTML = playback_src; 
     557    } else { 
     558      cell_left.colSpan = 9; 
     559      cell_left.innerHTML = playback_src; 
     560    } 
     561  } else { 
     562    // Change background color of status cell to alert user that the playback is still loading. 
     563    document.getElementById(\"callme_status\").parentNode.style.backgroundColor = 'yellow'; 
     564  } 
     565      } 
    511566      // End --> 
    512567      </script>"; 
    513568 
     
    525580 
    526581    // table 
    527582    $ret .= " 
    528       <table class='voicemail'> 
     583      <table id='vmail_table' class='voicemail'> 
    529584        <tr> 
    530585           " . $recording_delete_header . " 
    531586           " . $recording_header . " 
     587           " . $download_header . " 
    532588        </tr> 
    533589        " . $tableText . " 
    534590      </table>";