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