Merge "res_pjsip: Ignore empty TLS configuration"
[asterisk/asterisk.git] / res / res_monitor.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief PBX channel monitoring
22  *
23  * \author Mark Spencer <markster@digium.com>
24  */
25
26 /*** MODULEINFO
27         <use type="module">func_periodic_hook</use>
28         <support_level>core</support_level>
29  ***/
30  
31 #include "asterisk.h"
32
33 #include <sys/stat.h>
34 #include <libgen.h>
35
36 #include "asterisk/paths.h"     /* use ast_config_AST_MONITOR_DIR */
37 #include "asterisk/lock.h"
38 #include "asterisk/channel.h"
39 #include "asterisk/file.h"
40 #include "asterisk/pbx.h"
41 #include "asterisk/module.h"
42 #include "asterisk/cli.h"
43 #include "asterisk/manager.h"
44 #include "asterisk/stasis.h"
45 #include "asterisk/stasis_channels.h"
46 #define AST_API_MODULE
47 #include "asterisk/monitor.h"
48 #undef AST_API_MODULE
49 #include "asterisk/app.h"
50 #include "asterisk/utils.h"
51 #include "asterisk/config.h"
52 #include "asterisk/options.h"
53 #include "asterisk/beep.h"
54
55 /*** DOCUMENTATION
56         <application name="Monitor" language="en_US">
57                 <synopsis>
58                         Monitor a channel.
59                 </synopsis>
60                 <syntax>
61                         <parameter name="file_format" argsep=":">
62                                 <argument name="file_format" required="true">
63                                         <para>Optional.  If not set, defaults to <literal>wav</literal></para>
64                                 </argument>
65                                 <argument name="urlbase" />
66                         </parameter>
67                         <parameter name="fname_base">
68                                 <para>If set, changes the filename used to the one specified.</para>
69                         </parameter>
70                         <parameter name="options">
71                                 <optionlist>
72                                         <option name="m">
73                                                 <para>When the recording ends mix the two leg files into one and
74                                                 delete the two leg files. If the variable <variable>MONITOR_EXEC</variable>
75                                                 is set, the application referenced in it will be executed instead of
76                                                 soxmix/sox and the raw leg files will NOT be deleted automatically.
77                                                 soxmix/sox or <variable>MONITOR_EXEC</variable> is handed 3 arguments,
78                                                 the two leg files and a target mixed file name which is the same as
79                                                 the leg file names only without the in/out designator.</para>
80                                                 <para>If <variable>MONITOR_EXEC_ARGS</variable> is set, the contents
81                                                 will be passed on as additional arguments to <variable>MONITOR_EXEC</variable>.
82                                                 Both <variable>MONITOR_EXEC</variable> and the Mix flag can be set from the
83                                                 administrator interface.</para>
84                                                 <warning><para>Do not use untrusted strings such as
85                                                 <variable>CALLERID(num)</variable> or <variable>CALLERID(name)</variable>
86                                                 as part of <variable>MONITOR_EXEC</variable> or
87                                                 <variable>MONITOR_EXEC_ARGS</variable>.  You risk a command injection
88                                                 attack executing arbitrary commands if the untrusted strings aren't
89                                                 filtered to remove dangerous characters.  See function
90                                                 <variable>FILTER()</variable>.</para></warning>
91                                         </option>
92                                         <option name="b">
93                                                 <para>Don't begin recording unless a call is bridged to another channel.</para>
94                                         </option>
95                                         <option name="B">
96                                                 <para>Play a periodic beep while this call is being recorded.</para>
97                                                 <argument name="interval"><para>Interval, in seconds. Default is 15.</para></argument>
98                                         </option>
99                                         <option name="i">
100                                                 <para>Skip recording of input stream (disables <literal>m</literal> option).</para>
101                                         </option>
102                                         <option name="o">
103                                                 <para>Skip recording of output stream (disables <literal>m</literal> option).</para>
104                                         </option>
105                                 </optionlist>
106                         </parameter>
107                 </syntax>
108                 <description>
109                         <para>Used to start monitoring a channel. The channel's input and output
110                         voice packets are logged to files until the channel hangs up or
111                         monitoring is stopped by the StopMonitor application.</para>
112                         <para>By default, files are stored to <filename>/var/spool/asterisk/monitor/</filename>.
113                         Returns <literal>-1</literal> if monitor files can't be opened or if the channel is
114                         already monitored, otherwise <literal>0</literal>.</para>
115                 </description>
116                 <see-also>
117                         <ref type="application">StopMonitor</ref>
118                 </see-also>
119         </application>
120         <application name="StopMonitor" language="en_US">
121                 <synopsis>
122                         Stop monitoring a channel.
123                 </synopsis>
124                 <syntax />
125                 <description>
126                         <para>Stops monitoring a channel. Has no effect if the channel is not monitored.</para>
127                 </description>
128         </application>
129         <application name="ChangeMonitor" language="en_US">
130                 <synopsis>
131                         Change monitoring filename of a channel.
132                 </synopsis>
133                 <syntax>
134                         <parameter name="filename_base" required="true">
135                                 <para>The new filename base to use for monitoring this channel.</para>
136                         </parameter>
137                 </syntax>
138                 <description>
139                         <para>Changes monitoring filename of a channel. Has no effect if the
140                         channel is not monitored.</para>
141                 </description>
142         </application>
143         <application name="PauseMonitor" language="en_US">
144                 <synopsis>
145                         Pause monitoring of a channel.
146                 </synopsis>
147                 <syntax />
148                 <description>
149                         <para>Pauses monitoring of a channel until it is re-enabled by a call to UnpauseMonitor.</para>
150                 </description>
151                 <see-also>
152                         <ref type="application">UnpauseMonitor</ref>
153                 </see-also>
154         </application>
155         <application name="UnpauseMonitor" language="en_US">
156                 <synopsis>
157                         Unpause monitoring of a channel.
158                 </synopsis>
159                 <syntax />
160                 <description>
161                         <para>Unpauses monitoring of a channel on which monitoring had
162                         previously been paused with PauseMonitor.</para>
163                 </description>
164                 <see-also>
165                         <ref type="application">PauseMonitor</ref>
166                 </see-also>
167         </application>
168         <manager name="Monitor" language="en_US">
169                 <synopsis>
170                         Monitor a channel.
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 record.</para>
176                         </parameter>
177                         <parameter name="File">
178                                 <para>Is the name of the file created in the monitor spool directory.
179                                 Defaults to the same name as the channel (with slashes replaced with dashes).</para>
180                         </parameter>
181                         <parameter name="Format">
182                                 <para>Is the audio recording format. Defaults to <literal>wav</literal>.</para>
183                         </parameter>
184                         <parameter name="Mix">
185                                 <para>Boolean parameter as to whether to mix the input and output channels
186                                 together after the recording is finished.</para>
187                         </parameter>
188                 </syntax>
189                 <description>
190                         <para>This action may be used to record the audio on a
191                         specified channel.</para>
192                 </description>
193         </manager>
194         <manager name="StopMonitor" language="en_US">
195                 <synopsis>
196                         Stop monitoring a channel.
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>The name of the channel monitored.</para>
202                         </parameter>
203                 </syntax>
204                 <description>
205                         <para>This action may be used to end a previously started 'Monitor' action.</para>
206                 </description>
207         </manager>
208         <manager name="ChangeMonitor" language="en_US">
209                 <synopsis>
210                         Change monitoring filename of a channel.
211                 </synopsis>
212                 <syntax>
213                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
214                         <parameter name="Channel" required="true">
215                                 <para>Used to specify the channel to record.</para>
216                         </parameter>
217                         <parameter name="File" required="true">
218                                 <para>Is the new name of the file created in the
219                                 monitor spool directory.</para>
220                         </parameter>
221                 </syntax>
222                 <description>
223                         <para>This action may be used to change the file
224                         started by a previous 'Monitor' action.</para>
225                 </description>
226         </manager>
227         <manager name="PauseMonitor" language="en_US">
228                 <synopsis>
229                         Pause monitoring of a channel.
230                 </synopsis>
231                 <syntax>
232                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
233                         <parameter name="Channel" required="true">
234                                 <para>Used to specify the channel to record.</para>
235                         </parameter>
236                 </syntax>
237                 <description>
238                         <para>This action may be used to temporarily stop the
239                         recording of a channel.</para>
240                 </description>
241         </manager>
242         <manager name="UnpauseMonitor" language="en_US">
243                 <synopsis>
244                         Unpause monitoring of a channel.
245                 </synopsis>
246                 <syntax>
247                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
248                         <parameter name="Channel" required="true">
249                                 <para>Used to specify the channel to record.</para>
250                         </parameter>
251                 </syntax>
252                 <description>
253                         <para>This action may be used to re-enable recording
254                         of a channel after calling PauseMonitor.</para>
255                 </description>
256         </manager>
257
258  ***/
259
260 AST_MUTEX_DEFINE_STATIC(monitorlock);
261
262 #define LOCK_IF_NEEDED(lock, needed) do { \
263         if (needed) \
264                 ast_channel_lock(lock); \
265         } while(0)
266
267 #define UNLOCK_IF_NEEDED(lock, needed) do { \
268         if (needed) \
269                 ast_channel_unlock(lock); \
270         } while (0)
271
272 static unsigned long seq = 0;
273
274 /*! 
275  * \brief Change state of monitored channel 
276  * \param chan 
277  * \param state monitor state
278  * \retval 0 on success.
279  * \retval -1 on failure.
280 */
281 static int ast_monitor_set_state(struct ast_channel *chan, int state)
282 {
283         LOCK_IF_NEEDED(chan, 1);
284         if (!ast_channel_monitor(chan)) {
285                 UNLOCK_IF_NEEDED(chan, 1);
286                 return -1;
287         }
288         ast_channel_monitor(chan)->state = state;
289         UNLOCK_IF_NEEDED(chan, 1);
290         return 0;
291 }
292
293 /*! \brief Start monitoring a channel
294  * \param chan ast_channel struct to record
295  * \param format_spec file format to use for recording
296  * \param fname_base filename base to record to
297  * \param need_lock whether to lock the channel mutex
298  * \param stream_action whether to record the input and/or output streams.  X_REC_IN | X_REC_OUT is most often used
299  * Creates the file to record, if no format is specified it assumes WAV
300  * It also sets channel variable __MONITORED=yes
301  * \retval 0 on success
302  * \retval -1 on failure
303  */
304 int AST_OPTIONAL_API_NAME(ast_monitor_start)(struct ast_channel *chan, const char *format_spec,
305                                              const char *fname_base, int need_lock, int stream_action,
306                                              const char *beep_id)
307 {
308         int res = 0;
309         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
310
311         LOCK_IF_NEEDED(chan, need_lock);
312
313         if (!(ast_channel_monitor(chan))) {
314                 struct ast_channel_monitor *monitor;
315                 char *channel_name, *p;
316
317                 /* Create monitoring directory if needed */
318                 ast_mkdir(ast_config_AST_MONITOR_DIR, 0777);
319
320                 if (!(monitor = ast_calloc(1, sizeof(*monitor)))) {
321                         UNLOCK_IF_NEEDED(chan, need_lock);
322                         return -1;
323                 }
324
325                 if (!ast_strlen_zero(beep_id)) {
326                         ast_copy_string(monitor->beep_id, beep_id, sizeof(monitor->beep_id));
327                 }
328
329                 /* Determine file names */
330                 if (!ast_strlen_zero(fname_base)) {
331                         int directory = strchr(fname_base, '/') ? 1 : 0;
332                         const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR;
333                         const char *absolute_suffix = *fname_base == '/' ? "" : "/";
334
335                         snprintf(monitor->read_filename, FILENAME_MAX, "%s%s%s-in",
336                                                 absolute, absolute_suffix, fname_base);
337                         snprintf(monitor->write_filename, FILENAME_MAX, "%s%s%s-out",
338                                                 absolute, absolute_suffix, fname_base);
339                         snprintf(monitor->filename_base, FILENAME_MAX, "%s%s%s",
340                                                 absolute, absolute_suffix, fname_base);
341
342                         /* try creating the directory just in case it doesn't exist */
343                         if (directory) {
344                                 char *name = ast_strdupa(monitor->filename_base);
345                                 ast_mkdir(dirname(name), 0777);
346                         }
347                 } else {
348                         ast_mutex_lock(&monitorlock);
349                         snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%lu",
350                                                 ast_config_AST_MONITOR_DIR, seq);
351                         snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%lu",
352                                                 ast_config_AST_MONITOR_DIR, seq);
353                         seq++;
354                         ast_mutex_unlock(&monitorlock);
355
356                         /* Replace all '/' chars from the channel name with '-' chars. */
357                         channel_name = ast_strdupa(ast_channel_name(chan));
358                         for (p = channel_name; (p = strchr(p, '/')); ) {
359                                 *p = '-';
360                         }
361
362                         snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
363                                          ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name);
364                         monitor->filename_changed = 1;
365                 }
366
367                 monitor->stop = ast_monitor_stop;
368
369                 /* Determine file format */
370                 if (!ast_strlen_zero(format_spec)) {
371                         monitor->format = ast_strdup(format_spec);
372                 } else {
373                         monitor->format = ast_strdup("wav");
374                 }
375                 
376                 /* open files */
377                 if (stream_action & X_REC_IN) {
378                         if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0)
379                                 ast_filedelete(monitor->read_filename, NULL);
380                         if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
381                                                         monitor->format, NULL,
382                                                         O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
383                                 ast_log(LOG_WARNING, "Could not create file %s\n",
384                                                         monitor->read_filename);
385                                 ast_free(monitor);
386                                 UNLOCK_IF_NEEDED(chan, need_lock);
387                                 return -1;
388                         }
389                 } else
390                         monitor->read_stream = NULL;
391
392                 if (stream_action & X_REC_OUT) {
393                         if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
394                                 ast_filedelete(monitor->write_filename, NULL);
395                         }
396                         if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
397                                                         monitor->format, NULL,
398                                                         O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
399                                 ast_log(LOG_WARNING, "Could not create file %s\n",
400                                                         monitor->write_filename);
401                                 if (monitor->read_stream) {
402                                         ast_closestream(monitor->read_stream);
403                                 }
404                                 ast_free(monitor);
405                                 UNLOCK_IF_NEEDED(chan, need_lock);
406                                 return -1;
407                         }
408                 } else
409                         monitor->write_stream = NULL;
410
411                 ast_channel_insmpl_set(chan, 0);
412                 ast_channel_outsmpl_set(chan, 0);
413                 ast_channel_monitor_set(chan, monitor);
414                 ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
415                 /* so we know this call has been monitored in case we need to bill for it or something */
416                 pbx_builtin_setvar_helper(chan, "__MONITORED","true");
417
418                 message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan),
419                                 ast_channel_monitor_start_type(),
420                                 NULL);
421                 if (message) {
422                         stasis_publish(ast_channel_topic(chan), message);
423                 }
424         } else {
425                 ast_debug(1,"Cannot start monitoring %s, already monitored\n", ast_channel_name(chan));
426                 res = -1;
427         }
428
429         UNLOCK_IF_NEEDED(chan, need_lock);
430
431         return res;
432 }
433
434 /*!
435  * \brief Get audio format.
436  * \param format recording format.
437  * The file format extensions that Asterisk uses are not all the same as that
438  * which soxmix expects.  This function ensures that the format used as the
439  * extension on the filename is something soxmix will understand.
440  */
441 static const char *get_soxmix_format(const char *format)
442 {
443         const char *res = format;
444
445         if (!strcasecmp(format,"ulaw"))
446                 res = "ul";
447         if (!strcasecmp(format,"alaw"))
448                 res = "al";
449         
450         return res;
451 }
452
453 /*! 
454  * \brief Stop monitoring channel 
455  * \param chan 
456  * \param need_lock
457  * Stop the recording, close any open streams, mix in/out channels if required
458  * \return Always 0
459 */
460 int AST_OPTIONAL_API_NAME(ast_monitor_stop)(struct ast_channel *chan, int need_lock)
461 {
462         int delfiles = 0;
463         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
464
465         LOCK_IF_NEEDED(chan, need_lock);
466
467         if (ast_channel_monitor(chan)) {
468                 RAII_VAR(struct ast_str *, tmp, ast_str_create(1024), ast_free);
469
470                 if (ast_channel_monitor(chan)->read_stream) {
471                         ast_closestream(ast_channel_monitor(chan)->read_stream);
472                 }
473                 if (ast_channel_monitor(chan)->write_stream) {
474                         ast_closestream(ast_channel_monitor(chan)->write_stream);
475                 }
476
477                 if (tmp && ast_channel_monitor(chan)->filename_changed && !ast_strlen_zero(ast_channel_monitor(chan)->filename_base)) {
478                         if (ast_fileexists(ast_channel_monitor(chan)->read_filename,NULL,NULL) > 0) {
479                                 ast_str_set(&tmp, 0, "%s-in", ast_channel_monitor(chan)->filename_base);
480                                 if (ast_fileexists(ast_str_buffer(tmp), NULL, NULL) > 0) {
481                                         ast_filedelete(ast_str_buffer(tmp), NULL);
482                                 }
483                                 ast_filerename(ast_channel_monitor(chan)->read_filename, ast_str_buffer(tmp), ast_channel_monitor(chan)->format);
484                         } else {
485                                 ast_log(LOG_WARNING, "File %s not found\n", ast_channel_monitor(chan)->read_filename);
486                         }
487
488                         if (tmp && ast_fileexists(ast_channel_monitor(chan)->write_filename,NULL,NULL) > 0) {
489                                 ast_str_set(&tmp, 0, "%s-out", ast_channel_monitor(chan)->filename_base);
490                                 if (ast_fileexists(ast_str_buffer(tmp), NULL, NULL) > 0) {
491                                         ast_filedelete(ast_str_buffer(tmp), NULL);
492                                 }
493                                 ast_filerename(ast_channel_monitor(chan)->write_filename, ast_str_buffer(tmp), ast_channel_monitor(chan)->format);
494                         } else {
495                                 ast_log(LOG_WARNING, "File %s not found\n", ast_channel_monitor(chan)->write_filename);
496                         }
497                 }
498
499                 if (tmp && ast_channel_monitor(chan)->joinfiles && !ast_strlen_zero(ast_channel_monitor(chan)->filename_base)) {
500                         const char *format = !strcasecmp(ast_channel_monitor(chan)->format,"wav49") ? "WAV" : ast_channel_monitor(chan)->format;
501                         char *fname_base = ast_channel_monitor(chan)->filename_base;
502                         const char *execute, *execute_args;
503                         /* at this point, fname_base really is the full path */
504
505                         /* Set the execute application */
506                         execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC");
507                         if (ast_strlen_zero(execute)) {
508 #ifdef HAVE_SOXMIX
509                                 execute = "nice -n 19 soxmix";
510 #else
511                                 execute = "nice -n 19 sox -m";
512 #endif
513                                 format = get_soxmix_format(format);
514                                 delfiles = 1;
515                         } 
516                         execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS");
517                         if (ast_strlen_zero(execute_args)) {
518                                 execute_args = "";
519                         }
520
521                         ast_str_set(&tmp, 0, delfiles ? "( " : "");
522                         ast_str_append(&tmp, 0, "%s \"%s-in.%s\" \"%s-out.%s\" \"%s.%s\" %s &",
523                                 execute, fname_base, format, fname_base, format, fname_base, format,execute_args);
524                         if (delfiles) {
525                                 /* remove legs when done mixing */
526                                 ast_str_append(&tmp, 0, "& rm -f \"%s-\"* ) &", fname_base);
527                         }
528                         ast_debug(1,"monitor executing %s\n", ast_str_buffer(tmp));
529                         if (ast_safe_system(ast_str_buffer(tmp)) == -1)
530                                 ast_log(LOG_WARNING, "Execute of %s failed.\n", ast_str_buffer(tmp));
531                 }
532
533                 if (!ast_strlen_zero(ast_channel_monitor(chan)->beep_id)) {
534                         ast_beep_stop(chan, ast_channel_monitor(chan)->beep_id);
535                 }
536
537                 ast_free(ast_channel_monitor(chan)->format);
538                 ast_free(ast_channel_monitor(chan));
539                 ast_channel_monitor_set(chan, NULL);
540
541                 message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan),
542                                 ast_channel_monitor_stop_type(),
543                                 NULL);
544                 if (message) {
545                         stasis_publish(ast_channel_topic(chan), message);
546                 }
547                 pbx_builtin_setvar_helper(chan, "MONITORED", NULL);
548         }
549         pbx_builtin_setvar_helper(chan, "AUTO_MONITOR", NULL);
550
551         UNLOCK_IF_NEEDED(chan, need_lock);
552
553         return 0;
554 }
555
556
557 /*! \brief Pause monitoring of channel */
558 int AST_OPTIONAL_API_NAME(ast_monitor_pause)(struct ast_channel *chan)
559 {
560         return ast_monitor_set_state(chan, AST_MONITOR_PAUSED);
561 }
562
563 /*! \brief Unpause monitoring of channel */
564 int AST_OPTIONAL_API_NAME(ast_monitor_unpause)(struct ast_channel *chan)
565 {
566         return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
567 }
568
569 /*! \brief Wrapper for ast_monitor_pause */
570 static int pause_monitor_exec(struct ast_channel *chan, const char *data)
571 {
572         return ast_monitor_pause(chan);
573 }
574
575 /*! \brief Wrapper for ast_monitor_unpause */
576 static int unpause_monitor_exec(struct ast_channel *chan, const char *data)
577 {
578         return ast_monitor_unpause(chan);
579 }
580
581 /*! 
582  * \brief Change monitored filename of channel 
583  * \param chan
584  * \param fname_base new filename
585  * \param need_lock
586  * \retval 0 on success.
587  * \retval -1 on failure.
588 */
589 int AST_OPTIONAL_API_NAME(ast_monitor_change_fname)(struct ast_channel *chan, const char *fname_base, int need_lock)
590 {
591         if (ast_strlen_zero(fname_base)) {
592                 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null\n", ast_channel_name(chan));
593                 return -1;
594         }
595
596         LOCK_IF_NEEDED(chan, need_lock);
597
598         if (ast_channel_monitor(chan)) {
599                 int directory = strchr(fname_base, '/') ? 1 : 0;
600                 const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR;
601                 const char *absolute_suffix = *fname_base == '/' ? "" : "/";
602                 char tmpstring[sizeof(ast_channel_monitor(chan)->filename_base)] = "";
603                 int i, fd[2] = { -1, -1 }, doexit = 0;
604
605                 /* before continuing, see if we're trying to rename the file to itself... */
606                 snprintf(tmpstring, sizeof(tmpstring), "%s%s%s", absolute, absolute_suffix, fname_base);
607
608                 /* try creating the directory just in case it doesn't exist */
609                 if (directory) {
610                         char *name = ast_strdupa(tmpstring);
611                         ast_mkdir(dirname(name), 0777);
612                 }
613
614                 /*!
615                  * \note We cannot just compare filenames, due to symlinks, relative
616                  * paths, and other possible filesystem issues.  We could use
617                  * realpath(3), but its use is discouraged.  However, if we try to
618                  * create the same file from two different paths, the second will
619                  * fail, and so we have our notification that the filenames point to
620                  * the same path.
621                  *
622                  * Remember, also, that we're using the basename of the file (i.e.
623                  * the file without the format suffix), so it does not already exist
624                  * and we aren't interfering with the recording itself.
625                  */
626                 ast_debug(2, "comparing tmpstring %s to filename_base %s\n", tmpstring, ast_channel_monitor(chan)->filename_base);
627                 
628                 if ((fd[0] = open(tmpstring, O_CREAT | O_WRONLY, 0644)) < 0 ||
629                         (fd[1] = open(ast_channel_monitor(chan)->filename_base, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) {
630                         if (fd[0] < 0) {
631                                 ast_log(LOG_ERROR, "Unable to compare filenames: %s\n", strerror(errno));
632                         } else {
633                                 ast_debug(2, "No need to rename monitor filename to itself\n");
634                         }
635                         doexit = 1;
636                 }
637
638                 /* Cleanup temporary files */
639                 for (i = 0; i < 2; i++) {
640                         if (fd[i] >= 0) {
641                                 while (close(fd[i]) < 0 && errno == EINTR);
642                         }
643                 }
644                 unlink(tmpstring);
645                 /* if previous monitor file existed in a subdirectory, the directory will not be removed */
646                 unlink(ast_channel_monitor(chan)->filename_base);
647
648                 if (doexit) {
649                         UNLOCK_IF_NEEDED(chan, need_lock);
650                         return 0;
651                 }
652
653                 ast_copy_string(ast_channel_monitor(chan)->filename_base, tmpstring, sizeof(ast_channel_monitor(chan)->filename_base));
654                 ast_channel_monitor(chan)->filename_changed = 1;
655         } else {
656                 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", ast_channel_name(chan), fname_base);
657         }
658
659         UNLOCK_IF_NEEDED(chan, need_lock);
660
661         return 0;
662 }
663
664 enum {
665         MON_FLAG_BRIDGED =  (1 << 0),
666         MON_FLAG_MIX =      (1 << 1),
667         MON_FLAG_DROP_IN =  (1 << 2),
668         MON_FLAG_DROP_OUT = (1 << 3),
669         MON_FLAG_BEEP =     (1 << 4),
670 };
671
672 enum {
673         OPT_ARG_BEEP_INTERVAL,
674         OPT_ARG_ARRAY_SIZE,     /* Always last element of the enum */
675 };
676
677 AST_APP_OPTIONS(monitor_opts, {
678         AST_APP_OPTION('b', MON_FLAG_BRIDGED),
679         AST_APP_OPTION('m', MON_FLAG_MIX),
680         AST_APP_OPTION('i', MON_FLAG_DROP_IN),
681         AST_APP_OPTION('o', MON_FLAG_DROP_OUT),
682         AST_APP_OPTION_ARG('B', MON_FLAG_BEEP, OPT_ARG_BEEP_INTERVAL),
683 });
684
685 /*!
686  * \brief Start monitor
687  * \param chan
688  * \param data arguments passed fname|options
689  * \retval 0 on success.
690  * \retval -1 on failure.
691 */
692 static int start_monitor_exec(struct ast_channel *chan, const char *data)
693 {
694         char *arg;
695         char *options;
696         char *delay;
697         char *urlprefix = NULL;
698         char tmp[256];
699         int stream_action = X_REC_IN | X_REC_OUT;
700         int joinfiles = 0;
701         int res = 0;
702         char *parse;
703         struct ast_flags flags = { 0 };
704         char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
705         char beep_id[64] = "";
706         AST_DECLARE_APP_ARGS(args,
707                 AST_APP_ARG(format);
708                 AST_APP_ARG(fname_base);
709                 AST_APP_ARG(options);
710         );
711         
712         /* Parse arguments. */
713         if (ast_strlen_zero(data)) {
714                 ast_log(LOG_ERROR, "Monitor requires an argument\n");
715                 return 0;
716         }
717
718         parse = ast_strdupa(data);
719         AST_STANDARD_APP_ARGS(args, parse);
720
721         if (!ast_strlen_zero(args.options)) {
722                 ast_app_parse_options(monitor_opts, &flags, opts, args.options);
723
724                 if (ast_test_flag(&flags, MON_FLAG_MIX)) {
725                         stream_action |= X_JOIN;
726                 }
727                 if (ast_test_flag(&flags, MON_FLAG_DROP_IN)) {
728                         stream_action &= ~X_REC_IN;
729                 }
730                 if (ast_test_flag(&flags, MON_FLAG_DROP_OUT)) {
731                         stream_action &= ~X_REC_OUT;
732                 }
733                 if (ast_test_flag(&flags, MON_FLAG_BEEP)) {
734                         const char *interval_str = S_OR(opts[OPT_ARG_BEEP_INTERVAL], "15");
735                         unsigned int interval = 15;
736
737                         if (sscanf(interval_str, "%30u", &interval) != 1) {
738                                 ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
739                                                 interval_str, interval);
740                         }
741
742                         if (ast_beep_start(chan, interval, beep_id, sizeof(beep_id))) {
743                                 ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
744                                 return -1;
745                         }
746                 }
747         }
748
749         arg = strchr(args.format, ':');
750         if (arg) {
751                 *arg++ = 0;
752                 urlprefix = arg;
753         }
754
755         if (!ast_strlen_zero(urlprefix) && !ast_strlen_zero(args.fname_base)) {
756                 snprintf(tmp, sizeof(tmp), "%s/%s.%s", urlprefix, args.fname_base,
757                         ((strcmp(args.format, "gsm")) ? "wav" : "gsm"));
758                 ast_channel_lock(chan);
759                 ast_cdr_setuserfield(ast_channel_name(chan), tmp);
760                 ast_channel_unlock(chan);
761         }
762         if (ast_test_flag(&flags, MON_FLAG_BRIDGED)) {
763                 /* We must remove the "b" option if listed.  In principle none of
764                    the following could give NULL results, but we check just to
765                    be pedantic. Reconstructing with checks for 'm' option does not
766                    work if we end up adding more options than 'm' in the future. */
767                 delay = ast_strdupa(data);
768                 options = strrchr(delay, ',');
769                 if (options) {
770                         arg = strchr(options, 'b');
771                         if (arg) {
772                                 *arg = 'X';
773                                 pbx_builtin_setvar_helper(chan,"AUTO_MONITOR", delay);
774                         }
775                 }
776                 return 0;
777         }
778
779         res = ast_monitor_start(chan, args.format, args.fname_base, 1, stream_action, beep_id);
780         if (res < 0)
781                 res = ast_monitor_change_fname(chan, args.fname_base, 1);
782
783         if (stream_action & X_JOIN) {
784                 if ((stream_action & X_REC_IN) && (stream_action & X_REC_OUT))
785                         joinfiles = 1;
786                 else
787                         ast_log(LOG_WARNING, "Won't mix streams unless both input and output streams are recorded\n");
788         }
789         ast_monitor_setjoinfiles(chan, joinfiles);
790
791         return res;
792 }
793
794 /*! \brief Wrapper function \see ast_monitor_stop */
795 static int stop_monitor_exec(struct ast_channel *chan, const char *data)
796 {
797         return ast_monitor_stop(chan, 1);
798 }
799
800 /*! \brief Wrapper function \see ast_monitor_change_fname */
801 static int change_monitor_exec(struct ast_channel *chan, const char *data)
802 {
803         return ast_monitor_change_fname(chan, data, 1);
804 }
805
806 /*! \brief Start monitoring a channel by manager connection */
807 static int start_monitor_action(struct mansession *s, const struct message *m)
808 {
809         struct ast_channel *c = NULL;
810         const char *name = astman_get_header(m, "Channel");
811         const char *fname = astman_get_header(m, "File");
812         const char *format = astman_get_header(m, "Format");
813         const char *mix = astman_get_header(m, "Mix");
814         char *d;
815
816         if (ast_strlen_zero(name)) {
817                 astman_send_error(s, m, "No channel specified");
818                 return AMI_SUCCESS;
819         }
820
821         if (!(c = ast_channel_get_by_name(name))) {
822                 astman_send_error(s, m, "No such channel");
823                 return AMI_SUCCESS;
824         }
825
826         if (ast_strlen_zero(fname)) {
827                 /* No filename specified, default to the channel name. */
828                 ast_channel_lock(c);
829                 fname = ast_strdupa(ast_channel_name(c));
830                 ast_channel_unlock(c);
831
832                 /* Replace all '/' chars from the channel name with '-' chars. */
833                 for (d = (char *) fname; (d = strchr(d, '/')); ) {
834                         *d = '-';
835                 }
836         }
837
838         if (ast_monitor_start(c, format, fname, 1, X_REC_IN | X_REC_OUT, NULL)) {
839                 if (ast_monitor_change_fname(c, fname, 1)) {
840                         astman_send_error(s, m, "Could not start monitoring channel");
841                         c = ast_channel_unref(c);
842                         return AMI_SUCCESS;
843                 }
844         }
845
846         if (ast_true(mix)) {
847                 ast_channel_lock(c);
848                 ast_monitor_setjoinfiles(c, 1);
849                 ast_channel_unlock(c);
850         }
851
852         c = ast_channel_unref(c);
853
854         astman_send_ack(s, m, "Started monitoring channel");
855
856         return AMI_SUCCESS;
857 }
858
859 /*! \brief Stop monitoring a channel by manager connection */
860 static int stop_monitor_action(struct mansession *s, const struct message *m)
861 {
862         struct ast_channel *c = NULL;
863         const char *name = astman_get_header(m, "Channel");
864         int res;
865
866         if (ast_strlen_zero(name)) {
867                 astman_send_error(s, m, "No channel specified");
868                 return AMI_SUCCESS;
869         }
870
871         if (!(c = ast_channel_get_by_name(name))) {
872                 astman_send_error(s, m, "No such channel");
873                 return AMI_SUCCESS;
874         }
875
876         res = ast_monitor_stop(c, 1);
877
878         c = ast_channel_unref(c);
879
880         if (res) {
881                 astman_send_error(s, m, "Could not stop monitoring channel");
882                 return AMI_SUCCESS;
883         }
884
885         astman_send_ack(s, m, "Stopped monitoring channel");
886
887         return AMI_SUCCESS;
888 }
889
890 /*! \brief Change filename of a monitored channel by manager connection */
891 static int change_monitor_action(struct mansession *s, const struct message *m)
892 {
893         struct ast_channel *c = NULL;
894         const char *name = astman_get_header(m, "Channel");
895         const char *fname = astman_get_header(m, "File");
896
897         if (ast_strlen_zero(name)) {
898                 astman_send_error(s, m, "No channel specified");
899                 return AMI_SUCCESS;
900         }
901
902         if (ast_strlen_zero(fname)) {
903                 astman_send_error(s, m, "No filename specified");
904                 return AMI_SUCCESS;
905         }
906
907         if (!(c = ast_channel_get_by_name(name))) {
908                 astman_send_error(s, m, "No such channel");
909                 return AMI_SUCCESS;
910         }
911
912         if (ast_monitor_change_fname(c, fname, 1)) {
913                 c = ast_channel_unref(c);
914                 astman_send_error(s, m, "Could not change monitored filename of channel");
915                 return AMI_SUCCESS;
916         }
917
918         c = ast_channel_unref(c);
919
920         astman_send_ack(s, m, "Changed monitor filename");
921
922         return AMI_SUCCESS;
923 }
924
925 void AST_OPTIONAL_API_NAME(ast_monitor_setjoinfiles)(struct ast_channel *chan, int turnon)
926 {
927         if (ast_channel_monitor(chan))
928                 ast_channel_monitor(chan)->joinfiles = turnon;
929 }
930
931 enum MONITOR_PAUSING_ACTION
932 {
933         MONITOR_ACTION_PAUSE,
934         MONITOR_ACTION_UNPAUSE
935 };
936
937 static int do_pause_or_unpause(struct mansession *s, const struct message *m, int action)
938 {
939         struct ast_channel *c = NULL;
940         const char *name = astman_get_header(m, "Channel");
941
942         if (ast_strlen_zero(name)) {
943                 astman_send_error(s, m, "No channel specified");
944                 return AMI_SUCCESS;
945         }
946
947         if (!(c = ast_channel_get_by_name(name))) {
948                 astman_send_error(s, m, "No such channel");
949                 return AMI_SUCCESS;
950         }
951
952         if (action == MONITOR_ACTION_PAUSE) {
953                 ast_monitor_pause(c);
954         } else {
955                 ast_monitor_unpause(c);
956         }
957
958         c = ast_channel_unref(c);
959
960         astman_send_ack(s, m, (action == MONITOR_ACTION_PAUSE ? "Paused monitoring of the channel" : "Unpaused monitoring of the channel"));
961
962         return AMI_SUCCESS;
963 }
964
965 static int pause_monitor_action(struct mansession *s, const struct message *m)
966 {
967         return do_pause_or_unpause(s, m, MONITOR_ACTION_PAUSE);
968 }
969
970 static int unpause_monitor_action(struct mansession *s, const struct message *m)
971 {
972         return do_pause_or_unpause(s, m, MONITOR_ACTION_UNPAUSE);
973 }
974
975 static int load_module(void)
976 {
977         ast_register_application_xml("Monitor", start_monitor_exec);
978         ast_register_application_xml("StopMonitor", stop_monitor_exec);
979         ast_register_application_xml("ChangeMonitor", change_monitor_exec);
980         ast_register_application_xml("PauseMonitor", pause_monitor_exec);
981         ast_register_application_xml("UnpauseMonitor", unpause_monitor_exec);
982         ast_manager_register_xml("Monitor", EVENT_FLAG_CALL, start_monitor_action);
983         ast_manager_register_xml("StopMonitor", EVENT_FLAG_CALL, stop_monitor_action);
984         ast_manager_register_xml("ChangeMonitor", EVENT_FLAG_CALL, change_monitor_action);
985         ast_manager_register_xml("PauseMonitor", EVENT_FLAG_CALL, pause_monitor_action);
986         ast_manager_register_xml("UnpauseMonitor", EVENT_FLAG_CALL, unpause_monitor_action);
987
988         /* For Optional API. */
989         ast_module_shutdown_ref(AST_MODULE_SELF);
990
991         return AST_MODULE_LOAD_SUCCESS;
992 }
993
994 static int unload_module(void)
995 {
996         ast_unregister_application("Monitor");
997         ast_unregister_application("StopMonitor");
998         ast_unregister_application("ChangeMonitor");
999         ast_unregister_application("PauseMonitor");
1000         ast_unregister_application("UnpauseMonitor");
1001         ast_manager_unregister("Monitor");
1002         ast_manager_unregister("StopMonitor");
1003         ast_manager_unregister("ChangeMonitor");
1004         ast_manager_unregister("PauseMonitor");
1005         ast_manager_unregister("UnpauseMonitor");
1006
1007         return 0;
1008 }
1009
1010 /* usecount semantics need to be defined */
1011 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Call Monitoring Resource",
1012         .support_level = AST_MODULE_SUPPORT_CORE,
1013         .load = load_module,
1014         .unload = unload_module,
1015         .load_pri = AST_MODPRI_CHANNEL_DEPEND,
1016 );