function callrecording_get_config($engine) { global $ext; switch ($engine) { case 'asterisk': $context = 'ext-callrecording'; foreach (callrecording_list() as $row) { $ext->add($context, $row['callrecording_id'], '', new ext_noop_trace('Call Recording: [' . $row['callrecording_mode'] . '] Event')); switch ($row['callrecording_mode']) { case 'force': $ext->add($context, $row['callrecording_id'], '', new ext_gosub('1', 's', 'sub-record-check', 'generic,${FROM_DID},always')); break; case 'delayed': $ext->add($context, $row['callrecording_id'], '', new ext_set('__REC_POLICY_MODE', 'always')); break; case 'never': $ext->add($context, $row['callrecording_id'], '', new ext_gosub('1', 's', 'sub-record-check', 'generic,${FROM_DID},never')); $ext->add($context, $row['callrecording_id'], '', new ext_set('__REC_POLICY_MODE', 'never')); break; default: // allowed $ext->add($context, $row['callrecording_id'], '', new ext_execif('$["${REC_POLICY_MODE}"="never"]', 'Set', '__REC_POLICY_MODE=')); break; } $ext->add($context, $row['callrecording_id'], '', new ext_goto($row['dest'])); } /* * This used to abort and remove a recording, but is no longer needed. It's * kept around as a null stub in case other modules call it. */ $context = 'sub-record-cancel'; $exten = 's'; $ext->add($context, $exten, '', new ext_return('')); /* ; ARG1: type ; exten, out, rg, q, conf ; ARG2: called_exten ; ARG3: action (if we know it) ; force (== always), yes, dontcare, no, never ; */ $context = 'sub-record-check'; $exten = 's'; $ext->add($context, $exten, '', new ext_gotoif('$[${LEN(${FROMEXTEN})}]', 'initialized')); $ext->add($context, $exten, '', new ext_set('__REC_STATUS', 'INITIALIZED')); $ext->add($context, $exten, '', new ext_set('NOW', '${EPOCH}')); $ext->add($context, $exten, '', new ext_set('__DAY', '${STRFTIME(${NOW},,%d)}')); $ext->add($context, $exten, '', new ext_set('__MONTH', '${STRFTIME(${NOW},,%m)}')); $ext->add($context, $exten, '', new ext_set('__YEAR', '${STRFTIME(${NOW},,%Y)}')); $ext->add($context, $exten, '', new ext_set('__TIMESTR', '${YEAR}${MONTH}${DAY}-${STRFTIME(${NOW},,%H%M%S)}')); $ext->add($context, $exten, '', new ext_set('__FROMEXTEN', '${IF($[${LEN(${AMPUSER})}]?${AMPUSER}:${IF($[${LEN(${REALCALLERIDNUM})}]?${REALCALLERIDNUM}:unknown)})}')); // MON_FMT is the format that MixMon knows about. If we're set to 'wav49', MixMonitor actually saves the // filename as 'WAV', not, as expected, 'wav49' - see https://issues.asterisk.org/jira/browse/ASTERISK-24798 // So, if we've been given wav49, change it to WAV. Note, this breaks on non-case-sensitive filesystems (such // as anything windows based), so don't use GSM encoded wavs in that case. $ext->add($context, $exten, '', new ext_set('__MON_FMT', '${IF($["${MIXMON_FORMAT}"="wav49"]?WAV:${MIXMON_FORMAT})}')); $ext->add($context, $exten, 'initialized', new ext_noop('Recordings initialized')); $ext->add($context, $exten, '', new ext_execif('$[!${LEN(${ARG3})}]', 'Set', 'ARG3=dontcare')); // Make sure we have a recording request. // Backup our current setting, just in case we need to roll back to it. $ext->add($context, $exten, '', new ext_set('REC_POLICY_MODE_SAVE', '${REC_POLICY_MODE}')); // When we're internally transferred, we are NEVER recording. $ext->add($context, $exten, '', new ext_execif('$["${BLINDTRANSFER}${ATTENDEDTRANSFER}" != ""]', 'Set', 'REC_STATUS=NO')); // If we weren't given a type, error. This is a bug. $ext->add($context, $exten, 'next', new ext_gotoif('$[${LEN(${ARG1})}]', 'checkaction')); $ext->add($context, $exten, 'recorderror', new ext_playback('something-terribly-wrong,error')); $ext->add($context, $exten, '', new ext_hangup()); // If we don't have a current mode, and we were explicitly given a command, we can set our current mode // to that. This is what we CURRENTLY think we should be doing. This may change if it's an exten. // .. Disabled. Legacy code, should be unneeded now. // $ext->add($context, $exten, 'checkaction', new ext_execif('$["${REC_POLICY_MODE}"="" & "${ARG3}"!=""]','Set','__REC_POLICY_MODE=${TOUPPER(${ARG3})}')); // Now jump to the dialplan handler. If it doesn't exist, do the generic test (rg, force, q use these). $ext->add($context, $exten, 'checkaction', new ext_gotoif('$[${DIALPLAN_EXISTS(' . $context . ',${ARG1})}]', $context . ',${ARG1},1')); // Generic check $ext->add($context, $exten, '', new ext_noop('Generic ${ARG1} Recording Check - ${FROMEXTEN} ${ARG2}')); $ext->add($context, $exten, '', new ext_gosub('1', 'recordcheck', false, '${ARG3},${ARG1},${ARG2}')); $ext->add($context, $exten, '', new ext_return('')); // Check to see what should be done, based on the request type. // ARG1 = Policy. // ARG2 = Name ('q', 'exten', etc) // ARG3 = Destination $exten = 'recordcheck'; $ext->add($context, $exten, '', new ext_noop('Starting recording check against ${ARG1}')); $ext->add($context, $exten, '', new ext_goto('${ARG1}')); // Don't care - just return, nothing's changed. $ext->add($context, $exten, 'dontcare', new ext_return('')); // ALWAYS: Extensions used 'Always' and 'Never'. Alias 'Always' to 'Force' $ext->add($context, $exten, 'always', new ext_noop('Detected legacy "always" entry. Mapping to "force"')); // FORCE: Always start recording, if you're not already. $ext->add($context, $exten, 'force', new ext_set('__REC_POLICY_MODE', 'FORCE')); $ext->add($context, $exten, '', new ext_gotoif('$["${REC_STATUS}"!="RECORDING"]', 'startrec')); $ext->add($context, $exten, '', new ext_return('')); $ext->add($context, $exten, 'delayed', new ext_noop('Detected legacy "delayed" entry. Mapping to "yes"')); // YES: Start recording if we haven't been told otherwise. $ext->add($context, $exten, 'yes', new ext_execif('$["${REC_POLICY_MODE}" = "NEVER" | "${REC_POLICY_MODE}" = "NO" | "${REC_STATUS}" = "RECORDING"]', 'Return')); $ext->add($context, $exten, '', new ext_set('__REC_POLICY_MODE', 'YES')); $ext->add($context, $exten, '', new ext_goto('startrec')); // NO: Don't record this. This won't STOP a recording that's already happening though. $ext->add($context, $exten, 'no', new ext_set('__REC_POLICY_MODE', 'NO')); $ext->add($context, $exten, '', new ext_return('')); // NEVER: Don't record this call, and stop recording if we are. $ext->add($context, $exten, 'never', new ext_set('__REC_POLICY_MODE', 'NEVER')); $ext->add($context, $exten, '', new ext_goto('stoprec')); // Start recording if requested $ext->add($context, $exten, 'startrec', new ext_noop('Starting recording: ${ARG2}, ${ARG3}')); $ext->add($context, $exten, '', new ext_set('AUDIOHOOK_INHERIT(MixMonitor)', 'yes')); $ext->add($context, $exten, '', new ext_set('__CALLFILENAME', '${ARG2}-${ARG3}-${FROMEXTEN}-${TIMESTR}-${UNIQUEID}')); $ext->add($context, $exten, '', new ext_mixmonitor('${MIXMON_DIR}${YEAR}/${MONTH}/${DAY}/${CALLFILENAME}.${MON_FMT}', 'ai(LOCAL_MIXMON_ID)', '${MIXMON_POST}')); $ext->add($context, $exten, '', new ext_set('__MIXMON_ID', '${LOCAL_MIXMON_ID}')); $ext->add($context, $exten, '', new ext_set('__RECORD_ID', '${CHANNEL(name)}')); $ext->add($context, $exten, '', new ext_set('__REC_STATUS', 'RECORDING')); $ext->add($context, $exten, '', new ext_set('CDR(recordingfile)', '${CALLFILENAME}.${MON_FMT}')); $ext->add($context, $exten, '', new ext_return('')); // Stop recording if requested. $ext->add($context, $exten, 'stoprec', new ext_noop('Stopping recording: ${ARG2}, ${ARG3}')); $ext->add($context, $exten, '', new ext_set('__REC_STATUS', 'STOPPED')); // See https://issues.asterisk.org/jira/browse/ASTERISK-24527 $ext->add($context, $exten, '', new ext_system(FreePBX::Config()->get('ASTVARLIBDIR') . '/bin/stoprecording.php "${CHANNEL(name)}"')); $ext->add($context, $exten, '', new ext_return('')); // RECORDING POLICY LOGIC HERE // // OUTBOUND ROUTES $exten = 'out'; $ext->add($context, $exten, '', new ext_noop('Outbound Recording Check from ${FROMEXTEN} to ${ARG2}')); // The Extension is first in the chain. $ext->add($context, $exten, '', new ext_set('RECMODE', '${DB(AMPUSER/${FROMEXTEN}/recording/out/external)}')); // If the exten is blank or DONTCARE, then we use the route. $ext->add($context, $exten, '', new ext_execif('$[!${LEN(${RECMODE})} | "${RECMODE}" = "dontcare"]', 'Goto', 'routewins')); // If the route is FORCE or NEVER, then we use the route. $ext->add($context, $exten, '', new ext_execif('$["${ARG3}" = "never" | "${ARG3}" = "force"]', 'Goto', 'routewins')); // Neither of those, so we use exten's setting. $ext->add($context, $exten, 'extenwins', new ext_gosub('1', 'recordcheck', false, '${RECMODE},out,${ARG2}')); $ext->add($context, $exten, '', new ext_return('')); // Route wins $ext->add($context, $exten, 'routewins', new ext_gosub('1', 'recordcheck', false, '${ARG3},out,${ARG2}')); $ext->add($context, $exten, '', new ext_return('')); // INBOUND ROUTES $exten = 'in'; $ext->add($context, $exten, '', new ext_noop('Inbound Recording Check to ${ARG2}')); $ext->add($context, $exten, '', new ext_set('FROMEXTEN', 'unknown')); $ext->add($context, $exten, '', new ext_execif('$[${LEN(${CALLERID(num)})}]', 'Set', 'FROMEXTEN=${CALLERID(num)}')); $ext->add($context, $exten, '', new ext_gosub('1', 'recordcheck', false, '${ARG3},in,${ARG2}')); $ext->add($context, $exten, '', new ext_return('')); // CALLS BETWEEN EXTENSIONS $exten = 'exten'; $ext->add($context, $exten, '', new ext_noop('Exten Recording Check between ${FROMEXTEN} and ${ARG2}')); $ext->add($context, $exten, '', new ext_set('CALLTYPE', '${IF($[${LEN(${FROM_DID})}]?external:internal)}')); $ext->add($context, $exten, '', new ext_execif('${LEN(${CALLTYPE_OVERRIDE})}', 'Set', 'CALLTYPE=${CALLTYPE_OVERRIDE}')); // Queues use this to make sure a call is tagged as external $ext->add($context, $exten, '', new ext_set('CALLEE', '${DB(AMPUSER/${ARG2}/recording/in/${CALLTYPE})}')); // Make sure CALLEE isn't empty. Bad astdb entry? $ext->add($context, $exten, '', new ext_execif('$[!${LEN(${CALLEE})}]', 'Set', 'CALLEE=dontcare')); // Is it an external call? It's not going to be caller. $ext->add($context, $exten, '', new ext_gotoif('$["${CALLTYPE}"="external"]', 'callee')); // Does the callee care about it? If not, we let the caller choose. $ext->add($context, $exten, '', new ext_gotoif('$["${CALLEE}"="dontcare"]', 'caller')); // It does. We may have a priority battle on our hands. $ext->add($context, $exten, '', new ext_execif('$[${LEN(${DB(AMPUSER/${FROMEXTEN}/recording/priority)})}]', 'Set', 'CALLER_PRI=${DB(AMPUSER/${FROMEXTEN}/recording/priority)}', 'Set', 'CALLER_PRI=0')); $ext->add($context, $exten, '', new ext_execif('$[${LEN(${DB(AMPUSER/${ARG2}/recording/priority)})}]', 'Set', 'CALLEE_PRI=${DB(AMPUSER/${ARG2}/recording/priority)}', 'Set', 'CALLEE_PRI=0')); // Who wins? $ext->add($context, $exten, '', new ext_gotoif('$["${CALLER_PRI}"="${CALLEE_PRI}"]', '${REC_POLICY}', '${IF($[${CALLER_PRI}>${CALLEE_PRI}]?caller:callee)}')); // Recpient of the call wins. We've already sanity checked them above, so we can use the CALLEE var. $ext->add($context, $exten, 'callee', new ext_gosub('1', 'recordcheck', false, '${CALLEE},${CALLTYPE},${ARG2}')); $ext->add($context, $exten, '', new ext_return('')); // Originator of the call wins. Always out/internal. $ext->add($context, $exten, 'caller', new ext_set('RECMODE', '${DB(AMPUSER/${FROMEXTEN}/recording/out/internal)}')); $ext->add($context, $exten, '', new ext_execif('$[!${LEN(${RECMODE})}]', 'Set', 'RECMODE=dontcare')); // If we don't care, then the callee gets to pick. $ext->add($context, $exten, '', new ext_execif('$["${RECMODE}"="dontcare"]', 'Set', 'RECMODE=${CALLEE}')); $ext->add($context, $exten, '', new ext_gosub('1', 'recordcheck', false, '${RECMODE},${CALLTYPE},${ARG2}')); $ext->add($context, $exten, '', new ext_return('')); // For confernecing we will set the variables (since the actual meetme does the recording) in case an option were to exist to do on-demand recording // of the conference which doesn't currenly seem like it is supported but might. // $exten = 'conf'; $ext->add($context, $exten, '', new ext_noop('Conference Recording Check ${FROMEXTEN} to ${ARG2}')); $ext->add($context, $exten, '', new ext_gosub('1', 'recconf', false, '${ARG2},${ARG2},${ARG3}')); $ext->add($context, $exten, '', new ext_return('')); $exten = 'page'; $ext->add($context, $exten, '', new ext_noop('Paging Recording Check ${FROMEXTEN} to ${ARG2}')); $ext->add($context, $exten, '', new ext_gosubif('$["${REC_POLICY_MODE}"="always"]', 'recconf,1', false, '${ARG2},${FROMEXTEN},${ARG3}')); $ext->add($context, $exten, '', new ext_return('')); $exten = 'recconf'; $ext->add($context, $exten, '', new ext_noop('Setting up recording: ${ARG1}, ${ARG2}, ${ARG3}')); if (FreePBX::Config()->get('ASTCONFAPP')) { $ext->add($context, $exten, '', new ext_set('__CALLFILENAME', '${IF($[${CONFBRIDGE_INFO(parties,${ARG2})}]?${DB(RECCONF/${ARG2})}:${ARG1}-${ARG2}-${ARG3}-${TIMESTR}-${UNIQUEID})}')); $ext->add($context, $exten, '', new ext_execif('$[!${CONFBRIDGE_INFO(parties,${ARG2})}]', 'Set', 'DB(RECCONF/${ARG2})=${CALLFILENAME}')); $ext->add($context, $exten, '', new ext_set('CONFBRIDGE(bridge,record_file)', '${MIXMON_DIR}${YEAR}/${MONTH}/${DAY}/${CALLFILENAME}.${MON_FMT}')); } else { // Conferencing must set the path to MIXMON_DIR explicitly since unlike other parts of Asterisk // Meetme does not default to the defined monitor directory. // $ext->add($context, $exten, '', new ext_set('__CALLFILENAME', '${IF($[${MEETME_INFO(parties,${ARG2})}]?${DB(RECCONF/${ARG2})}:${ARG1}-${ARG2}-${ARG3}-${TIMESTR}-${UNIQUEID})}')); $ext->add($context, $exten, '', new ext_execif('$[!${MEETME_INFO(parties,${ARG2})}]', 'Set', 'DB(RECCONF/${ARG2})=${CALLFILENAME}')); $ext->add($context, $exten, '', new ext_set('MEETME_RECORDINGFILE', '${IF($[${LEN(${MIXMON_DIR})}]?${MIXMON_DIR}:${ASTSPOOLDIR}/monitor/)}${YEAR}/${MONTH}/${DAY}/${CALLFILENAME}')); $ext->add($context, $exten, '', new ext_set('MEETME_RECORDINGFORMAT', '${MON_FMT}')); } $ext->add($context, $exten, '', new ext_execif('$["${ARG3}"!="always"]', 'Return')); if (FreePBX::Config()->get('ASTCONFAPP') == 'app_confbridge') { $ext->add($context, $exten, '', new ext_set('CONFBRIDGE(bridge,record_conference)', 'yes')); } $ext->add($context, $exten, '', new ext_set('__REC_STATUS', 'RECORDING')); $ext->add($context, $exten, '', new ext_set('CDR(recordingfile)', '${CALLFILENAME}.${MON_FMT}')); $ext->add($context, $exten, '', new ext_return('')); /* Queue Recording Section */ $exten = 'recq'; $ext->add($context, $exten, '', new ext_noop('Setting up recording: ${ARG1}, ${ARG2}, ${ARG3}')); $ext->add($context, $exten, '', new ext_set('AUDIOHOOK_INHERIT(MixMonitor)', 'yes')); $ext->add($context, $exten, '', new ext_set('MONITOR_FILENAME', '${MIXMON_DIR}${YEAR}/${MONTH}/${DAY}/${CALLFILENAME}')); $ext->add($context, $exten, '', new ext_mixmonitor('${MONITOR_FILENAME}.${MON_FMT}', '${MONITOR_OPTIONS}', '${MIXMON_POST}')); $ext->add($context, $exten, '', new ext_set('__REC_STATUS', 'RECORDING')); $ext->add($context, $exten, '', new ext_set('CDR(recordingfile)', '${CALLFILENAME}.${MON_FMT}')); $ext->add($context, $exten, '', new ext_return('')); /* Picked up parked call */ $exten = 'parking'; $ext->add($context, $exten, '', new ext_noop('User ${ARG2} picked up a parked call')); $ext->add($context, $exten, '', new ext_set('USER', '${ARG2}')); $ext->add($context, $exten, '', new ext_execif('$[!${LEN(${ARG2})}]', 'Set', 'USER=unknown')); $ext->add($context, $exten, '', new ext_set('RECMODE', '${DB(AMPUSER/${ARG2}/recording/out/internal)}')); $ext->add($context, $exten, '', new ext_execif('$[!${LEN(${RECMODE})}]', 'Set', 'RECMODE=dontcare')); // Make sure we have a recording request. $ext->add($context, $exten, '', new ext_gosub('1', 'recordcheck', false, '${RECMODE},parked,${USER}')); $ext->add($context, $exten, '', new ext_return('')); /* macro-one-touch-record */ $context = 'macro-one-touch-record'; $exten = 's'; $ext->add($context, $exten, '', new ext_set('ONETOUCH_REC_SCRIPT_STATUS', '')); $ext->add($context, $exten, '', new ext_system(FreePBX::Config()->get('ASTVARLIBDIR') . '/bin/one_touch_record.php "${CHANNEL(name)}"')); $ext->add($context, $exten, '', new ext_noop('ONETOUCH_REC_SCRIPT_STATUS: [${ONETOUCH_REC_SCRIPT_STATUS}]')); $ext->add($context, $exten, '', new ext_noop_trace('REC_STATUS: [${REC_STATUS}]')); $ext->add($context, $exten, '', new ext_noop_trace('ONETOUCH_RECFILE: [${ONETOUCH_RECFILE}] CDR(recordingfile): [${CDR(recordingfile)}]')); $ext->add($context, $exten, '', new ext_execif('$["${REC_STATUS}"="RECORDING"]', 'Playback', 'beep')); $ext->add($context, $exten, '', new ext_execif('$["${REC_STATUS}"="STOPPED"]', 'Playback', 'beep&beep')); $ext->add($context, $exten, '', new ext_execif('$["${ONETOUCH_REC_SCRIPT_STATUS:0:6}"="DENIED"]', 'Playback', 'access-denied')); $ext->add($context, $exten, '', new ext_macroexit()); } }
<?php // License for all code of this FreePBX module can be found in the license file inside the module directory // Copyright 2015 Sangoma Technologies. foreach (callrecording_list() as $row) { $arows .= '<tr><td>'; $arows .= $row['description']; $arows .= '</td>'; $arows .= '<td>'; $arows .= '<a href="?display=callrecording&view=form&extdisplay=' . $row['callrecording_id'] . '"><i class="fa fa-edit"></i></a>'; $arows .= ' '; $arows .= '<a href="config.php?display=callrecording&callrecording_id=' . $row['callrecording_id'] . '&action=delete"><i class="fa fa-trash"></i></a>'; $arows .= '</td></tr>'; } ?> <div id="toolbar-all"> <a href="config.php?display=callrecording&view=form" class="btn btn-default"><i class="fa fa-plus"></i> <?php echo _("Add Call Recording"); ?> </a> </div> <table data-toggle="table" data-toolbar="#toolbar-all" data-pagination="true" data-search="true" class="table table-striped"> <thead> <tr> <th><?php echo _("Description"); ?> </th> <th><?php echo _("Actions"); ?>