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