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