50da59306952a02f0fe1c5d5f39c001d861e2bea
[asterisk/asterisk.git] / apps / app_mixmonitor.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2005, Anthony Minessale II
5  * Copyright (C) 2005 - 2006, Digium, Inc.
6  *
7  * Mark Spencer <markster@digium.com>
8  * Kevin P. Fleming <kpfleming@digium.com>
9  *
10  * Based on app_muxmon.c provided by
11  * Anthony Minessale II <anthmct@yahoo.com>
12  *
13  * See http://www.asterisk.org for more information about
14  * the Asterisk project. Please do not directly contact
15  * any of the maintainers of this project for assistance;
16  * the project provides a web site, mailing lists and IRC
17  * channels for your use.
18  *
19  * This program is free software, distributed under the terms of
20  * the GNU General Public License Version 2. See the LICENSE file
21  * at the top of the source tree.
22  */
23
24 /*! \file
25  *
26  * \brief MixMonitor() - Record a call and mix the audio during the recording
27  * \ingroup applications
28  *
29  * \author Mark Spencer <markster@digium.com>
30  * \author Kevin P. Fleming <kpfleming@digium.com>
31  *
32  * \note Based on app_muxmon.c provided by
33  * Anthony Minessale II <anthmct@yahoo.com>
34  */
35
36 /*** MODULEINFO
37         <support_level>core</support_level>
38  ***/
39
40 #include "asterisk.h"
41
42 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
43
44 #include "asterisk/paths.h"     /* use ast_config_AST_MONITOR_DIR */
45 #include "asterisk/stringfields.h"
46 #include "asterisk/file.h"
47 #include "asterisk/audiohook.h"
48 #include "asterisk/pbx.h"
49 #include "asterisk/module.h"
50 #include "asterisk/cli.h"
51 #include "asterisk/app.h"
52 #include "asterisk/channel.h"
53 #include "asterisk/autochan.h"
54 #include "asterisk/manager.h"
55 #include "asterisk/callerid.h"
56 #include "asterisk/mod_format.h"
57 #include "asterisk/linkedlists.h"
58
59 /*** DOCUMENTATION
60         <application name="MixMonitor" language="en_US">
61                 <synopsis>
62                         Record a call and mix the audio during the recording.  Use of StopMixMonitor is required
63                         to guarantee the audio file is available for processing during dialplan execution.
64                 </synopsis>
65                 <syntax>
66                         <parameter name="file" required="true" argsep=".">
67                                 <argument name="filename" required="true">
68                                         <para>If <replaceable>filename</replaceable> is an absolute path, uses that path, otherwise
69                                         creates the file in the configured monitoring directory from <filename>asterisk.conf.</filename></para>
70                                 </argument>
71                                 <argument name="extension" required="true" />
72                         </parameter>
73                         <parameter name="options">
74                                 <optionlist>
75                                         <option name="a">
76                                                 <para>Append to the file instead of overwriting it.</para>
77                                         </option>
78                                         <option name="b">
79                                                 <para>Only save audio to the file while the channel is bridged.</para>
80                                                 <note><para>Does not include conferences or sounds played to each bridged party</para></note>
81                                                 <note><para>If you utilize this option inside a Local channel, you must make sure the Local
82                                                 channel is not optimized away. To do this, be sure to call your Local channel with the
83                                                 <literal>/n</literal> option. For example: Dial(Local/start@mycontext/n)</para></note>
84                                         </option>
85                                         <option name="v">
86                                                 <para>Adjust the <emphasis>heard</emphasis> volume by a factor of <replaceable>x</replaceable>
87                                                 (range <literal>-4</literal> to <literal>4</literal>)</para>
88                                                 <argument name="x" required="true" />
89                                         </option>
90                                         <option name="V">
91                                                 <para>Adjust the <emphasis>spoken</emphasis> volume by a factor
92                                                 of <replaceable>x</replaceable> (range <literal>-4</literal> to <literal>4</literal>)</para>
93                                                 <argument name="x" required="true" />
94                                         </option>
95                                         <option name="W">
96                                                 <para>Adjust both, <emphasis>heard and spoken</emphasis> volumes by a factor
97                                                 of <replaceable>x</replaceable> (range <literal>-4</literal> to <literal>4</literal>)</para>
98                                                 <argument name="x" required="true" />
99                                         </option>
100                                         <option name="r">
101                                                 <argument name="file" required="true" />
102                                                 <para>Use the specified file to record the <emphasis>receive</emphasis> audio feed.
103                                                 Like with the basic filename argument, if an absolute path isn't given, it will create
104                                                 the file in the configured monitoring directory.</para>
105
106                                         </option>
107                                         <option name="t">
108                                                 <argument name="file" required="true" />
109                                                 <para>Use the specified file to record the <emphasis>transmit</emphasis> audio feed.
110                                                 Like with the basic filename argument, if an absolute path isn't given, it will create
111                                                 the file in the configured monitoring directory.</para>
112                                         </option>
113                                         <option name="i">
114                                                 <argument name="chanvar" required="true" />
115                                                 <para>Stores the MixMonitor's ID on this channel variable.</para>
116                                         </option>
117                                         <option name="m">
118                                                 <argument name="mailbox" required="true" />
119                                                 <para>Create a copy of the recording as a voicemail in the indicated <emphasis>mailbox</emphasis>(es)
120                                                 separated by commas eg. m(1111@default,2222@default,...).  Folders can be optionally specified using
121                                                 the syntax: mailbox@context/folder</para>
122                                         </option>
123                                 </optionlist>
124                         </parameter>
125                         <parameter name="command">
126                                 <para>Will be executed when the recording is over.</para>
127                                 <para>Any strings matching <literal>^{X}</literal> will be unescaped to <variable>X</variable>.</para>
128                                 <para>All variables will be evaluated at the time MixMonitor is called.</para>
129                         </parameter>
130                 </syntax>
131                 <description>
132                         <para>Records the audio on the current channel to the specified file.</para>
133                         <para>This application does not automatically answer and should be preceeded by
134                         an application such as Answer or Progress().</para>
135                         <note><para>MixMonitor runs as an audiohook. In order to keep it running through
136                         a transfer, AUDIOHOOK_INHERIT must be set for the channel which ran mixmonitor.
137                         For more information, including dialplan configuration set for using
138                         AUDIOHOOK_INHERIT with MixMonitor, see the function documentation for
139                         AUDIOHOOK_INHERIT.</para></note>
140                         <variablelist>
141                                 <variable name="MIXMONITOR_FILENAME">
142                                         <para>Will contain the filename used to record.</para>
143                                 </variable>
144                         </variablelist> 
145                 </description>
146                 <see-also>
147                         <ref type="application">Monitor</ref>
148                         <ref type="application">StopMixMonitor</ref>
149                         <ref type="application">PauseMonitor</ref>
150                         <ref type="application">UnpauseMonitor</ref>
151                         <ref type="function">AUDIOHOOK_INHERIT</ref>
152                 </see-also>
153         </application>
154         <application name="StopMixMonitor" language="en_US">
155                 <synopsis>
156                         Stop recording a call through MixMonitor, and free the recording's file handle.
157                 </synopsis>
158                 <syntax>
159                         <parameter name="MixMonitorID" required="false">
160                                 <para>If a valid ID is provided, then this command will stop only that specific
161                                 MixMonitor.</para>
162                         </parameter>
163                 </syntax>
164                 <description>
165                         <para>Stops the audio recording that was started with a call to <literal>MixMonitor()</literal>
166                         on the current channel.</para>
167                 </description>
168                 <see-also>
169                         <ref type="application">MixMonitor</ref>
170                 </see-also>
171         </application>
172         <manager name="MixMonitorMute" language="en_US">
173                 <synopsis>
174                         Mute / unMute a Mixmonitor recording.
175                 </synopsis>
176                 <syntax>
177                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
178                         <parameter name="Channel" required="true">
179                                 <para>Used to specify the channel to mute.</para>
180                         </parameter>
181                         <parameter name="Direction">
182                                 <para>Which part of the recording to mute:  read, write or both (from channel, to channel or both channels).</para>
183                         </parameter>
184                         <parameter name="State">
185                                 <para>Turn mute on or off : 1 to turn on, 0 to turn off.</para>
186                         </parameter>
187                 </syntax>
188                 <description>
189                         <para>This action may be used to mute a MixMonitor recording.</para>
190                 </description>
191         </manager>
192         <manager name="MixMonitor" language="en_US">
193                 <synopsis>
194                         Record a call and mix the audio during the recording.  Use of StopMixMonitor is required
195                         to guarantee the audio file is available for processing during dialplan execution.
196                 </synopsis>
197                 <syntax>
198                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
199                         <parameter name="Channel" required="true">
200                                 <para>Used to specify the channel to record.</para>
201                         </parameter>
202                         <parameter name="File">
203                                 <para>Is the name of the file created in the monitor spool directory.
204                                 Defaults to the same name as the channel (with slashes replaced with dashes).
205                                 This argument is optional if you specify to record unidirectional audio with
206                                 either the r(filename) or t(filename) options in the options field. If
207                                 neither MIXMONITOR_FILENAME or this parameter is set, the mixed stream won't
208                                 be recorded.</para>
209                         </parameter>
210                         <parameter name="options">
211                                 <para>Options that apply to the MixMonitor in the same way as they
212                                 would apply if invoked from the MixMonitor application. For a list of
213                                 available options, see the documentation for the mixmonitor application. </para>
214                         </parameter>
215                 </syntax>
216                 <description>
217                         <para>This action records the audio on the current channel to the specified file.</para>
218                         <variablelist>
219                                 <variable name="MIXMONITOR_FILENAME">
220                                         <para>Will contain the filename used to record the mixed stream.</para>
221                                 </variable>
222                         </variablelist>
223                 </description>
224         </manager>
225         <manager name="StopMixMonitor" language="en_US">
226                 <synopsis>
227                         Stop recording a call through MixMonitor, and free the recording's file handle.
228                 </synopsis>
229                 <syntax>
230                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
231                         <parameter name="Channel" required="true">
232                                 <para>The name of the channel monitored.</para>
233                         </parameter>
234                         <parameter name="MixMonitorID" required="false">
235                                 <para>If a valid ID is provided, then this command will stop only that specific
236                                 MixMonitor.</para>
237                         </parameter>
238                 </syntax>
239                 <description>
240                         <para>This action stops the audio recording that was started with the <literal>MixMonitor</literal>
241                         action on the current channel.</para>
242                 </description>
243         </manager>
244
245  ***/
246
247 #define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
248
249 static const char * const app = "MixMonitor";
250
251 static const char * const stop_app = "StopMixMonitor";
252
253 static const char * const mixmonitor_spy_type = "MixMonitor";
254
255 /*!
256  * \internal
257  * \brief This struct is a list item holds data needed to find a vm_recipient within voicemail
258  */
259 struct vm_recipient {
260         char mailbox[AST_MAX_CONTEXT];
261         char context[AST_MAX_EXTENSION];
262         char folder[80];
263         AST_LIST_ENTRY(vm_recipient) list;
264 };
265
266 struct mixmonitor {
267         struct ast_audiohook audiohook;
268         struct ast_callid *callid;
269         char *filename;
270         char *filename_read;
271         char *filename_write;
272         char *post_process;
273         char *name;
274         unsigned int flags;
275         struct ast_autochan *autochan;
276         struct mixmonitor_ds *mixmonitor_ds;
277
278         /* the below string fields describe data used for creating voicemails from the recording */
279         AST_DECLARE_STRING_FIELDS(
280                 AST_STRING_FIELD(call_context);
281                 AST_STRING_FIELD(call_macrocontext);
282                 AST_STRING_FIELD(call_extension);
283                 AST_STRING_FIELD(call_callerchan);
284                 AST_STRING_FIELD(call_callerid);
285         );
286         int call_priority;
287
288         /* FUTURE DEVELOPMENT NOTICE
289          * recipient_list will need locks if we make it editable after the monitor is started */
290         AST_LIST_HEAD_NOLOCK(, vm_recipient) recipient_list;
291 };
292
293 enum mixmonitor_flags {
294         MUXFLAG_APPEND = (1 << 1),
295         MUXFLAG_BRIDGED = (1 << 2),
296         MUXFLAG_VOLUME = (1 << 3),
297         MUXFLAG_READVOLUME = (1 << 4),
298         MUXFLAG_WRITEVOLUME = (1 << 5),
299         MUXFLAG_READ = (1 << 6),
300         MUXFLAG_WRITE = (1 << 7),
301         MUXFLAG_COMBINED = (1 << 8),
302         MUXFLAG_UID = (1 << 9),
303         MUXFLAG_VMRECIPIENTS = (1 << 10),
304 };
305
306 enum mixmonitor_args {
307         OPT_ARG_READVOLUME = 0,
308         OPT_ARG_WRITEVOLUME,
309         OPT_ARG_VOLUME,
310         OPT_ARG_WRITENAME,
311         OPT_ARG_READNAME,
312         OPT_ARG_UID,
313         OPT_ARG_VMRECIPIENTS,
314         OPT_ARG_ARRAY_SIZE,     /* Always last element of the enum */
315 };
316
317 AST_APP_OPTIONS(mixmonitor_opts, {
318         AST_APP_OPTION('a', MUXFLAG_APPEND),
319         AST_APP_OPTION('b', MUXFLAG_BRIDGED),
320         AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME),
321         AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME),
322         AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
323         AST_APP_OPTION_ARG('r', MUXFLAG_READ, OPT_ARG_READNAME),
324         AST_APP_OPTION_ARG('t', MUXFLAG_WRITE, OPT_ARG_WRITENAME),
325         AST_APP_OPTION_ARG('i', MUXFLAG_UID, OPT_ARG_UID),
326         AST_APP_OPTION_ARG('m', MUXFLAG_VMRECIPIENTS, OPT_ARG_VMRECIPIENTS),
327 });
328
329 struct mixmonitor_ds {
330         unsigned int destruction_ok;
331         ast_cond_t destruction_condition;
332         ast_mutex_t lock;
333
334         /* The filestream is held in the datastore so it can be stopped
335          * immediately during stop_mixmonitor or channel destruction. */
336         int fs_quit;
337
338         struct ast_filestream *fs;
339         struct ast_filestream *fs_read;
340         struct ast_filestream *fs_write;
341
342         struct ast_audiohook *audiohook;
343
344         unsigned int samp_rate;
345 };
346
347 /*!
348  * \internal
349  * \pre mixmonitor_ds must be locked before calling this function
350  */
351 static void mixmonitor_ds_close_fs(struct mixmonitor_ds *mixmonitor_ds)
352 {
353         unsigned char quitting = 0;
354
355         if (mixmonitor_ds->fs) {
356                 quitting = 1;
357                 ast_closestream(mixmonitor_ds->fs);
358                 mixmonitor_ds->fs = NULL;
359                 ast_verb(2, "MixMonitor close filestream (mixed)\n");
360         }
361
362         if (mixmonitor_ds->fs_read) {
363                 quitting = 1;
364                 ast_closestream(mixmonitor_ds->fs_read);
365                 mixmonitor_ds->fs_read = NULL;
366                 ast_verb(2, "MixMonitor close filestream (read)\n");
367         }
368
369         if (mixmonitor_ds->fs_write) {
370                 quitting = 1;
371                 ast_closestream(mixmonitor_ds->fs_write);
372                 mixmonitor_ds->fs_write = NULL;
373                 ast_verb(2, "MixMonitor close filestream (write)\n");
374         }
375
376         if (quitting) {
377                 mixmonitor_ds->fs_quit = 1;
378         }
379 }
380
381 static void mixmonitor_ds_destroy(void *data)
382 {
383         struct mixmonitor_ds *mixmonitor_ds = data;
384
385         ast_mutex_lock(&mixmonitor_ds->lock);
386         mixmonitor_ds->audiohook = NULL;
387         mixmonitor_ds->destruction_ok = 1;
388         ast_cond_signal(&mixmonitor_ds->destruction_condition);
389         ast_mutex_unlock(&mixmonitor_ds->lock);
390 }
391
392 static const struct ast_datastore_info mixmonitor_ds_info = {
393         .type = "mixmonitor",
394         .destroy = mixmonitor_ds_destroy,
395 };
396
397 static void destroy_monitor_audiohook(struct mixmonitor *mixmonitor)
398 {
399         if (mixmonitor->mixmonitor_ds) {
400                 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
401                 mixmonitor->mixmonitor_ds->audiohook = NULL;
402                 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
403         }
404         /* kill the audiohook.*/
405         ast_audiohook_lock(&mixmonitor->audiohook);
406         ast_audiohook_detach(&mixmonitor->audiohook);
407         ast_audiohook_unlock(&mixmonitor->audiohook);
408         ast_audiohook_destroy(&mixmonitor->audiohook);
409 }
410
411 static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook) 
412 {
413         struct ast_channel *peer = NULL;
414         int res = 0;
415
416         if (!chan)
417                 return -1;
418
419         ast_audiohook_attach(chan, audiohook);
420
421         if (!res && ast_test_flag(ast_channel_flags(chan), AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
422                 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
423
424         return res;
425 }
426
427 /*!
428  * \internal
429  * \brief adds recipients to a mixmonitor's recipient list
430  * \param mixmonitor mixmonitor being affected
431  * \param vm_recipients string containing the desired recipients to add
432  */
433 static void add_vm_recipients_from_string(struct mixmonitor *mixmonitor, const char *vm_recipients)
434 {
435         /* recipients are in a single string with a format format resembling "mailbox@context/INBOX,mailbox2@context2,mailbox3@context3/Work" */
436         char *cur_mailbox = ast_strdupa(vm_recipients);
437         char *cur_context;
438         char *cur_folder;
439         char *next;
440         int elements_processed = 0;
441
442         while (!ast_strlen_zero(cur_mailbox)) {
443                 ast_debug(3, "attempting to add next element %d from %s\n", elements_processed, cur_mailbox);
444                 if ((next = strchr(cur_mailbox, ',')) || (next = strchr(cur_mailbox, '&'))) {
445                         *(next++) = '\0';
446                 }
447
448                 if ((cur_folder = strchr(cur_mailbox, '/'))) {
449                         *(cur_folder++) = '\0';
450                 } else {
451                         cur_folder = "INBOX";
452                 }
453
454                 if ((cur_context = strchr(cur_mailbox, '@'))) {
455                         *(cur_context++) = '\0';
456                 } else {
457                         cur_context = "default";
458                 }
459
460                 if (!ast_strlen_zero(cur_mailbox) && !ast_strlen_zero(cur_context)) {
461                         struct vm_recipient *recipient;
462                         if (!(recipient = ast_malloc(sizeof(*recipient)))) {
463                                 ast_log(LOG_ERROR, "Failed to allocate recipient. Aborting function.\n");
464                                 return;
465                         }
466                         ast_copy_string(recipient->context, cur_context, sizeof(recipient->context));
467                         ast_copy_string(recipient->mailbox, cur_mailbox, sizeof(recipient->mailbox));
468                         ast_copy_string(recipient->folder, cur_folder, sizeof(recipient->folder));
469
470                         /* Add to list */
471                         ast_verb(5, "Adding %s@%s to recipient list\n", recipient->mailbox, recipient->context);
472                         AST_LIST_INSERT_HEAD(&mixmonitor->recipient_list, recipient, list);
473                 } else {
474                         ast_log(LOG_ERROR, "Failed to properly parse extension and/or context from element %d of recipient string: %s\n", elements_processed, vm_recipients);
475                 }
476
477                 cur_mailbox = next;
478                 elements_processed++;
479         }
480 }
481
482 static void clear_mixmonitor_recipient_list(struct mixmonitor *mixmonitor)
483 {
484         struct vm_recipient *current;
485         while ((current = AST_LIST_REMOVE_HEAD(&mixmonitor->recipient_list, list))) {
486                 /* Clear list element data */
487                 ast_free(current);
488         }
489 }
490
491 #define SAMPLES_PER_FRAME 160
492
493 static void mixmonitor_free(struct mixmonitor *mixmonitor)
494 {
495         if (mixmonitor) {
496                 if (mixmonitor->mixmonitor_ds) {
497                         ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
498                         ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
499                         ast_free(mixmonitor->filename_write);
500                         ast_free(mixmonitor->filename_read);
501                         ast_free(mixmonitor->mixmonitor_ds);
502                         ast_free(mixmonitor->name);
503                         ast_free(mixmonitor->post_process);
504                 }
505
506                 /* Free everything in the recipient list */
507                 clear_mixmonitor_recipient_list(mixmonitor);
508
509                 /* clean stringfields */
510                 ast_string_field_free_memory(mixmonitor);
511
512                 if (mixmonitor->callid) {
513                         ast_callid_unref(mixmonitor->callid);
514                 }
515                 ast_free(mixmonitor);
516         }
517 }
518
519 /*!
520  * \internal
521  * \brief Copies the mixmonitor to all voicemail recipients
522  * \param mixmonitor The mixmonitor that needs to forward its file to recipients
523  * \param ext Format of the file that was saved
524  */
525 static void copy_to_voicemail(struct mixmonitor *mixmonitor, const char *ext, const char *filename)
526 {
527         struct vm_recipient *recipient = NULL;
528         struct ast_vm_recording_data recording_data;
529         if (ast_string_field_init(&recording_data, 512)) {
530                 ast_log(LOG_ERROR, "Failed to string_field_init, skipping copy_to_voicemail\n");
531                 return;
532         }
533
534         /* Copy strings to stringfields that will be used for all recipients */
535         ast_string_field_set(&recording_data, recording_file, filename);
536         ast_string_field_set(&recording_data, recording_ext, ext);
537         ast_string_field_set(&recording_data, call_context, mixmonitor->call_context);
538         ast_string_field_set(&recording_data, call_macrocontext, mixmonitor->call_macrocontext);
539         ast_string_field_set(&recording_data, call_extension, mixmonitor->call_extension);
540         ast_string_field_set(&recording_data, call_callerchan, mixmonitor->call_callerchan);
541         ast_string_field_set(&recording_data, call_callerid, mixmonitor->call_callerid);
542         /* and call_priority gets copied too */
543         recording_data.call_priority = mixmonitor->call_priority;
544
545         AST_LIST_TRAVERSE(&mixmonitor->recipient_list, recipient, list) {
546                 /* context, mailbox, and folder need to be set per recipient */
547                 ast_string_field_set(&recording_data, context, recipient->context);
548                 ast_string_field_set(&recording_data, mailbox, recipient->mailbox);
549                 ast_string_field_set(&recording_data, folder, recipient->folder);
550
551                 ast_verb(4, "MixMonitor attempting to send voicemail copy to %s@%s\n", recording_data.mailbox,
552                         recording_data.context);
553                 ast_app_copy_recording_to_vm(&recording_data);
554         }
555
556         /* Free the string fields for recording_data before exiting the function. */
557         ast_string_field_free_memory(&recording_data);
558 }
559
560 static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag, char **ext)
561 {
562         /* Initialize the file if not already done so */
563         char *last_slash = NULL;
564         if (!ast_strlen_zero(filename)) {
565                 if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
566                         *oflags = O_CREAT | O_WRONLY;
567                         *oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
568
569                         last_slash = strrchr(filename, '/');
570
571                         if ((*ext = strrchr(filename, '.')) && (*ext > last_slash)) {
572                                 **ext = '\0';
573                                 *ext = *ext + 1;
574                         } else {
575                                 *ext = "raw";
576                         }
577
578                         if (!(*fs = ast_writefile(filename, *ext, NULL, *oflags, 0, 0666))) {
579                                 ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, *ext);
580                                 *errflag = 1;
581                         } else {
582                                 struct ast_filestream *tmp = *fs;
583                                 mixmonitor->mixmonitor_ds->samp_rate = MAX(mixmonitor->mixmonitor_ds->samp_rate, ast_format_rate(&tmp->fmt->format));
584                         }
585                 }
586         }
587 }
588
589 static void *mixmonitor_thread(void *obj) 
590 {
591         struct mixmonitor *mixmonitor = obj;
592         char *fs_ext = "";
593         char *fs_read_ext = "";
594         char *fs_write_ext = "";
595
596         struct ast_filestream **fs = NULL;
597         struct ast_filestream **fs_read = NULL;
598         struct ast_filestream **fs_write = NULL;
599
600         unsigned int oflags;
601         int errflag = 0;
602         struct ast_format format_slin;
603
604         /* Keep callid association before any log messages */
605         if (mixmonitor->callid) {
606                 ast_callid_threadassoc_add(mixmonitor->callid);
607         }
608
609         ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
610
611         fs = &mixmonitor->mixmonitor_ds->fs;
612         fs_read = &mixmonitor->mixmonitor_ds->fs_read;
613         fs_write = &mixmonitor->mixmonitor_ds->fs_write;
614
615         ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
616         mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag, &fs_ext);
617         mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag, &fs_read_ext);
618         mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag, &fs_write_ext);
619
620         ast_format_set(&format_slin, ast_format_slin_by_rate(mixmonitor->mixmonitor_ds->samp_rate), 0);
621
622         ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
623
624
625         /* The audiohook must enter and exit the loop locked */
626         ast_audiohook_lock(&mixmonitor->audiohook);
627         while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
628                 struct ast_frame *fr = NULL;
629                 struct ast_frame *fr_read = NULL;
630                 struct ast_frame *fr_write = NULL;
631
632                 if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME, &format_slin,
633                                                 &fr_read, &fr_write))) {
634                         ast_audiohook_trigger_wait(&mixmonitor->audiohook);
635
636                         if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
637                                 break;
638                         }
639                         continue;
640                 }
641
642                 /* audiohook lock is not required for the next block.
643                  * Unlock it, but remember to lock it before looping or exiting */
644                 ast_audiohook_unlock(&mixmonitor->audiohook);
645
646                 if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) {
647                         ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
648
649                         /* Write out the frame(s) */
650                         if ((*fs_read) && (fr_read)) {
651                                 struct ast_frame *cur;
652
653                                 for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
654                                         ast_writestream(*fs_read, cur);
655                                 }
656                         }
657
658                         if ((*fs_write) && (fr_write)) {
659                                 struct ast_frame *cur;
660
661                                 for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
662                                         ast_writestream(*fs_write, cur);
663                                 }
664                         }
665
666                         if ((*fs) && (fr)) {
667                                 struct ast_frame *cur;
668
669                                 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
670                                         ast_writestream(*fs, cur);
671                                 }
672                         }
673                         ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
674                 }
675                 /* All done! free it. */
676                 if (fr) {
677                         ast_frame_free(fr, 0);
678                 }
679                 if (fr_read) {
680                         ast_frame_free(fr_read, 0);
681                 }
682                 if (fr_write) {
683                         ast_frame_free(fr_write, 0);
684                 }
685
686                 fr = NULL;
687                 fr_write = NULL;
688                 fr_read = NULL;
689
690                 ast_audiohook_lock(&mixmonitor->audiohook);
691         }
692         ast_audiohook_unlock(&mixmonitor->audiohook);
693
694         ast_autochan_destroy(mixmonitor->autochan);
695
696         /* Datastore cleanup.  close the filestream and wait for ds destruction */
697         ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
698         mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
699         if (!mixmonitor->mixmonitor_ds->destruction_ok) {
700                 ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
701         }
702         ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
703
704         /* kill the audiohook */
705         destroy_monitor_audiohook(mixmonitor);
706
707         if (mixmonitor->post_process) {
708                 ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
709                 ast_safe_system(mixmonitor->post_process);
710         }
711
712         ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
713
714         if (!AST_LIST_EMPTY(&mixmonitor->recipient_list)) {
715                 if (ast_strlen_zero(fs_ext)) {
716                         ast_log(LOG_ERROR, "No file extension set for Mixmonitor %s. Skipping copy to voicemail.\n",
717                                 mixmonitor -> name);
718                 } else {
719                         ast_verb(3, "Copying recordings for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
720                         copy_to_voicemail(mixmonitor, fs_ext, mixmonitor->filename);
721                 }
722                 if (!ast_strlen_zero(fs_read_ext)) {
723                         ast_verb(3, "Copying read recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
724                         copy_to_voicemail(mixmonitor, fs_read_ext, mixmonitor->filename_read);
725                 }
726                 if (!ast_strlen_zero(fs_write_ext)) {
727                         ast_verb(3, "Copying write recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
728                         copy_to_voicemail(mixmonitor, fs_write_ext, mixmonitor->filename_write);
729                 }
730         } else {
731                 ast_debug(3, "No recipients to forward monitor to, moving on.\n");
732         }
733
734         mixmonitor_free(mixmonitor);
735         return NULL;
736 }
737
738 static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id)
739 {
740         struct ast_datastore *datastore = NULL;
741         struct mixmonitor_ds *mixmonitor_ds;
742
743         if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
744                 return -1;
745         }
746
747         if (ast_asprintf(datastore_id, "%p", mixmonitor_ds) == -1) {
748                 ast_log(LOG_ERROR, "Failed to allocate memory for MixMonitor ID.\n");
749         }
750
751         ast_mutex_init(&mixmonitor_ds->lock);
752         ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
753
754         if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, *datastore_id))) {
755                 ast_mutex_destroy(&mixmonitor_ds->lock);
756                 ast_cond_destroy(&mixmonitor_ds->destruction_condition);
757                 ast_free(mixmonitor_ds);
758                 return -1;
759         }
760
761
762         mixmonitor_ds->samp_rate = 8000;
763         mixmonitor_ds->audiohook = &mixmonitor->audiohook;
764         datastore->data = mixmonitor_ds;
765
766         ast_channel_lock(chan);
767         ast_channel_datastore_add(chan, datastore);
768         ast_channel_unlock(chan);
769
770         mixmonitor->mixmonitor_ds = mixmonitor_ds;
771         return 0;
772 }
773
774 static void launch_monitor_thread(struct ast_channel *chan, const char *filename,
775                                   unsigned int flags, int readvol, int writevol,
776                                   const char *post_process, const char *filename_write,
777                                   char *filename_read, const char *uid_channel_var,
778                                   const char *recipients)
779 {
780         pthread_t thread;
781         struct mixmonitor *mixmonitor;
782         char postprocess2[1024] = "";
783         char *datastore_id = NULL;
784
785         postprocess2[0] = 0;
786         /* If a post process system command is given attach it to the structure */
787         if (!ast_strlen_zero(post_process)) {
788                 char *p1, *p2;
789
790                 p1 = ast_strdupa(post_process);
791                 for (p2 = p1; *p2; p2++) {
792                         if (*p2 == '^' && *(p2+1) == '{') {
793                                 *p2 = '$';
794                         }
795                 }
796                 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
797         }
798
799         /* Pre-allocate mixmonitor structure and spy */
800         if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
801                 return;
802         }
803
804         /* Now that the struct has been calloced, go ahead and initialize the string fields. */
805         if (ast_string_field_init(mixmonitor, 512)) {
806                 mixmonitor_free(mixmonitor);
807                 return;
808         }
809
810         /* Setup the actual spy before creating our thread */
811         if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type, 0)) {
812                 mixmonitor_free(mixmonitor);
813                 return;
814         }
815
816         /* Copy over flags and channel name */
817         mixmonitor->flags = flags;
818         if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
819                 mixmonitor_free(mixmonitor);
820                 return;
821         }
822
823         if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id)) {
824                 ast_autochan_destroy(mixmonitor->autochan);
825                 mixmonitor_free(mixmonitor);
826                 ast_free(datastore_id);
827                 return;
828         }
829
830         if (!ast_strlen_zero(uid_channel_var)) {
831                 if (datastore_id) {
832                         pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
833                 }
834         }
835         ast_free(datastore_id);
836
837         mixmonitor->name = ast_strdup(ast_channel_name(chan));
838
839         if (!ast_strlen_zero(postprocess2)) {
840                 mixmonitor->post_process = ast_strdup(postprocess2);
841         }
842
843         if (!ast_strlen_zero(filename)) {
844                 mixmonitor->filename = ast_strdup(filename);
845         }
846
847         if (!ast_strlen_zero(filename_write)) {
848                 mixmonitor->filename_write = ast_strdup(filename_write);
849         }
850
851         if (!ast_strlen_zero(filename_read)) {
852                 mixmonitor->filename_read = ast_strdup(filename_read);
853         }
854
855         if (!ast_strlen_zero(recipients)) {
856                 char callerid[256];
857                 struct ast_party_connected_line *connected;
858
859                 ast_channel_lock(chan);
860
861                 /* We use the connected line of the invoking channel for caller ID. */
862
863                 connected = ast_channel_connected(chan);
864                 ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid,
865                         connected->id.name.str, connected->id.number.valid,
866                         connected->id.number.str);
867                 ast_callerid_merge(callerid, sizeof(callerid),
868                         S_COR(connected->id.name.valid, connected->id.name.str, NULL),
869                         S_COR(connected->id.number.valid, connected->id.number.str, NULL),
870                         "Unknown");
871
872                 ast_string_field_set(mixmonitor, call_context, ast_channel_context(chan));
873                 ast_string_field_set(mixmonitor, call_macrocontext, ast_channel_macrocontext(chan));
874                 ast_string_field_set(mixmonitor, call_extension, ast_channel_exten(chan));
875                 ast_string_field_set(mixmonitor, call_callerchan, ast_channel_name(chan));
876                 ast_string_field_set(mixmonitor, call_callerid, callerid);
877                 mixmonitor->call_priority = ast_channel_priority(chan);
878
879                 ast_channel_unlock(chan);
880
881                 add_vm_recipients_from_string(mixmonitor, recipients);
882         }
883
884         ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
885
886         if (readvol)
887                 mixmonitor->audiohook.options.read_volume = readvol;
888         if (writevol)
889                 mixmonitor->audiohook.options.write_volume = writevol;
890
891         if (startmon(chan, &mixmonitor->audiohook)) {
892                 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
893                         mixmonitor_spy_type, ast_channel_name(chan));
894                 ast_audiohook_destroy(&mixmonitor->audiohook);
895                 mixmonitor_free(mixmonitor);
896                 return;
897         }
898
899         /* reference be released at mixmonitor destruction */
900         mixmonitor->callid = ast_read_threadstorage_callid();
901
902         ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor);
903 }
904
905 /* a note on filename_parse: creates directory structure and assigns absolute path from relative paths for filenames */
906 /* requires immediate copying of string from return to retain data since otherwise it will immediately lose scope */
907 static char *filename_parse(char *filename, char *buffer, size_t len)
908 {
909         char *slash;
910         if (ast_strlen_zero(filename)) {
911                 ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
912         } else if (filename[0] != '/') {
913                 char *build;
914                 build = ast_alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(filename) + 3);
915                 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, filename);
916                 filename = build;
917         }
918
919         ast_copy_string(buffer, filename, len);
920
921         if ((slash = strrchr(filename, '/'))) {
922                 *slash = '\0';
923         }
924         ast_mkdir(filename, 0777);
925
926         return buffer;
927 }
928
929 static int mixmonitor_exec(struct ast_channel *chan, const char *data)
930 {
931         int x, readvol = 0, writevol = 0;
932         char *filename_read = NULL;
933         char *filename_write = NULL;
934         char filename_buffer[1024] = "";
935         char *uid_channel_var = NULL;
936
937         struct ast_flags flags = { 0 };
938         char *recipients = NULL;
939         char *parse;
940         AST_DECLARE_APP_ARGS(args,
941                 AST_APP_ARG(filename);
942                 AST_APP_ARG(options);
943                 AST_APP_ARG(post_process);
944         );
945
946         if (ast_strlen_zero(data)) {
947                 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
948                 return -1;
949         }
950
951         parse = ast_strdupa(data);
952
953         AST_STANDARD_APP_ARGS(args, parse);
954
955         if (args.options) {
956                 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
957
958                 ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
959
960                 if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
961                         if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
962                                 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
963                         } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
964                                 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
965                         } else {
966                                 readvol = get_volfactor(x);
967                         }
968                 }
969
970                 if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
971                         if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
972                                 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
973                         } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
974                                 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
975                         } else {
976                                 writevol = get_volfactor(x);
977                         }
978                 }
979
980                 if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
981                         if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
982                                 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
983                         } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
984                                 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
985                         } else {
986                                 readvol = writevol = get_volfactor(x);
987                         }
988                 }
989
990                 if (ast_test_flag(&flags, MUXFLAG_VMRECIPIENTS)) {
991                         if (ast_strlen_zero(opts[OPT_ARG_VMRECIPIENTS])) {
992                                 ast_log(LOG_WARNING, "No voicemail recipients were specified for the vm copy ('m') option.\n");
993                         } else {
994                                 recipients = ast_strdupa(opts[OPT_ARG_VMRECIPIENTS]);
995                         }
996                 }
997
998                 if (ast_test_flag(&flags, MUXFLAG_WRITE)) {
999                         filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer)));
1000                 }
1001
1002                 if (ast_test_flag(&flags, MUXFLAG_READ)) {
1003                         filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
1004                 }
1005
1006                 if (ast_test_flag(&flags, MUXFLAG_UID)) {
1007                         uid_channel_var = opts[OPT_ARG_UID];
1008                 }
1009         }
1010         /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
1011
1012         if (!ast_test_flag(&flags, MUXFLAG_WRITE) && !ast_test_flag(&flags, MUXFLAG_READ) && ast_strlen_zero(args.filename)) {
1013                 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
1014                 return -1;
1015         }
1016
1017         /* If filename exists, try to create directories for it */
1018         if (!(ast_strlen_zero(args.filename))) {
1019                 args.filename = ast_strdupa(filename_parse(args.filename, filename_buffer, sizeof(filename_buffer)));
1020         }
1021
1022         pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
1023         launch_monitor_thread(chan,
1024                         args.filename,
1025                         flags.flags,
1026                         readvol,
1027                         writevol,
1028                         args.post_process,
1029                         filename_write,
1030                         filename_read,
1031                         uid_channel_var,
1032                         recipients);
1033
1034         return 0;
1035 }
1036
1037 static int stop_mixmonitor_exec(struct ast_channel *chan, const char *data)
1038 {
1039         struct ast_datastore *datastore = NULL;
1040         char *parse = "";
1041         struct mixmonitor_ds *mixmonitor_ds;
1042
1043         AST_DECLARE_APP_ARGS(args,
1044                 AST_APP_ARG(mixmonid);
1045         );
1046
1047         if (!ast_strlen_zero(data)) {
1048                 parse = ast_strdupa(data);
1049         }
1050
1051         AST_STANDARD_APP_ARGS(args, parse);
1052
1053         ast_channel_lock(chan);
1054
1055         if (!(datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.mixmonid))) {
1056                 ast_channel_unlock(chan);
1057                 return -1;
1058         }
1059         mixmonitor_ds = datastore->data;
1060
1061         ast_mutex_lock(&mixmonitor_ds->lock);
1062
1063         /* closing the filestream here guarantees the file is avaliable to the dialplan
1064          * after calling StopMixMonitor */
1065         mixmonitor_ds_close_fs(mixmonitor_ds);
1066
1067         /* The mixmonitor thread may be waiting on the audiohook trigger.
1068          * In order to exit from the mixmonitor loop before waiting on channel
1069          * destruction, poke the audiohook trigger. */
1070         if (mixmonitor_ds->audiohook) {
1071                 if (mixmonitor_ds->audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
1072                         ast_audiohook_update_status(mixmonitor_ds->audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
1073                 }
1074                 ast_audiohook_lock(mixmonitor_ds->audiohook);
1075                 ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
1076                 ast_audiohook_unlock(mixmonitor_ds->audiohook);
1077                 mixmonitor_ds->audiohook = NULL;
1078         }
1079
1080         ast_mutex_unlock(&mixmonitor_ds->lock);
1081
1082         /* Remove the datastore so the monitor thread can exit */
1083         if (!ast_channel_datastore_remove(chan, datastore)) {
1084                 ast_datastore_free(datastore);
1085         }
1086         ast_channel_unlock(chan);
1087
1088         return 0;
1089 }
1090
1091 static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1092 {
1093         struct ast_channel *chan;
1094         struct ast_datastore *datastore = NULL;
1095         struct mixmonitor_ds *mixmonitor_ds = NULL;
1096
1097         switch (cmd) {
1098         case CLI_INIT:
1099                 e->command = "mixmonitor {start|stop|list}";
1100                 e->usage =
1101                         "Usage: mixmonitor <start|stop|list> <chan_name> [args]\n"
1102                         "       The optional arguments are passed to the MixMonitor\n"
1103                         "       application when the 'start' command is used.\n";
1104                 return NULL;
1105         case CLI_GENERATE:
1106                 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
1107         }
1108
1109         if (a->argc < 3) {
1110                 return CLI_SHOWUSAGE;
1111         }
1112
1113         if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
1114                 ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
1115                 /* Technically this is a failure, but we don't want 2 errors printing out */
1116                 return CLI_SUCCESS;
1117         }
1118
1119         ast_channel_lock(chan);
1120
1121         if (!strcasecmp(a->argv[1], "start")) {
1122                 mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1123                 ast_channel_unlock(chan);
1124         } else if (!strcasecmp(a->argv[1], "stop")){
1125                 ast_channel_unlock(chan);
1126                 stop_mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1127         } else if (!strcasecmp(a->argv[1], "list")) {
1128                 ast_cli(a->fd, "MixMonitor ID\tFile\tReceive File\tTransmit File\n");
1129                 ast_cli(a->fd, "=========================================================================\n");
1130                 AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
1131                         if (datastore->info == &mixmonitor_ds_info) {
1132                                 char *filename = "";
1133                                 char *filename_read = "";
1134                                 char *filename_write = "";
1135                                 mixmonitor_ds = datastore->data;
1136                                 if (mixmonitor_ds->fs)
1137                                         filename = ast_strdupa(mixmonitor_ds->fs->filename);
1138                                 if (mixmonitor_ds->fs_read)
1139                                         filename_read = ast_strdupa(mixmonitor_ds->fs_read->filename);
1140                                 if (mixmonitor_ds->fs_write)
1141                                         filename_write = ast_strdupa(mixmonitor_ds->fs_write->filename);
1142                                 ast_cli(a->fd, "%p\t%s\t%s\t%s\n", mixmonitor_ds, filename, filename_read, filename_write);
1143                         }
1144                 }
1145                 ast_channel_unlock(chan);
1146         } else {
1147                 ast_channel_unlock(chan);
1148                 chan = ast_channel_unref(chan);
1149                 return CLI_SHOWUSAGE;
1150         }
1151
1152         chan = ast_channel_unref(chan);
1153
1154         return CLI_SUCCESS;
1155 }
1156
1157 /*! \brief  Mute / unmute  a MixMonitor channel */
1158 static int manager_mute_mixmonitor(struct mansession *s, const struct message *m)
1159 {
1160         struct ast_channel *c = NULL;
1161
1162         const char *name = astman_get_header(m, "Channel");
1163         const char *id = astman_get_header(m, "ActionID");
1164         const char *state = astman_get_header(m, "State");
1165         const char *direction = astman_get_header(m,"Direction");
1166
1167         int clearmute = 1;
1168
1169         enum ast_audiohook_flags flag;
1170
1171         if (ast_strlen_zero(direction)) {
1172                 astman_send_error(s, m, "No direction specified. Must be read, write or both");
1173                 return AMI_SUCCESS;
1174         }
1175
1176         if (!strcasecmp(direction, "read")) {
1177                 flag = AST_AUDIOHOOK_MUTE_READ;
1178         } else  if (!strcasecmp(direction, "write")) {
1179                 flag = AST_AUDIOHOOK_MUTE_WRITE;
1180         } else  if (!strcasecmp(direction, "both")) {
1181                 flag = AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE;
1182         } else {
1183                 astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
1184                 return AMI_SUCCESS;
1185         }
1186
1187         if (ast_strlen_zero(name)) {
1188                 astman_send_error(s, m, "No channel specified");
1189                 return AMI_SUCCESS;
1190         }
1191
1192         if (ast_strlen_zero(state)) {
1193                 astman_send_error(s, m, "No state specified");
1194                 return AMI_SUCCESS;
1195         }
1196
1197         clearmute = ast_false(state);
1198         c = ast_channel_get_by_name(name);
1199
1200         if (!c) {
1201                 astman_send_error(s, m, "No such channel");
1202                 return AMI_SUCCESS;
1203         }
1204
1205         if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) {
1206                 c = ast_channel_unref(c);
1207                 astman_send_error(s, m, "Cannot set mute flag");
1208                 return AMI_SUCCESS;
1209         }
1210
1211         astman_append(s, "Response: Success\r\n");
1212
1213         if (!ast_strlen_zero(id)) {
1214                 astman_append(s, "ActionID: %s\r\n", id);
1215         }
1216
1217         astman_append(s, "\r\n");
1218
1219         c = ast_channel_unref(c);
1220
1221         return AMI_SUCCESS;
1222 }
1223
1224 static int manager_mixmonitor(struct mansession *s, const struct message *m)
1225 {
1226         struct ast_channel *c = NULL;
1227
1228         const char *name = astman_get_header(m, "Channel");
1229         const char *id = astman_get_header(m, "ActionID");
1230         const char *file = astman_get_header(m, "File");
1231         const char *options = astman_get_header(m, "Options");
1232         char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1233         struct ast_flags flags = { 0 };
1234         char *uid_channel_var = NULL;
1235         const char *mixmonitor_id = NULL;
1236
1237         int res;
1238         char args[PATH_MAX] = "";
1239         if (ast_strlen_zero(name)) {
1240                 astman_send_error(s, m, "No channel specified");
1241                 return AMI_SUCCESS;
1242         }
1243
1244         c = ast_channel_get_by_name(name);
1245
1246         if (!c) {
1247                 astman_send_error(s, m, "No such channel");
1248                 return AMI_SUCCESS;
1249         }
1250
1251         if (!ast_strlen_zero(options)) {
1252                 ast_app_parse_options(mixmonitor_opts, &flags, opts, ast_strdupa(options));
1253         }
1254
1255         snprintf(args, sizeof(args), "%s,%s", file, options);
1256
1257         ast_channel_lock(c);
1258         res = mixmonitor_exec(c, args);
1259
1260         if (ast_test_flag(&flags, MUXFLAG_UID)) {
1261                 uid_channel_var = opts[OPT_ARG_UID];
1262                 mixmonitor_id = pbx_builtin_getvar_helper(c, uid_channel_var);
1263         }
1264         ast_channel_unlock(c);
1265
1266         if (res) {
1267                 c = ast_channel_unref(c);
1268                 astman_send_error(s, m, "Could not start monitoring channel");
1269                 return AMI_SUCCESS;
1270         }
1271
1272         astman_append(s, "Response: Success\r\n");
1273
1274         if (!ast_strlen_zero(id)) {
1275                 astman_append(s, "ActionID: %s\r\n", id);
1276         }
1277
1278         if (!ast_strlen_zero(mixmonitor_id)) {
1279                 astman_append(s, "MixMonitorID: %s\r\n", mixmonitor_id);
1280         }
1281
1282         astman_append(s, "\r\n");
1283
1284         c = ast_channel_unref(c);
1285
1286         return AMI_SUCCESS;
1287 }
1288
1289 static int manager_stop_mixmonitor(struct mansession *s, const struct message *m)
1290 {
1291         struct ast_channel *c = NULL;
1292
1293         const char *name = astman_get_header(m, "Channel");
1294         const char *id = astman_get_header(m, "ActionID");
1295         const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1296
1297         int res;
1298         if (ast_strlen_zero(name)) {
1299                 astman_send_error(s, m, "No channel specified");
1300                 return AMI_SUCCESS;
1301         }
1302
1303         c = ast_channel_get_by_name(name);
1304
1305         if (!c) {
1306                 astman_send_error(s, m, "No such channel");
1307                 return AMI_SUCCESS;
1308         }
1309
1310         res = stop_mixmonitor_exec(c, mixmonitor_id);
1311
1312         if (res) {
1313                 astman_send_error(s, m, "Could not stop monitoring channel");
1314                 return AMI_SUCCESS;
1315         }
1316
1317         astman_append(s, "Response: Success\r\n");
1318
1319         if (!ast_strlen_zero(id)) {
1320                 astman_append(s, "ActionID: %s\r\n", id);
1321         }
1322
1323         astman_append(s, "\r\n");
1324
1325         c = ast_channel_unref(c);
1326
1327         return AMI_SUCCESS;
1328 }
1329
1330 static struct ast_cli_entry cli_mixmonitor[] = {
1331         AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
1332 };
1333
1334 static int unload_module(void)
1335 {
1336         int res;
1337
1338         ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
1339         res = ast_unregister_application(stop_app);
1340         res |= ast_unregister_application(app);
1341         res |= ast_manager_unregister("MixMonitorMute");
1342         res |= ast_manager_unregister("MixMonitor");
1343         res |= ast_manager_unregister("StopMixMonitor");
1344
1345         return res;
1346 }
1347
1348 static int load_module(void)
1349 {
1350         int res;
1351
1352         ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
1353         res = ast_register_application_xml(app, mixmonitor_exec);
1354         res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec);
1355         res |= ast_manager_register_xml("MixMonitorMute", 0, manager_mute_mixmonitor);
1356         res |= ast_manager_register_xml("MixMonitor", 0, manager_mixmonitor);
1357         res |= ast_manager_register_xml("StopMixMonitor", 0, manager_stop_mixmonitor);
1358
1359         return res;
1360 }
1361
1362 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mixed Audio Monitoring Application");