Parent Directory
|
Revision Log
|
Revision Graph
more lax file perms. fixing playback file debugging code.
| 1 | <?php |
| 2 | // $Id: asterisk.module,v 1.107 2008/06/02 03:01:33 thehunmonkgroup Exp $ |
| 3 | |
| 4 | /** |
| 5 | * @file |
| 6 | * Enables integratation of Drupal and asterisk |
| 7 | */ |
| 8 | |
| 9 | define('DEBUG', FALSE); |
| 10 | |
| 11 | /* |
| 12 | * Core drupal hooks. |
| 13 | */ |
| 14 | |
| 15 | /** |
| 16 | * Implementation of hook_block |
| 17 | */ |
| 18 | function asterisk_block($op = 'list', $delta = 0, $edit = array()) { |
| 19 | if ($op == 'list') { |
| 20 | $blocks[0]['info'] = t('Displays a listing of recent audio files. Users can click to hear the file via phone'); |
| 21 | $blocks[0]['cache'] = BLOCK_CACHE_PER_USER; |
| 22 | $blocks[1]['info'] = t('Display a simple text entry to originate calls'); |
| 23 | $blocks[1]['cache'] = BLOCK_CACHE_PER_USER; |
| 24 | return $blocks; |
| 25 | } |
| 26 | else if ($op == 'configure') { |
| 27 | switch ($delta) { |
| 28 | case 0: |
| 29 | $form['asterisk_audio_block_items'] = array('#type' => 'select', |
| 30 | '#title' => t('Number of audio files to show'), |
| 31 | '#options' => array('3', '4', '5', '6', '7', '8'), |
| 32 | '#default_value' => variable_get('asterisk_audio_block_items', 5), |
| 33 | ); |
| 34 | break; |
| 35 | case 1: |
| 36 | $form['asterisk_call_number_help'] = array('#type' => 'textarea', |
| 37 | '#title' => t('Call number instructions'), |
| 38 | '#default_value' => variable_get('asterisk_call_number_help', t('You can dial Free World Dialup numbers as fwd://')), |
| 39 | ); |
| 40 | break; |
| 41 | } |
| 42 | return $form; |
| 43 | } |
| 44 | else if ($op == 'save') { |
| 45 | switch($delta) { |
| 46 | case 0: |
| 47 | variable_set('asterisk_audio_block_items', $edit['asterisk_audio_block_items']); |
| 48 | break; |
| 49 | case 1: |
| 50 | variable_set('asterisk_call_number_help', $edit['asterisk_call_number_help']); |
| 51 | break; |
| 52 | } |
| 53 | } |
| 54 | else if ($op == 'view') { |
| 55 | switch($delta) { |
| 56 | case 0: |
| 57 | $block['subject'] = t('Recent audio files'); |
| 58 | $block['content'] = asterisk_audio_file_block(); |
| 59 | break; |
| 60 | case 1: |
| 61 | $block['subject'] = t('Make call'); |
| 62 | $block['content'] = drupal_get_form('asterisk_make_call_block_form'); |
| 63 | break; |
| 64 | } |
| 65 | return $block; |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | /** |
| 70 | * Implementation of hook_cron() |
| 71 | */ |
| 72 | function asterisk_cron() { |
| 73 | // check for queued messages needs to go here. |
| 74 | } |
| 75 | |
| 76 | function asterisk_form_alter(&$form, $form_state, $form_id) { |
| 77 | |
| 78 | switch ($form_id) { |
| 79 | // node settings form |
| 80 | case 'node_type_form': |
| 81 | $type = $form['old_type']['#value']; |
| 82 | $form['workflow']['asterisk_node'] = array( |
| 83 | '#type' => 'checkbox', |
| 84 | '#title' => t('Allow telephone recordings'), |
| 85 | '#default_value' => variable_get('asterisk_node_'. $type, 0), |
| 86 | '#description' => t('Enabling will allow users with the appropriate permissions to record attachments by telephone.'), |
| 87 | ); |
| 88 | break; |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | /** |
| 93 | * Implementation of hook_help(). |
| 94 | */ |
| 95 | function asterisk_help($path, $arg) { |
| 96 | switch ($path) { |
| 97 | case 'admin/help#asterisk': |
| 98 | global $user; |
| 99 | |
| 100 | return t("<p>The Asterisk integration project seeks to add a rich telephony feature set to Drupal. This module maintains a call queue in your local drupal database.</p> |
| 101 | |
| 102 | <p>In order for these calls to be actually made, you must either configure your own asterisk or use an asterisk server that has already been set up to provide drupal services. </p> |
| 103 | |
| 104 | <p>You can view the !site-logs. Each user will have access to their own call logs. This is accessed by clicking the 'My calls' tab while under 'My account'. For example, here are your !user-logs</p>", array('!site-logs' => l(t('site wide call logs'), 'admin/asterisk/calls'), '!user-logs' => l(t('personal call logs'), 'user/'.$user->uid.'/calls'))); |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | /** |
| 109 | * Implementation of hook_menu() |
| 110 | */ |
| 111 | function asterisk_menu() { |
| 112 | |
| 113 | global $user; |
| 114 | |
| 115 | $make_calls = array('make calls'); |
| 116 | $admin_calls = array('administer calls'); |
| 117 | $admin_asterisk = array('administer asterisk configuration'); |
| 118 | |
| 119 | $items = array(); |
| 120 | |
| 121 | $items['asterisk/callnumber'] = array( |
| 122 | 'title' => 'Call number', |
| 123 | 'page callback' => 'asterisk_page', |
| 124 | 'access callback' => 'user_access', |
| 125 | 'access arguments' => $make_calls, |
| 126 | 'type' => MENU_CALLBACK, |
| 127 | ); |
| 128 | $items['asterisk/calluser'] = array( |
| 129 | 'title' => 'Call user', |
| 130 | 'page callback' => 'asterisk_page', |
| 131 | 'access callback' => 'asterisk_calluser_access', |
| 132 | 'type' => MENU_CALLBACK, |
| 133 | ); |
| 134 | $items['asterisk/callme'] = array( |
| 135 | 'title' => 'Call me', |
| 136 | 'page callback' => 'asterisk_page', |
| 137 | 'access callback' => 'user_access', |
| 138 | 'access arguments' => $make_calls, |
| 139 | 'type' => MENU_CALLBACK, |
| 140 | ); |
| 141 | $items['asterisk/play'] = array( |
| 142 | 'title' => 'Play me', |
| 143 | 'page callback' => 'asterisk_page', |
| 144 | 'access callback' => 'user_access', |
| 145 | 'access arguments' => $make_calls, |
| 146 | 'type' => MENU_CALLBACK, |
| 147 | ); |
| 148 | // Admin menu items. |
| 149 | $items['admin/asterisk'] = array( |
| 150 | 'title' => 'Asterisk integration', |
| 151 | 'description' => 'Manage integration with an Asterisk server.', |
| 152 | 'page callback' => 'system_admin_menu_block_page', |
| 153 | 'access callback' => 'user_access', |
| 154 | 'access arguments' => $admin_asterisk, |
| 155 | ); |
| 156 | $items['admin/asterisk/settings'] = array( |
| 157 | 'title' => 'Settings', |
| 158 | 'description' => 'Set up a connection with an Asterisk server. ', |
| 159 | 'page callback' => 'drupal_get_form', |
| 160 | 'page arguments' => array('asterisk_settings_form'), |
| 161 | 'access callback' => 'user_access', |
| 162 | 'access arguments' => $admin_asterisk, |
| 163 | ); |
| 164 | $items['admin/asterisk/server_test'] = array( |
| 165 | 'title' => 'Test XML-RPC connection', |
| 166 | 'page callback' => 'asterisk_server_test', |
| 167 | 'access callback' => 'user_access', |
| 168 | 'access arguments' => $admin_asterisk, |
| 169 | 'type' => MENU_CALLBACK, |
| 170 | ); |
| 171 | $items['admin/asterisk/calls'] = array( |
| 172 | 'title' => 'Call logs', |
| 173 | 'description' => 'View logs of all placed calls.', |
| 174 | 'page callback' => 'asterisk_call_log', |
| 175 | 'access callback' => 'user_access', |
| 176 | 'access arguments' => $admin_calls, |
| 177 | ); |
| 178 | |
| 179 | $items['user/%user/calls'] = array( |
| 180 | 'title' => 'My calls', |
| 181 | 'page callback' => 'asterisk_call_log', |
| 182 | 'page arguments' => array(1), |
| 183 | 'access callback' => 'asterisk_call_log_access', |
| 184 | 'access arguments' => array(1), |
| 185 | 'type' => MENU_LOCAL_TASK, |
| 186 | 'weight' => 4, |
| 187 | ); |
| 188 | |
| 189 | return $items; |
| 190 | } |
| 191 | |
| 192 | /** |
| 193 | * Access callback for asterisk/calluser. |
| 194 | */ |
| 195 | function asterisk_calluser_access() { |
| 196 | return user_access('make calls') && user_access('access user profiles'); |
| 197 | } |
| 198 | |
| 199 | /** |
| 200 | * Access callback for user/%user/calls. |
| 201 | */ |
| 202 | function asterisk_call_log_access($account) { |
| 203 | global $user; |
| 204 | return ($account->uid == $user->uid && user_access('make calls')) || user_access('administer calls'); |
| 205 | } |
| 206 | |
| 207 | /* |
| 208 | * Implementation of hook_nodeapi |
| 209 | */ |
| 210 | function asterisk_nodeapi(&$node, $op) { |
| 211 | global $user; |
| 212 | switch ($op) { |
| 213 | case 'view': |
| 214 | if ((($node->uid == $user->uid && user_access('make calls') && user_access('upload recordings')) || user_access('administer calls')) && variable_get('asterisk_node_'. $node->type, 0)) { |
| 215 | $node->content['asterisk_record_form'] = array( |
| 216 | '#value' => drupal_get_form('asterisk_record_form', $node), |
| 217 | '#weight' => 10, |
| 218 | ); |
| 219 | } |
| 220 | break; |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | function asterisk_record_form(&$form_state, $node) { |
| 225 | $form = array(); |
| 226 | $form['asterisk_record'] = array('#type' => 'fieldset', |
| 227 | '#title' => t('Record attachment'), |
| 228 | '#collapsible' => TRUE, |
| 229 | '#collapsed' => TRUE, |
| 230 | '#description' => t('Note: once you click \'Record file\', you will receive a call to the telephone number you have listed on your user page. Wait for the beep and record your message. Hang up when finished, and the message will be uploaded to %title shortly thereafter.', array('%title' => $node->title)), |
| 231 | ); |
| 232 | $form['asterisk_record']['asterisk_record_nid'] = array('#type' => 'value', |
| 233 | '#value' => $node->nid, |
| 234 | ); |
| 235 | $form['asterisk_record']['asterisk_record_file'] = array('#type' => 'textfield', |
| 236 | '#title' => t('Filename'), |
| 237 | '#description' => t('A name for your audio file. Please use only letters, numbers, dashes, and underscores--no spaces, and no file extension.'), |
| 238 | '#required' => TRUE, |
| 239 | ); |
| 240 | $form['asterisk_record']['asterisk_record_list_file'] = array('#type' => 'checkbox', |
| 241 | '#title' => t('List file immediately'), |
| 242 | '#description' => t('If checked, the file will be listed for viewing immediately upon upload--otherwise it must specifically enabled for viewing at a later time.'), |
| 243 | ); |
| 244 | /* $form['asterisk_record']['callee_number'] = array('#type' => 'textfield', |
| 245 | '#title' => t('Second Party Number'), |
| 246 | '#description' => t('If you\'d like to connect to another party first before beginning the recording, enter the party\'s number here. Leave blank if you just want to record yourself. <em>Note: once you are connected to the other party, you can start and stop recording by pressing *1</em>'), |
| 247 | );*/ |
| 248 | $form['asterisk_record']['submit'] = array('#type' => 'submit', |
| 249 | '#value' => t('Record file'), |
| 250 | ); |
| 251 | return $form; |
| 252 | } |
| 253 | |
| 254 | /** |
| 255 | * Implementation of hook_perm() |
| 256 | */ |
| 257 | function asterisk_perm() { |
| 258 | return array( |
| 259 | 'make calls', |
| 260 | 'upload recordings', |
| 261 | 'administer calls', |
| 262 | 'administer asterisk configuration', |
| 263 | ); |
| 264 | } |
| 265 | |
| 266 | /** |
| 267 | * Implementation of hook_settings() |
| 268 | */ |
| 269 | function asterisk_settings_form(&$form_state) { |
| 270 | global $base_url; |
| 271 | |
| 272 | $form = array(); |
| 273 | $form['asterisk_phone_number_message'] = array('#type' => 'textarea', |
| 274 | '#title' => t('Profile page text'), |
| 275 | '#default_value' => variable_get('asterisk_phone_number_message', t('Your phone number of course. You must put your country code, eg 1 for USA. An example would be 13213210123 for a US (NANPA) number')), |
| 276 | '#description' => t('Help text for the user profile page. You should state which types of numbers are allowed by your drupal site'), |
| 277 | '#cols' => 50, |
| 278 | '#rows' => 4, |
| 279 | ); |
| 280 | |
| 281 | // Asterisk XML-RPC server settings. |
| 282 | $form['asterisk_instant_notification'] = array('#type' => 'fieldset', |
| 283 | '#title' => t('Asterisk server connection parameters'), |
| 284 | '#description' => t('<em>Warning: It is highly recommended that you connect to an Asterisk server that has set up a secure XML-RPC server via SSL, otherwise your credentials and data will be transmitted unencrypted. If another party were to successfully intercept them, they might be able to make calls through the Asterisk server as you!</em>'), |
| 285 | ); |
| 286 | $form['asterisk_instant_notification']['asterisk_server_url'] = array('#type' => 'textfield', |
| 287 | '#title' => t('Asterisk XML-RPC URL'), |
| 288 | '#default_value' => variable_get('asterisk_server_url', ''), |
| 289 | '#maxlength' => 255, |
| 290 | '#description' => t('The URL of the XML-RPC server on your Asterisk installation (ex: https://example.com/asterisk_xmlrpc.php). The client end of this module supports both http and https connections.'), |
| 291 | ); |
| 292 | $form['asterisk_instant_notification']['asterisk_server_user'] = array( |
| 293 | '#type' => 'item', |
| 294 | '#title' => t('Asterisk username: %username', array('%username' => _asterisk_create_username())), |
| 295 | '#description' => '<em>'. t('Set automatically by the system.') .'</em>', |
| 296 | ); |
| 297 | |
| 298 | $form['asterisk_instant_notification']['asterisk_server_pass'] = array('#type' => 'textfield', |
| 299 | '#title' => t('Asterisk server password'), |
| 300 | '#default_value' => variable_get('asterisk_server_pass', ''), |
| 301 | '#size' => 30, |
| 302 | '#maxlength' => 30, |
| 303 | '#description' => t('The password that you have configured on the Asterisk server for this website.'), |
| 304 | ); |
| 305 | $drupal_url = $base_url .'/xmlrpc.php'; |
| 306 | $form['asterisk_instant_notification']['asterisk_drupal_url'] = array('#type' => 'textfield', |
| 307 | '#title' => t('Drupal XML-RPC URL'), |
| 308 | '#default_value' => variable_get('asterisk_drupal_url', $drupal_url), |
| 309 | '#maxlength' => 255, |
| 310 | '#description' => t('The URL of the XML-RPC server on your Drupal installation. This is most probably %drupal_url', array('%drupal_url' => $drupal_url)), |
| 311 | ); |
| 312 | $form['asterisk_instant_notification']['asterisk_drupal_server_test'] = array('#value' => '<div>'. l(t('Test connection'), 'admin/asterisk/server_test') .' -- use this only after you have saved the settings!</div>'); |
| 313 | |
| 314 | return system_settings_form($form); |
| 315 | } |
| 316 | |
| 317 | /** |
| 318 | * Implementation of hook_user() |
| 319 | */ |
| 320 | function asterisk_user($op, &$edit, &$account) { |
| 321 | |
| 322 | switch($op) { |
| 323 | case 'load': |
| 324 | asterisk_user_load($account); |
| 325 | break; |
| 326 | case 'insert': |
| 327 | asterisk_user_insert($edit, $account); |
| 328 | break; |
| 329 | case 'update': |
| 330 | asterisk_user_update($edit, $account); |
| 331 | break; |
| 332 | case 'delete': |
| 333 | asterisk_user_delete($edit, $account); |
| 334 | break; |
| 335 | case 'form': |
| 336 | return asterisk_user_form($edit, $account); |
| 337 | case 'view': |
| 338 | |
| 339 | /* |
| 340 | * Adds a telephone number to the users profile. |
| 341 | * Users with telephone numbers can click to call other users |
| 342 | */ |
| 343 | if (user_access('make calls') && isset($account->number) && $account->number != '') { |
| 344 | if (_asterisk_is_same_user($account)) { |
| 345 | $output = l(t('Call me'), 'asterisk/callme', array('query' => drupal_get_destination())); |
| 346 | } |
| 347 | else { |
| 348 | $output = l(t('Call user'), "asterisk/calluser/$account->uid", array('query' => drupal_get_destination())); |
| 349 | } |
| 350 | |
| 351 | if (!isset($account->content['telephone'])) { |
| 352 | $account->content['telephone'] = array(); |
| 353 | } |
| 354 | $account->content['telephone'] += array( |
| 355 | '#type' => 'user_profile_category', |
| 356 | '#attributes' => array('class' => 'user-member'), |
| 357 | '#weight' => 10, |
| 358 | '#title' => t('Telephone'), |
| 359 | ); |
| 360 | $account->content['telephone']['call_link'] = array( |
| 361 | '#type' => 'user_profile_item', |
| 362 | '#title' => t('Place calls'), |
| 363 | '#value' => $output, |
| 364 | ); |
| 365 | } |
| 366 | break; |
| 367 | } |
| 368 | } |
| 369 | |
| 370 | /** |
| 371 | * Implementation of hook_xmlrpc() |
| 372 | */ |
| 373 | function asterisk_xmlrpc() { |
| 374 | return array( |
| 375 | array( |
| 376 | 'asterisk.notify.NewMessages', |
| 377 | 'asterisk_check_messages', |
| 378 | array('boolean', 'array'), |
| 379 | t('receives a list of new messages from the Asterisk server') |
| 380 | ), |
| 381 | ); |
| 382 | } |
| 383 | |
| 384 | /** |
| 385 | * @defgroup Asterisk call API |
| 386 | * @{ |
| 387 | * Functions to make calls using Asterisk. |
| 388 | * |
| 389 | * These functions can connect two users, playback a message to a single user |
| 390 | * and record a message over the phone. |
| 391 | */ |
| 392 | |
| 393 | /** |
| 394 | * Builds a call array, adding defaults if necessary |
| 395 | * |
| 396 | * @param $call |
| 397 | * An associative array of call parameters, key = parameter name, value = value. |
| 398 | * The following parameters are valid: |
| 399 | * |
| 400 | * 'caller_number' => Phone number to call first. When answered the caller will |
| 401 | * hear ringing until the 'callee' answers. The phone number types supported depend |
| 402 | * on the configuration of the Asterisk server. The default configuration |
| 403 | * allows calls to SIP, IAX(2), and FWD (http://fwdnet.net) numbers. PSTN |
| 404 | * calling can be enabled by configuring a VoIP provider or PSTN connection |
| 405 | * with Asterisk. |
| 406 | * |
| 407 | * Number formats are as follows: |
| 408 | * IAX: iax://username user is registered to your asterisk server |
| 409 | * SIP: sip://username |
| 410 | * FWD: fwd://fwd_number |
| 411 | * |
| 412 | * Numbers can also be regular Asterisk extensions. These extensions must be |
| 413 | * in the context that the call goes to. The default context is drupal. Extensions |
| 414 | * are more useful when used as 'callee' numbers. |
| 415 | * |
| 416 | * 'callee_number' => Phone number to connect the first number to. This is usually an Asterisk |
| 417 | * extension. This parameter follows the same rules as 'caller_number'. |
| 418 | * |
| 419 | * 'module' => The module that originated the call. This is also useful for tracking |
| 420 | * purposes. |
| 421 | * |
| 422 | * 'uid' => The user ID to log as the originator of the call. Useful for tracking. Default is 0. |
| 423 | * |
| 424 | * 'dispatch_time' => Earliest time that the call should be made (and hopefully not too long |
| 425 | * after!). This should be a Unix timestamp. Drupal won't deliver the call |
| 426 | * to Asterisk until this time. The time the call will actually be made will |
| 427 | * depend on: |
| 428 | * 1. How frequently the Drupal site checks for queued calls to send |
| 429 | * 2. How long the Asterisk server takes to make the call. This is usually |
| 430 | * a fraction of a second, depending on load. |
| 431 | * Default is immediately. |
| 432 | * |
| 433 | * 'caller_id' => Caller ID to set for the call. Not all providers allow setting the caller |
| 434 | * ID. Generally VoIP providers will allow this for most calls, digital TDM |
| 435 | * (T1, E1, etc.) allows this if you have the feature from your provider, |
| 436 | * analog lines do not support this (regular phone lines). Default is no caller ID |
| 437 | * |
| 438 | * Note: Most providers require this to be a numeric string! VoIP endpoints |
| 439 | * SIP, IAX, FWD(uses SIP), etc. will accept strings as well. |
| 440 | * |
| 441 | * 'vars' => An array of variables to pass to Asterisk. These variables can then be |
| 442 | * used in your dialplan or AGI script. |
| 443 | * |
| 444 | * 'max_retries' => Number of retries before failing (not including the initial attempt, e.g. |
| 445 | * 0 = total of 1 attempt to make the call). Default is 2. |
| 446 | * |
| 447 | * 'retry_time' => Seconds between retries, don't hammer an unavailable phone. Default is 60 seconds |
| 448 | * |
| 449 | * 'wait_time' => Seconds to wait for an answer. Default is 30 seconds. |
| 450 | * |
| 451 | * 'context' => Context that the callee call will be made in. Default is 'drupal'. |
| 452 | * |
| 453 | * 'priority' => The priority of the extension for the call part of the call. Default is 1. |
| 454 | * |
| 455 | * 'call_status' => Whether the call has been sent to the Asterisk server. This is set to 'dipatched' |
| 456 | * by default. If you're not dispatching a call immediately, set to 'uncalled', and set the |
| 457 | * 'dispatch_time' parameter appropriately. |
| 458 | * |
| 459 | * 'drupal_filename' => Name of a file to be recorded. This is only valid if a recording call |
| 460 | * is being passed. |
| 461 | * |
| 462 | * @return |
| 463 | * Returns the full calll array with defaults added if necessary. |
| 464 | */ |
| 465 | function asterisk_call($call) { |
| 466 | |
| 467 | // Set defaults if necessary. |
| 468 | $call['module'] = isset($call['module']) ? $call['module'] : ''; |
| 469 | $call['uid'] = isset($call['uid']) ? $call['uid'] : 0; |
| 470 | $call['dispatch_time'] = isset($call['dispatch_time']) ? $call['dispatch_time'] : time(); |
| 471 | $call['vars'] = isset($call['vars']) ? $call['vars'] : array(); |
| 472 | $call['caller_id'] = isset($call['caller_id']) ? $call['caller_id'] : ''; |
| 473 | $call['max_retries'] = isset($call['max_retries']) ? $call['max_retries'] : 2; |
| 474 | $call['retry_time'] = isset($call['retry_time']) ? $call['retry_time'] : 60; |
| 475 | $call['wait_time'] = isset($call['wait_time']) ? $call['wait_time'] : 30; |
| 476 | $call['context'] = isset($call['context']) ? $call['context'] : 'drupal'; |
| 477 | $call['priority'] = isset($call['priority']) ? $call['priority'] : 1; |
| 478 | $call['call_status'] = isset($call['call_status']) ? $call['call_status']: 'dispatched'; |
| 479 | |
| 480 | return $call; |
| 481 | } |
| 482 | |
| 483 | /** |
| 484 | * Sends calls to the Asterisk server. |
| 485 | * |
| 486 | * @param $calls An array of calls, each elment of which is an associative array |
| 487 | * describing a call, based on the parameters listed in function asterisk_call. |
| 488 | */ |
| 489 | function asterisk_send_calls($calls) { |
| 490 | |
| 491 | // Get server data. |
| 492 | $server = _asterisk_instant_notification(); |
| 493 | |
| 494 | // Since we want playback files to be processed before callfiles, we set the |
| 495 | // order here. |
| 496 | $outgoing = array(); |
| 497 | $outgoing['playback_file'] = array(); |
| 498 | $outgoing['callfile'] = array(); |
| 499 | |
| 500 | foreach ($calls as $key => $call) { |
| 501 | |
| 502 | // Only allow calls that have both a caller and callee number. |
| 503 | if ($call['caller_number'] && $call['callee_number']) { |
| 504 | // Prepare the arguments for later insertion into the database. |
| 505 | $arguments[$key] = array($call['caller_number'], |
| 506 | $call['callee_number'], |
| 507 | $call['module'], |
| 508 | $call['uid'], |
| 509 | $call['dispatch_time'], |
| 510 | serialize($call['vars']), |
| 511 | $call['caller_id'], |
| 512 | $call['max_retries'], |
| 513 | $call['retry_time'], |
| 514 | $call['wait_time'], |
| 515 | $call['context'], |
| 516 | $call['priority'], |
| 517 | $call['call_status'], |
| 518 | time() |
| 519 | ); |
| 520 | |
| 521 | // calls marked dispatched are sent to the Asterisk server immediately, and only entered in the database |
| 522 | // if the XML-RPC call is successful. |
| 523 | if ($call['call_status'] == 'dispatched') { |
| 524 | $outgoing['callfile'][$key] = asterisk_create_call_file($call); |
| 525 | // The call has an uncached playback file associated with it--load it to the call array. |
| 526 | if (isset($call['playback_file'])) { |
| 527 | $outgoing['playback_file'][$key] = $call['playback_file']; |
| 528 | } |
| 529 | } |
| 530 | // While calls marked uncalled are entered into the db immediately. |
| 531 | else { |
| 532 | asterisk_add_call_to_db($arguments[$key]); |
| 533 | unset($arguments[$key]); |
| 534 | unset($calls[$key]); |
| 535 | } |
| 536 | } |
| 537 | } |
| 538 | |
| 539 | // Send the dispatched calls to the Asterisk server, and get back an array of completed call information. |
| 540 | // NOTE: A successfully completed call only means that the call was successfully queued to Asterisk's |
| 541 | // outgoing call spool. |
| 542 | $completed_calls = xmlrpc($server['url'], 'asterisk.send.NewCalls', $server['user'], $server['pass'], $outgoing); |
| 543 | |
| 544 | foreach ($calls as $key => $call) { |
| 545 | $message_args = array('%caller_number' => $call['caller_number'], '%callee_number' => $call['callee_number']); |
| 546 | // Check for server errors. |
| 547 | if (!isset($completed_calls['callfile'][$key]['error']) && !isset($completed_calls['playback_file'][$key]['error'])) { |
| 548 | // Mark the call as completed successfully if it was returned in the completed calls array, with an |
| 549 | // additional check for a successfully processed playback messagee if one was sent. |
| 550 | if (isset($completed_calls['callfile'][$key]) && (!isset($outgoing['playback_file'][$key]) || $completed_calls['playback_file'][$key])) { |
| 551 | asterisk_add_call_to_db($arguments[$key]); |
| 552 | watchdog('asterisk', 'Queued call to %callee_number, from %caller_number', $message_args, WATCHDOG_NOTICE); |
| 553 | drupal_set_message(t('Placed call to %callee_number, from %caller_number', $message_args)); |
| 554 | } |
| 555 | // Call did not complete successfully. |
| 556 | else { |
| 557 | watchdog('asterisk', 'Call to %callee_number, from %caller_number failed', $message_args, WATCHDOG_ERROR); |
| 558 | drupal_set_message(t('Call to %callee_number, from %caller_number failed', $message_args), 'error'); |
| 559 | } |
| 560 | } |
| 561 | else { |
| 562 | $type = isset($call['playback_file']) ? 'playback_file' : 'callfile'; |
| 563 | watchdog('asterisk', 'Call to %callee_number, from %caller_number failed: '. $completed_calls[$type][$key]['error'], $message_args, WATCHDOG_ERROR); |
| 564 | drupal_set_message(t('Call to %callee_number, from %caller_number failed: '. $completed_calls[$type][$key]['error'], $message_args), 'error'); |
| 565 | } |
| 566 | unset($arguments[$key]); |
| 567 | unset($calls[$key]); |
| 568 | } |
| 569 | } |
| 570 | |
| 571 | /** |
| 572 | * Call a number and play a message. The file to be played must be in the |
| 573 | * {files} table, and the file must be either in wav or mp3 format. |
| 574 | * When the call is dispatched this file is converted to an Asterisk compatible wav file. |
| 575 | * (8kHz mono PCM). Files are cached on the Asterisk server, matched by file ID, node ID, |
| 576 | * and filename. |
| 577 | * @param $fid |
| 578 | * The fid identifier for the file to be played back to the callee. |
| 579 | * @param $callee_number |
| 580 | * The number of the user being called (see asterisk_call()). |
| 581 | * @param $module |
| 582 | * Module making the call (see asterisk_call()). |
| 583 | * @param $uid |
| 584 | * uid of user making the call (see asterisk_call()). |
| 585 | * @param $dispatch_time |
| 586 | * Time that call should occur (see asterisk_call()). |
| 587 | * @param $playback_file |
| 588 | * A playback file to upload--necessary if the file is not already cached on the |
| 589 | * Asterisk server. |
| 590 | */ |
| 591 | function asterisk_playback_message($fid, $callee_number, $module = '', $uid = 0, $dispatch_time = NULL, $playback_file = NULL) { |
| 592 | $call = array(); |
| 593 | $call['caller_number'] = $callee_number; |
| 594 | $call['callee_number'] = 'playback'; |
| 595 | $call['module'] = $module; |
| 596 | $call['uid'] = $uid; |
| 597 | $call['dispatch_time'] = $dispatch_time; |
| 598 | $call['vars'] = array('drupal_fid' => $fid); |
| 599 | if (isset($playback_file)) { |
| 600 | $call['playback_file'] = $playback_file; |
| 601 | } |
| 602 | $calls[1] = asterisk_call($call); |
| 603 | asterisk_send_calls($calls); |
| 604 | } |
| 605 | |
| 606 | /** |
| 607 | * Call a number and record a message. |
| 608 | * @param $filename |
| 609 | * The desired filename of the future recording. |
| 610 | * @param $callee_number |
| 611 | * The number of the user being called (see asterisk_call()). |
| 612 | * @param $nid |
| 613 | * Identifier of the node to which the recorded message should be attached. |
| 614 | * @param $module |
| 615 | * Module making the call (see asterisk_call()). |
| 616 | * @param $uid |
| 617 | * uid of user making the call (see asterisk_call()). |
| 618 | * @param dispatch_time |
| 619 | * Time that call should occur (see asterisk_call()). |
| 620 | * @param $list |
| 621 | * Boolean which determines if the file will be listed in the node as soon as it's created. Default is FALSE. |
| 622 | */ |
| 623 | function asterisk_record_message($filename, $callee_number, $nid = 0, $module = '', $uid = 0, $dispatch_time = NULL, $list = 0) { |
| 624 | |
| 625 | // Get a file ID. |
| 626 | $fid = asterisk_get_file_id($uid); |
| 627 | |
| 628 | $call = array(); |
| 629 | $calls = array(); |
| 630 | $call['caller_number'] = $callee_number; |
| 631 | $call['callee_number'] = 'record'; |
| 632 | $call['module'] = $module; |
| 633 | $call['uid'] = $uid; |
| 634 | $call['dispatch_time'] = $dispatch_time; |
| 635 | $call['vars'] = array('drupal_fid' => $fid, 'drupal_nid' => $nid, 'drupal_filename' => $filename, 'drupal_list_file' => $list); |
| 636 | |
| 637 | $calls[1] = asterisk_call($call); |
| 638 | asterisk_send_calls($calls); |
| 639 | |
| 640 | $node = node_load($nid); |
| 641 | drupal_set_message(t('Your message will be uploaded to %title shortly after you hang up.', array('%title' => $node->title))); |
| 642 | } |
| 643 | |
| 644 | /** |
| 645 | * Gets a file ID for a file recording. |
| 646 | * |
| 647 | * @param $uid |
| 648 | * The user submitting the record request. |
| 649 | * @return |
| 650 | * The file ID. |
| 651 | */ |
| 652 | function asterisk_get_file_id($uid) { |
| 653 | // Enter a temporary file into the files table -- placeholder. |
| 654 | $query = "INSERT INTO {files} |
| 655 | (uid, filename, filepath, filemime, filesize, status, timestamp) |
| 656 | VALUES |
| 657 | (%d, '%s', '%s', '%s', %d, %d, %d)"; |
| 658 | |
| 659 | $args = array( |
| 660 | $uid, |
| 661 | '', |
| 662 | '', |
| 663 | '', |
| 664 | 0, |
| 665 | FILE_STATUS_TEMPORARY, |
| 666 | time(), |
| 667 | ); |
| 668 | |
| 669 | db_query($query, $args); |
| 670 | $fid = db_last_insert_id('files', 'fid'); |
| 671 | |
| 672 | return $fid; |
| 673 | } |
| 674 | |
| 675 | /** |
| 676 | * Use the generic call function to call given a user (the callee). The caller is made |
| 677 | * the callee so that the user can hear anything that the IVR might play |
| 678 | * @param $callee |
| 679 | * User object of the user to be called. |
| 680 | * @param $number |
| 681 | * Number that the callee user will be connected to. |
| 682 | * @param $module |
| 683 | * Module making the call (see asterisk_call()). |
| 684 | * @param $uid |
| 685 | * uid of user making the call (see asterisk_call()). |
| 686 | * @param dispatch_time |
| 687 | * Time that call should occur (see asterisk_call()). |
| 688 | */ |
| 689 | function asterisk_call_number($callee, $number, $module ='', $uid = 0, $dispatch_time = NULL, $call = array()) { |
| 690 | $calls = array(); |
| 691 | $call['caller_number'] = $callee->number; |
| 692 | $call['callee_number'] = $number; |
| 693 | $call['module'] = $module; |
| 694 | $call['uid'] = $uid; |
| 695 | $call['dispatch_time'] = $dispatch_time; |
| 696 | $calls[1] = asterisk_call($call); |
| 697 | asterisk_send_calls($calls); |
| 698 | } |
| 699 | |
| 700 | /** |
| 701 | * @} End of "defgroup Asterisk call API". |
| 702 | */ |
| 703 | |
| 704 | /** |
| 705 | * Adds a successful call or a successfully queued call to the call queue database table. |
| 706 | * |
| 707 | * @param $args An array of call data to enter into the database. |
| 708 | */ |
| 709 | function asterisk_add_call_to_db($args) { |
| 710 | $query = "INSERT INTO {asterisk_call_queue} |
| 711 | (caller_number, callee_number, module, uid, dispatch_time, vars, caller_id, max_retries, retry_time, wait_time, context, priority, call_status, queuetime) |
| 712 | VALUES |
| 713 | ('%s', '%s', '%s', %d, %d, '%s', '%s', %d, %d, %d, '%s', %d, '%s', %d) |
| 714 | "; |
| 715 | db_query($query, $args); |
| 716 | } |
| 717 | |
| 718 | /** |
| 719 | * Checks files for existence on the Asterisk server. |
| 720 | * |
| 721 | * @param $fids An array of file ID's to check (fid in the files table). |
| 722 | * |
| 723 | * @return An array of all file ID's that exist on the Asterisk server. |
| 724 | */ |
| 725 | function asterisk_validate_playback_files($fids) { |
| 726 | |
| 727 | $files_array = array(); |
| 728 | $return = array(); |
| 729 | $server = _asterisk_instant_notification(); |
| 730 | |
| 731 | // Prepare each file for checking on the server--we need to get the file name as it |
| 732 | // appears on the server to do that. |
| 733 | foreach ($fids as $key => $fid) { |
| 734 | $file = asterisk_get_file_info($fid); |
| 735 | $files_array['playback_file'][$key] = $file['server_file_name']; |
| 736 | } |
| 737 | |
| 738 | // Get the results from the server. |
| 739 | $result = xmlrpc($server['url'], 'asterisk.check.Files', $server['user'], $server['pass'], $files_array); |
| 740 | |
| 741 | // Build the array of found files. |
| 742 | foreach ($result['playback_file'] as $key => $value) { |
| 743 | $return[] = $fids[$key]; |
| 744 | } |
| 745 | |
| 746 | return $return; |
| 747 | } |
| 748 | |
| 749 | /** |
| 750 | * Validates the call for recording. |
| 751 | */ |
| 752 | function asterisk_record_form_validate($form, &$form_state) { |
| 753 | |
| 754 | // Check to make sure the current user has a valid callback number. |
| 755 | asterisk_user_has_number(); |
| 756 | |
| 757 | // Replace all characters that aren't numbers, letters, dashes, or underscores with underscores |
| 758 | $filename = preg_replace('/[^\d\w\-]/', '_', $form_state['values']['asterisk_record_file']); |
| 759 | form_set_value($form['asterisk_record']['asterisk_record_file'], $filename, $form_state); |
| 760 | } |
| 761 | |
| 762 | /** |
| 763 | * Submits the call for recording. |
| 764 | */ |
| 765 | function asterisk_record_form_submit($form, &$form_state) { |
| 766 | global $user; |
| 767 | |
| 768 | // This call is a bridged call with optional recording |
| 769 | if ($callee_number = format_number($form_state['values']['callee_number'])) { |
| 770 | // Get a file ID. |
| 771 | $fid = asterisk_get_file_id($uid); |
| 772 | $call['vars'] = array( |
| 773 | 'drupal_fid' => $fid, |
| 774 | 'drupal_nid' => $form_state['values']['asterisk_record_nid'], |
| 775 | 'drupal_filename' => $form_state['values']['asterisk_record_file'], |
| 776 | 'drupal_list_file' => $form_state['values']['asterisk_record_list_file'], |
| 777 | 'drupal_callee_number' => $callee_number, |
| 778 | ); |
| 779 | asterisk_call_number($user, 'bridge', 'asterisk', $user->uid, NULL, $call); |
| 780 | } |
| 781 | // This is a call just to the user. |
| 782 | else { |
| 783 | asterisk_record_message($form_state['values']['asterisk_record_file'], $user->number, $form_state['values']['asterisk_record_nid'], 'asterisk', $user->uid, NULL, $form_state['values']['asterisk_record_list_file']); |
| 784 | } |
| 785 | } |
| 786 | |
| 787 | function asterisk_check_messages($messages) { |
| 788 | |
| 789 | if (!($server = _asterisk_instant_notification())) { |
| 790 | return FALSE; |
| 791 | } |
| 792 | foreach ($messages as $message_key) { |
| 793 | $message = xmlrpc($server['url'], 'asterisk.get.Message', $server['user'], $server['pass'], $message_key); |
| 794 | asterisk_process_new_message($message); |
| 795 | } |
| 796 | |
| 797 | return TRUE; |
| 798 | } |
| 799 | |
| 800 | function asterisk_process_new_message($message) { |
| 801 | |
| 802 | switch ($message['type']) { |
| 803 | case 'recording': |
| 804 | _asterisk_save_file($message); |
| 805 | break; |
| 806 | } |
| 807 | } |
| 808 | |
| 809 | /** |
| 810 | * Saves an uploaded file to the files directory, and records it properly |
| 811 | * in the files tables. |
| 812 | */ |
| 813 | function _asterisk_save_file($file) { |
| 814 | |
| 815 | $node = node_load($file['nid']); |
| 816 | $file['vid'] = $node->vid ? $node->vid : 0; |
| 817 | $data = $file['bits']; |
| 818 | |
| 819 | $name = $file['filename'] ? $file['filename'] : t('unknown'); |
| 820 | |
| 821 | $t_args = array('%file' => $name, '%title' => $node->title); |
| 822 | |
| 823 | |
| 824 | if(!$data) { |
| 825 | watchdog('asterisk', 'File upload failed. No file sent for %file.', $t_args, WATCHDOG_ERROR); |
| 826 | return; |
| 827 | } |
| 828 | if (!$filepath = file_save_data($data, $name)) { |
| 829 | watchdog('asterisk', 'File upload failed. Error storing %file.', $t_args, WATCHDOG_ERROR); |
| 830 | return; |
| 831 | } |
| 832 | |
| 833 | $query = "UPDATE {files} SET filename = '%s', filepath = '%s', filemime = '%s', filesize = %d, status = %d, timestamp = %d WHERE fid = %d"; |
| 834 | |
| 835 | $args = array( |
| 836 | $name, |
| 837 | $filepath, |
| 838 | $file['filemime'], |
| 839 | $file['filesize'], |
| 840 | FILE_STATUS_PERMANENT, |
| 841 | time(), |
| 842 | $file['fid'], |
| 843 | ); |
| 844 | |
| 845 | db_query($query, $args); |
| 846 | |
| 847 | $query = "INSERT INTO {upload} |
| 848 | (fid, nid, vid, description, list) |
| 849 | VALUES |
| 850 | (%d, %d, %d, '%s', %d)"; |
| 851 | |
| 852 | $args = array($file['fid'], |
| 853 | $file['nid'], |
| 854 | $file['vid'], |
| 855 | $name, |
| 856 | (integer) $file['list'] |
| 857 | ); |
| 858 | |
| 859 | db_query($query, $args); |
| 860 | watchdog('asterisk', '%file uploaded successfully to %title.', $t_args); |
| 861 | } |
| 862 | |
| 863 | /** |
| 864 | * Generates file information about a file to be passed to the Asterisk server. |
| 865 | * |
| 866 | * @param $fid The file ID. |
| 867 | * @return An associative array of information about the file. |
| 868 | */ |
| 869 | function asterisk_get_file_info($fid) { |
| 870 | global $base_url; |
| 871 | |
| 872 | $nid = db_result(db_query('SELECT n.nid FROM {upload} u INNER JOIN {node} n ON n.nid = u.nid WHERE n.status = 1 AND n.vid = u.vid AND fid = %d', $fid)); |
| 873 | $node = node_load($nid); |
| 874 | |
| 875 | // Make sure the file is still active on the node. |
| 876 | if ($node) { |
| 877 | $file = (array) $node->files[$fid]; |
| 878 | |
| 879 | // more unique name for the file on the asterisk server |
| 880 | $file['server_file_name'] = $file['fid'] .'_'. $file['nid'] .'_'. $file['filename']; |
| 881 | |
| 882 | if (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC) { |
| 883 | $file['is_public'] = TRUE; |
| 884 | } |
| 885 | |
| 886 | // get rid of this variable--replaced with the channel variable below |
| 887 | unset($file['filename']); |
| 888 | |
| 889 | // We use the FILENAME variable in our dialplan. strip the file extension--Asterisk doesn't need it. |
| 890 | $filename_stripped_ext = substr($file['server_file_name'], 0, strrpos($file['server_file_name'], '.')); |
| 891 | $file['FILENAME'] = $filename_stripped_ext; |
| 892 | |
| 893 | return $file; |
| 894 | } |
| 895 | else { |
| 896 | return FALSE; |
| 897 | } |
| 898 | } |
| 899 | |
| 900 | /** |
| 901 | * Load the user's information |
| 902 | */ |
| 903 | function asterisk_user_load(&$user) { |
| 904 | $query = "SELECT * FROM {asterisk_users} WHERE uid = %d"; |
| 905 | if ($additions = db_fetch_object(db_query($query, $user->uid))) { |
| 906 | foreach ($additions as $key => $value) { |
| 907 | $user->$key = $value; |
| 908 | } |
| 909 | } |
| 910 | } |
| 911 | |
| 912 | /** |
| 913 | * Inserts the user's information |
| 914 | */ |
| 915 | function asterisk_user_insert(&$edit, &$user) { |
| 916 | // save the main details to the database |
| 917 | $query = "INSERT INTO {asterisk_users} (pin, number, uid) VALUES ('%s', '%s', %d)"; |
| 918 | db_query($query, $edit['asterisk_pin'], $edit['asterisk_number'], $user->uid); |
| 919 | |
| 920 | |
| 921 | /* Disabled for now... |
| 922 | |
| 923 | // create the user on the asterisk server |
| 924 | $vars = array('op' => 'create-user', 'user' => $user); |
| 925 | asterisk_call('system', 'system', 'asterisk', $user->uid, FALSE, $vars); |
| 926 | |
| 927 | */ |
| 928 | |
| 929 | $edit['asterisk_number'] = NULL; |
| 930 | $edit['asterisk_pin'] = NULL; |
| 931 | |
| 932 | } |
| 933 | |
| 934 | /** |
| 935 | * Updates the user's information |
| 936 | */ |
| 937 | function asterisk_user_update(&$edit, &$user) { |
| 938 | |
| 939 | // update the PIN and telephone number information |
| 940 | $query = "UPDATE {asterisk_users} SET pin = '%s', number = '%s' WHERE uid = %d"; |
| 941 | db_query($query, $edit['asterisk_pin'], $edit['asterisk_number'], $user->uid); |
| 942 | if (db_affected_rows() == 0) { |
| 943 | $query = "INSERT INTO {asterisk_users} (pin, number, uid) VALUES ('%s', '%s', %d)"; |
| 944 | db_query($query, $edit['asterisk_pin'], $edit['asterisk_number'], $user->uid); |
| 945 | } |
| 946 | |
| 947 | /* Disabled for now... |
| 948 | // update the user information on the asterisk server |
| 949 | $vars = array('op' => 'update-user', 'user' => $user); |
| 950 | asterisk_call('system', 'system', 'asterisk', $user->uid, FALSE, $vars); |
| 951 | $edit['direct_leap_account_number'] = NULL; |
| 952 | */ |
| 953 | |
| 954 | $edit['asterisk_number'] = NULL; |
| 955 | $edit['asterisk_pin'] = NULL; |
| 956 | } |
| 957 | |
| 958 | /** |
| 959 | * Deletes the user's information |
| 960 | */ |
| 961 | function asterisk_user_delete(&$edit, &$user) { |
| 962 | |
| 963 | // delete the user's info from our database |
| 964 | db_query("DELETE FROM {asterisk_users} WHERE uid = %d", $user->uid); |
| 965 | |
| 966 | /* Disabled for now... |
| 967 | // remove the user from our asterisk server as well |
| 968 | $vars = array('op' => 'delete-user', 'user' => $user); |
| 969 | asterisk_call('system', 'system', 'asterisk', $user->uid, FALSE, $vars); |
| 970 | */ |
| 971 | } |
| 972 | |
| 973 | /** |
| 974 | * Generates additions for the user edit form |
| 975 | */ |
| 976 | function asterisk_user_form($edit, $user) { |
| 977 | |
| 978 | $form = array(); |
| 979 | |
| 980 | // User asterisk account info |
| 981 | $form['asterisk_telephone_information'] = array( |
| 982 | '#type' => 'fieldset', |
| 983 | '#title' => t('Telephone information'), |
| 984 | '#collapsible' => TRUE, |
| 985 | '#weight' => 1, |
| 986 | ); |
| 987 | $form['asterisk_telephone_information']['asterisk_number'] = array( |
| 988 | '#type' => 'textfield', |
| 989 | '#title' => t('Phone number'), |
| 990 | '#default_value' => isset($user->number) ?$user->number : '', |
| 991 | '#maxlength' => 255, |
| 992 | '#description' => variable_get('asterisk_phone_number_message', t('Your phone number of course. You must put your country code, eg 1 for USA. An example would be 13213210123 for a US (NANPA) number')), |
| 993 | ); |
| 994 | $form['asterisk_telephone_information']['asterisk_pin'] = array( |
| 995 | '#type' => 'textfield', |
| 996 | '#title' => t('Telephone PIN'), |
| 997 | '#default_value' => isset($user->pin) ? $user->pin : '', |
| 998 | '#size' => 30, |
| 999 | '#maxlength' => 30, |
| 1000 | '#description' => t('This is your password for telephony features. It should consist of just digits (eg 1542). If you are going to connect your softphone or hardphone to our asterisk servers, this will be the password. Additionally, this PIN will be used to access your voicemail.'), |
| 1001 | ); |
| 1002 | |
| 1003 | return $form; |
| 1004 | } |
| 1005 | |
| 1006 | /** |
| 1007 | * Helper function that checks if a user object is the same as that of the user |
| 1008 | * currently viewing the page. |
| 1009 | */ |
| 1010 | function _asterisk_is_same_user($callee) { |
| 1011 | global $user; |
| 1012 | if ($callee->uid == $user->uid) { |
| 1013 | return TRUE; |
| 1014 | } |
| 1015 | else { |
| 1016 | return FALSE; |
| 1017 | } |
| 1018 | } |
| 1019 | |
| 1020 | function asterisk_audio_file_block() { |
| 1021 | $query = "SELECT DISTINCT f.fid, f.filename FROM {files} f INNER JOIN {upload} u ON f.fid = u.fid INNER JOIN {node} n ON n.nid = u.nid WHERE n.status = 1 AND n.vid = u.vid AND (f.filemime LIKE '%audio%wav%' OR f.filemime LIKE '%audio%mpeg%') AND u.list = 1 ORDER BY f.fid DESC"; |
| 1022 | $result = db_query_range($query, 0, variable_get('asterisk_audio_block_items', 5)); |
| 1023 | |
| 1024 | $links = array(); |
| 1025 | while ($file = db_fetch_object($result)) { |
| 1026 | $links[] = l($file->filename, 'asterisk/play/'. $file->fid, |
| 1027 | array('title' => t('listen to this file by phone'), 'query' => drupal_get_destination())); |
| 1028 | } |
| 1029 | |
| 1030 | $output = ''; |
| 1031 | if (!empty($links)) { |
| 1032 | $output .= '<strong>'. t('Click to listen by phone:') .'</strong>'; |
| 1033 | $output .= theme('item_list', $links); |
| 1034 | } |
| 1035 | |
| 1036 | return $output; |
| 1037 | } |
| 1038 | |
| 1039 | function asterisk_make_call_block_form(&$form_state) { |
| 1040 | $form = array(); |
| 1041 | $form['asterisk_number'] = array('#type' => 'textfield', |
| 1042 | '#title' => t('Number'), |
| 1043 | '#size' => 15, |
| 1044 | '#maxlength' => 64, |
| 1045 | '#description' => variable_get('asterisk_call_number_help', 'You can call Free World Dialup numbers as fwd://username'), |
| 1046 | ); |
| 1047 | $form['submit'] = array('#type' => 'submit', |
| 1048 | '#value' => t('Call now'), |
| 1049 | ); |
| 1050 | return $form; |
| 1051 | } |
| 1052 | |
| 1053 | /** |
| 1054 | * Page callback |
| 1055 | */ |
| 1056 | function asterisk_page() { |
| 1057 | global $user; |
| 1058 | |
| 1059 | // Check to make sure the current user has a valid callback number. |
| 1060 | asterisk_user_has_number(); |
| 1061 | |
| 1062 | $op = arg(1); |
| 1063 | switch ($op) { |
| 1064 | case 'calluser': |
| 1065 | asterisk_call_user_page($user); |
| 1066 | break; |
| 1067 | case 'callme': |
| 1068 | asterisk_call_number($user, 'demo', 'asterisk', $user->uid); |
| 1069 | break; |
| 1070 | case 'play': |
| 1071 | $fid = explode('?', arg(2)); |
| 1072 | $fid = $fid[0]; |
| 1073 | // Validate that the user can listen to this file. |
| 1074 | $nid = db_result(db_query('SELECT nid FROM {upload} WHERE fid = %d', $fid)); |
| 1075 | if (!node_access('view', node_load($nid))) { |
| 1076 | return drupal_access_denied();; |
| 1077 | } |
| 1078 | // Check for existence of file on Asterisk server. |
| 1079 | $file_on_server = asterisk_validate_playback_files(array($fid)); |
| 1080 | // File is not on server, so generate a playback_file element. |
| 1081 | if (!in_array($fid, $file_on_server)) { |
| 1082 | $file = asterisk_get_file_info($fid); |
| 1083 | $playback_file = asterisk_generate_playback_file($file); |
| 1084 | } |
| 1085 | $uids = array($user->uid); |
| 1086 | foreach ($uids as $uid) { |
| 1087 | $u = user_load(array('uid' => $uid)); |
| 1088 | if ($u->number) { |
| 1089 | // Only send the playfile with the first call--saves bandwidth. |
| 1090 | if (isset($playback_file)) { |
| 1091 | asterisk_playback_message($fid, $u->number, 'asterisk', $user->uid, NULL, $playback_file); |
| 1092 | unset($playback_file); |
| 1093 | } |
| 1094 | else { |
| 1095 | asterisk_playback_message($fid, $u->number, 'asterisk', $user->uid); |
| 1096 | } |
| 1097 | } |
| 1098 | } |
| 1099 | break; |
| 1100 | } |
| 1101 | |
| 1102 | drupal_goto(); |
| 1103 | } |
| 1104 | |
| 1105 | /** |
| 1106 | * Validates that the current user has a callback number, and displays a warning message |
| 1107 | * with an edit link if not. |
| 1108 | */ |
| 1109 | function asterisk_user_has_number() { |
| 1110 | global $user; |
| 1111 | |
| 1112 | asterisk_user_load($user); |
| 1113 | |
| 1114 | // We don't have a phone number for this user--send them an appropriate message. |
| 1115 | if ($user->number == '') { |
| 1116 | drupal_set_message(t('You need to configure your phone number in the \'Telephone information\' section below so that we can connect the call to you'), 'error'); |
| 1117 | drupal_goto('user/'. $user->uid .'/edit'); |
| 1118 | } |
| 1119 | } |
| 1120 | |
| 1121 | function asterisk_generate_playback_file($file) { |
| 1122 | |
| 1123 | $return = NULL; |
| 1124 | |
| 1125 | if (file_exists($file['filepath'])) { |
| 1126 | if ($fh = fopen($file['filepath'], 'r')) { |
| 1127 | $playback_file['bits'] = ''; |
| 1128 | while (!feof($fh)) { |
| 1129 | $playback_file['bits'] .= fread($fh, 8192); |
| 1130 | } |
| 1131 | fclose($fh); |
| 1132 | |
| 1133 | $return['bits'] = xmlrpc_base64($playback_file['bits']); |
| 1134 | $return['filemime'] = $file['filemime']; |
| 1135 | $return['server_file_name'] = $file['server_file_name']; |
| 1136 | } |
| 1137 | } |
| 1138 | |
| 1139 | return $return; |
| 1140 | } |
| 1141 | |
| 1142 | /** |
| 1143 | * Validates the number in the submitted call block. |
| 1144 | */ |
| 1145 | function asterisk_make_call_block_form_validate($form, &$form_state) { |
| 1146 | |
| 1147 | // Check that user has correct permissions |
| 1148 | if (!user_access('make calls')) { |
| 1149 | form_set_error('asterisk_number', t('You do not have the required permissions to make a call.')); |
| 1150 | } |
| 1151 | else { |
| 1152 | // Check to make sure the current user has a valid callback number. |
| 1153 | asterisk_user_has_number(); |
| 1154 | |
| 1155 | // Check to make sure the user entered a number in the call block. |
| 1156 | if ($form_state['values']['asterisk_number'] == '') { |
| 1157 | form_set_error('asterisk_number', t('You need to supply a valid number')); |
| 1158 | } |
| 1159 | } |
| 1160 | } |
| 1161 | |
| 1162 | /** |
| 1163 | * Calls the number in the submitted call block. |
| 1164 | * |
| 1165 | * @param $form_id The form ID. |
| 1166 | * @param $form_values An array of submitted form values. |
| 1167 | */ |
| 1168 | function asterisk_make_call_block_form_submit($form, &$form_state) { |
| 1169 | global $user; |
| 1170 | |
| 1171 | $call['vars'] = array('drupal_callee_number' => $form_state['values']['asterisk_number']); |
| 1172 | asterisk_call_number($user, 'bridge', 'asterisk', $user->uid, NULL, $call); |
| 1173 | } |
| 1174 | |
| 1175 | /** |
| 1176 | * Processes the call user callback |
| 1177 | */ |
| 1178 | function asterisk_call_user_page($user) { |
| 1179 | |
| 1180 | $callee = user_load(array('uid' => arg(2))); |
| 1181 | |
| 1182 | if ($user->uid == $callee->uid) { |
| 1183 | drupal_set_message(t('You cannot call yourself')); |
| 1184 | } |
| 1185 | elseif ($callee->number == '') { |
| 1186 | drupal_set_message(t('You cannot call this user--their phone number has not been configured.')); |
| 1187 | } |
| 1188 | else { |
| 1189 | $call['vars'] = array('drupal_callee_number' => $callee->number); |
| 1190 | return asterisk_call_number($user, 'bridge', 'asterisk', $user->uid, NULL, $call); |
| 1191 | } |
| 1192 | |
| 1193 | return FALSE; |
| 1194 | } |
| 1195 | |
| 1196 | function asterisk_call_log($account = NULL) { |
| 1197 | $user_log = is_object($account) && isset($account->uid); |
| 1198 | |
| 1199 | $sql = "SELECT a.*, u.name FROM {asterisk_call_queue} a INNER JOIN {users} u ON u.uid = a.uid WHERE caller_number |
| 1200 | != 'system' AND callee_number != 'system'"; |
| 1201 | |
| 1202 | $header = array( |
| 1203 | array('data' => t('Time'), 'field' => 'dispatch_time', 'sort' => 'desc'), |
| 1204 | array('data' => t('Caller'), 'field' => 'caller_number'), |
| 1205 | array('data' => t('Callee'), 'field' => 'callee_number') |
| 1206 | ); |
| 1207 | |
| 1208 | if ($user_log) { |
| 1209 | $sql .= " AND u.uid = %d"; |
| 1210 | $sql .= tablesort_sql($header);< |