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