Merge "res_pjsip: New endpoint option "refer_blind_progress""
[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                 char filename[ FILENAME_MAX ];
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 (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                                 snprintf(filename, FILENAME_MAX, "%s-in", ast_channel_monitor(chan)->filename_base);
472                                 if (ast_fileexists(filename, NULL, NULL) > 0) {
473                                         ast_filedelete(filename, NULL);
474                                 }
475                                 ast_filerename(ast_channel_monitor(chan)->read_filename, filename, 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 (ast_fileexists(ast_channel_monitor(chan)->write_filename,NULL,NULL) > 0) {
481                                 snprintf(filename, FILENAME_MAX, "%s-out", ast_channel_monitor(chan)->filename_base);
482                                 if (ast_fileexists(filename, NULL, NULL) > 0) {
483                                         ast_filedelete(filename, NULL);
484                                 }
485                                 ast_filerename(ast_channel_monitor(chan)->write_filename, filename, 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 (ast_channel_monitor(chan)->joinfiles && !ast_strlen_zero(ast_channel_monitor(chan)->filename_base)) {
492                         char tmp[1024];
493                         char tmp2[1024];
494                         const char *format = !strcasecmp(ast_channel_monitor(chan)->format,"wav49") ? "WAV" : ast_channel_monitor(chan)->format;
495                         char *fname_base = ast_channel_monitor(chan)->filename_base;
496                         const char *execute, *execute_args;
497                         /* at this point, fname_base really is the full path */
498
499                         /* Set the execute application */
500                         execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC");
501                         if (ast_strlen_zero(execute)) {
502 #ifdef HAVE_SOXMIX
503                                 execute = "nice -n 19 soxmix";
504 #else
505                                 execute = "nice -n 19 sox -m";
506 #endif
507                                 format = get_soxmix_format(format);
508                                 delfiles = 1;
509                         } 
510                         execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS");
511                         if (ast_strlen_zero(execute_args)) {
512                                 execute_args = "";
513                         }
514                         
515                         snprintf(tmp, sizeof(tmp), "%s \"%s-in.%s\" \"%s-out.%s\" \"%s.%s\" %s &",
516                                 execute, fname_base, format, fname_base, format, fname_base, format,execute_args);
517                         if (delfiles) {
518                                 snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s-\"* ) &",tmp, fname_base); /* remove legs when done mixing */
519                                 ast_copy_string(tmp, tmp2, sizeof(tmp));
520                         }
521                         ast_debug(1,"monitor executing %s\n",tmp);
522                         if (ast_safe_system(tmp) == -1)
523                                 ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
524                 }
525
526                 if (!ast_strlen_zero(ast_channel_monitor(chan)->beep_id)) {
527                         ast_beep_stop(chan, ast_channel_monitor(chan)->beep_id);
528                 }
529
530                 ast_free(ast_channel_monitor(chan)->format);
531                 ast_free(ast_channel_monitor(chan));
532                 ast_channel_monitor_set(chan, NULL);
533
534                 message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan),
535                                 ast_channel_monitor_stop_type(),
536                                 NULL);
537                 if (message) {
538                         stasis_publish(ast_channel_topic(chan), message);
539                 }
540                 pbx_builtin_setvar_helper(chan, "MONITORED", NULL);
541         }
542         pbx_builtin_setvar_helper(chan, "AUTO_MONITOR", NULL);
543
544         UNLOCK_IF_NEEDED(chan, need_lock);
545
546         return 0;
547 }
548
549
550 /*! \brief Pause monitoring of channel */
551 int AST_OPTIONAL_API_NAME(ast_monitor_pause)(struct ast_channel *chan)
552 {
553         return ast_monitor_set_state(chan, AST_MONITOR_PAUSED);
554 }
555
556 /*! \brief Unpause monitoring of channel */
557 int AST_OPTIONAL_API_NAME(ast_monitor_unpause)(struct ast_channel *chan)
558 {
559         return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
560 }
561
562 /*! \brief Wrapper for ast_monitor_pause */
563 static int pause_monitor_exec(struct ast_channel *chan, const char *data)
564 {
565         return ast_monitor_pause(chan);
566 }
567
568 /*! \brief Wrapper for ast_monitor_unpause */
569 static int unpause_monitor_exec(struct ast_channel *chan, const char *data)
570 {
571         return ast_monitor_unpause(chan);
572 }
573
574 /*! 
575  * \brief Change monitored filename of channel 
576  * \param chan
577  * \param fname_base new filename
578  * \param need_lock
579  * \retval 0 on success.
580  * \retval -1 on failure.
581 */
582 int AST_OPTIONAL_API_NAME(ast_monitor_change_fname)(struct ast_channel *chan, const char *fname_base, int need_lock)
583 {
584         if (ast_strlen_zero(fname_base)) {
585                 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null\n", ast_channel_name(chan));
586                 return -1;
587         }
588
589         LOCK_IF_NEEDED(chan, need_lock);
590
591         if (ast_channel_monitor(chan)) {
592                 int directory = strchr(fname_base, '/') ? 1 : 0;
593                 const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR;
594                 const char *absolute_suffix = *fname_base == '/' ? "" : "/";
595                 char tmpstring[sizeof(ast_channel_monitor(chan)->filename_base)] = "";
596                 int i, fd[2] = { -1, -1 }, doexit = 0;
597
598                 /* before continuing, see if we're trying to rename the file to itself... */
599                 snprintf(tmpstring, sizeof(tmpstring), "%s%s%s", absolute, absolute_suffix, fname_base);
600
601                 /* try creating the directory just in case it doesn't exist */
602                 if (directory) {
603                         char *name = ast_strdupa(tmpstring);
604                         ast_mkdir(dirname(name), 0777);
605                 }
606
607                 /*!
608                  * \note We cannot just compare filenames, due to symlinks, relative
609                  * paths, and other possible filesystem issues.  We could use
610                  * realpath(3), but its use is discouraged.  However, if we try to
611                  * create the same file from two different paths, the second will
612                  * fail, and so we have our notification that the filenames point to
613                  * the same path.
614                  *
615                  * Remember, also, that we're using the basename of the file (i.e.
616                  * the file without the format suffix), so it does not already exist
617                  * and we aren't interfering with the recording itself.
618                  */
619                 ast_debug(2, "comparing tmpstring %s to filename_base %s\n", tmpstring, ast_channel_monitor(chan)->filename_base);
620                 
621                 if ((fd[0] = open(tmpstring, O_CREAT | O_WRONLY, 0644)) < 0 ||
622                         (fd[1] = open(ast_channel_monitor(chan)->filename_base, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) {
623                         if (fd[0] < 0) {
624                                 ast_log(LOG_ERROR, "Unable to compare filenames: %s\n", strerror(errno));
625                         } else {
626                                 ast_debug(2, "No need to rename monitor filename to itself\n");
627                         }
628                         doexit = 1;
629                 }
630
631                 /* Cleanup temporary files */
632                 for (i = 0; i < 2; i++) {
633                         if (fd[i] >= 0) {
634                                 while (close(fd[i]) < 0 && errno == EINTR);
635                         }
636                 }
637                 unlink(tmpstring);
638                 /* if previous monitor file existed in a subdirectory, the directory will not be removed */
639                 unlink(ast_channel_monitor(chan)->filename_base);
640
641                 if (doexit) {
642                         UNLOCK_IF_NEEDED(chan, need_lock);
643                         return 0;
644                 }
645
646                 ast_copy_string(ast_channel_monitor(chan)->filename_base, tmpstring, sizeof(ast_channel_monitor(chan)->filename_base));
647                 ast_channel_monitor(chan)->filename_changed = 1;
648         } else {
649                 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", ast_channel_name(chan), fname_base);
650         }
651
652         UNLOCK_IF_NEEDED(chan, need_lock);
653
654         return 0;
655 }
656
657 enum {
658         MON_FLAG_BRIDGED =  (1 << 0),
659         MON_FLAG_MIX =      (1 << 1),
660         MON_FLAG_DROP_IN =  (1 << 2),
661         MON_FLAG_DROP_OUT = (1 << 3),
662         MON_FLAG_BEEP =     (1 << 4),
663 };
664
665 enum {
666         OPT_ARG_BEEP_INTERVAL,
667         OPT_ARG_ARRAY_SIZE,     /* Always last element of the enum */
668 };
669
670 AST_APP_OPTIONS(monitor_opts, {
671         AST_APP_OPTION('b', MON_FLAG_BRIDGED),
672         AST_APP_OPTION('m', MON_FLAG_MIX),
673         AST_APP_OPTION('i', MON_FLAG_DROP_IN),
674         AST_APP_OPTION('o', MON_FLAG_DROP_OUT),
675         AST_APP_OPTION_ARG('B', MON_FLAG_BEEP, OPT_ARG_BEEP_INTERVAL),
676 });
677
678 /*!
679  * \brief Start monitor
680  * \param chan
681  * \param data arguments passed fname|options
682  * \retval 0 on success.
683  * \retval -1 on failure.
684 */
685 static int start_monitor_exec(struct ast_channel *chan, const char *data)
686 {
687         char *arg;
688         char *options;
689         char *delay;
690         char *urlprefix = NULL;
691         char tmp[256];
692         int stream_action = X_REC_IN | X_REC_OUT;
693         int joinfiles = 0;
694         int res = 0;
695         char *parse;
696         struct ast_flags flags = { 0 };
697         char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
698         char beep_id[64] = "";
699         AST_DECLARE_APP_ARGS(args,
700                 AST_APP_ARG(format);
701                 AST_APP_ARG(fname_base);
702                 AST_APP_ARG(options);
703         );
704         
705         /* Parse arguments. */
706         if (ast_strlen_zero(data)) {
707                 ast_log(LOG_ERROR, "Monitor requires an argument\n");
708                 return 0;
709         }
710
711         parse = ast_strdupa(data);
712         AST_STANDARD_APP_ARGS(args, parse);
713
714         if (!ast_strlen_zero(args.options)) {
715                 ast_app_parse_options(monitor_opts, &flags, opts, args.options);
716
717                 if (ast_test_flag(&flags, MON_FLAG_MIX)) {
718                         stream_action |= X_JOIN;
719                 }
720                 if (ast_test_flag(&flags, MON_FLAG_DROP_IN)) {
721                         stream_action &= ~X_REC_IN;
722                 }
723                 if (ast_test_flag(&flags, MON_FLAG_DROP_OUT)) {
724                         stream_action &= ~X_REC_OUT;
725                 }
726                 if (ast_test_flag(&flags, MON_FLAG_BEEP)) {
727                         const char *interval_str = S_OR(opts[OPT_ARG_BEEP_INTERVAL], "15");
728                         unsigned int interval = 15;
729
730                         if (sscanf(interval_str, "%30u", &interval) != 1) {
731                                 ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
732                                                 interval_str, interval);
733                         }
734
735                         if (ast_beep_start(chan, interval, beep_id, sizeof(beep_id))) {
736                                 ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
737                                 return -1;
738                         }
739                 }
740         }
741
742         arg = strchr(args.format, ':');
743         if (arg) {
744                 *arg++ = 0;
745                 urlprefix = arg;
746         }
747
748         if (!ast_strlen_zero(urlprefix) && !ast_strlen_zero(args.fname_base)) {
749                 snprintf(tmp, sizeof(tmp), "%s/%s.%s", urlprefix, args.fname_base,
750                         ((strcmp(args.format, "gsm")) ? "wav" : "gsm"));
751                 ast_channel_lock(chan);
752                 ast_cdr_setuserfield(ast_channel_name(chan), tmp);
753                 ast_channel_unlock(chan);
754         }
755         if (ast_test_flag(&flags, MON_FLAG_BRIDGED)) {
756                 /* We must remove the "b" option if listed.  In principle none of
757                    the following could give NULL results, but we check just to
758                    be pedantic. Reconstructing with checks for 'm' option does not
759                    work if we end up adding more options than 'm' in the future. */
760                 delay = ast_strdupa(data);
761                 options = strrchr(delay, ',');
762                 if (options) {
763                         arg = strchr(options, 'b');
764                         if (arg) {
765                                 *arg = 'X';
766                                 pbx_builtin_setvar_helper(chan,"AUTO_MONITOR", delay);
767                         }
768                 }
769                 return 0;
770         }
771
772         res = ast_monitor_start(chan, args.format, args.fname_base, 1, stream_action, beep_id);
773         if (res < 0)
774                 res = ast_monitor_change_fname(chan, args.fname_base, 1);
775
776         if (stream_action & X_JOIN) {
777                 if ((stream_action & X_REC_IN) && (stream_action & X_REC_OUT))
778                         joinfiles = 1;
779                 else
780                         ast_log(LOG_WARNING, "Won't mix streams unless both input and output streams are recorded\n");
781         }
782         ast_monitor_setjoinfiles(chan, joinfiles);
783
784         return res;
785 }
786
787 /*! \brief Wrapper function \see ast_monitor_stop */
788 static int stop_monitor_exec(struct ast_channel *chan, const char *data)
789 {
790         return ast_monitor_stop(chan, 1);
791 }
792
793 /*! \brief Wrapper function \see ast_monitor_change_fname */
794 static int change_monitor_exec(struct ast_channel *chan, const char *data)
795 {
796         return ast_monitor_change_fname(chan, data, 1);
797 }
798
799 /*! \brief Start monitoring a channel by manager connection */
800 static int start_monitor_action(struct mansession *s, const struct message *m)
801 {
802         struct ast_channel *c = NULL;
803         const char *name = astman_get_header(m, "Channel");
804         const char *fname = astman_get_header(m, "File");
805         const char *format = astman_get_header(m, "Format");
806         const char *mix = astman_get_header(m, "Mix");
807         char *d;
808
809         if (ast_strlen_zero(name)) {
810                 astman_send_error(s, m, "No channel specified");
811                 return AMI_SUCCESS;
812         }
813
814         if (!(c = ast_channel_get_by_name(name))) {
815                 astman_send_error(s, m, "No such channel");
816                 return AMI_SUCCESS;
817         }
818
819         if (ast_strlen_zero(fname)) {
820                 /* No filename specified, default to the channel name. */
821                 ast_channel_lock(c);
822                 fname = ast_strdupa(ast_channel_name(c));
823                 ast_channel_unlock(c);
824
825                 /* Replace all '/' chars from the channel name with '-' chars. */
826                 for (d = (char *) fname; (d = strchr(d, '/')); ) {
827                         *d = '-';
828                 }
829         }
830
831         if (ast_monitor_start(c, format, fname, 1, X_REC_IN | X_REC_OUT, NULL)) {
832                 if (ast_monitor_change_fname(c, fname, 1)) {
833                         astman_send_error(s, m, "Could not start monitoring channel");
834                         c = ast_channel_unref(c);
835                         return AMI_SUCCESS;
836                 }
837         }
838
839         if (ast_true(mix)) {
840                 ast_channel_lock(c);
841                 ast_monitor_setjoinfiles(c, 1);
842                 ast_channel_unlock(c);
843         }
844
845         c = ast_channel_unref(c);
846
847         astman_send_ack(s, m, "Started monitoring channel");
848
849         return AMI_SUCCESS;
850 }
851
852 /*! \brief Stop monitoring a channel by manager connection */
853 static int stop_monitor_action(struct mansession *s, const struct message *m)
854 {
855         struct ast_channel *c = NULL;
856         const char *name = astman_get_header(m, "Channel");
857         int res;
858
859         if (ast_strlen_zero(name)) {
860                 astman_send_error(s, m, "No channel specified");
861                 return AMI_SUCCESS;
862         }
863
864         if (!(c = ast_channel_get_by_name(name))) {
865                 astman_send_error(s, m, "No such channel");
866                 return AMI_SUCCESS;
867         }
868
869         res = ast_monitor_stop(c, 1);
870
871         c = ast_channel_unref(c);
872
873         if (res) {
874                 astman_send_error(s, m, "Could not stop monitoring channel");
875                 return AMI_SUCCESS;
876         }
877
878         astman_send_ack(s, m, "Stopped monitoring channel");
879
880         return AMI_SUCCESS;
881 }
882
883 /*! \brief Change filename of a monitored channel by manager connection */
884 static int change_monitor_action(struct mansession *s, const struct message *m)
885 {
886         struct ast_channel *c = NULL;
887         const char *name = astman_get_header(m, "Channel");
888         const char *fname = astman_get_header(m, "File");
889
890         if (ast_strlen_zero(name)) {
891                 astman_send_error(s, m, "No channel specified");
892                 return AMI_SUCCESS;
893         }
894
895         if (ast_strlen_zero(fname)) {
896                 astman_send_error(s, m, "No filename specified");
897                 return AMI_SUCCESS;
898         }
899
900         if (!(c = ast_channel_get_by_name(name))) {
901                 astman_send_error(s, m, "No such channel");
902                 return AMI_SUCCESS;
903         }
904
905         if (ast_monitor_change_fname(c, fname, 1)) {
906                 c = ast_channel_unref(c);
907                 astman_send_error(s, m, "Could not change monitored filename of channel");
908                 return AMI_SUCCESS;
909         }
910
911         c = ast_channel_unref(c);
912
913         astman_send_ack(s, m, "Changed monitor filename");
914
915         return AMI_SUCCESS;
916 }
917
918 void AST_OPTIONAL_API_NAME(ast_monitor_setjoinfiles)(struct ast_channel *chan, int turnon)
919 {
920         if (ast_channel_monitor(chan))
921                 ast_channel_monitor(chan)->joinfiles = turnon;
922 }
923
924 enum MONITOR_PAUSING_ACTION
925 {
926         MONITOR_ACTION_PAUSE,
927         MONITOR_ACTION_UNPAUSE
928 };
929
930 static int do_pause_or_unpause(struct mansession *s, const struct message *m, int action)
931 {
932         struct ast_channel *c = NULL;
933         const char *name = astman_get_header(m, "Channel");
934
935         if (ast_strlen_zero(name)) {
936                 astman_send_error(s, m, "No channel specified");
937                 return AMI_SUCCESS;
938         }
939
940         if (!(c = ast_channel_get_by_name(name))) {
941                 astman_send_error(s, m, "No such channel");
942                 return AMI_SUCCESS;
943         }
944
945         if (action == MONITOR_ACTION_PAUSE) {
946                 ast_monitor_pause(c);
947         } else {
948                 ast_monitor_unpause(c);
949         }
950
951         c = ast_channel_unref(c);
952
953         astman_send_ack(s, m, (action == MONITOR_ACTION_PAUSE ? "Paused monitoring of the channel" : "Unpaused monitoring of the channel"));
954
955         return AMI_SUCCESS;
956 }
957
958 static int pause_monitor_action(struct mansession *s, const struct message *m)
959 {
960         return do_pause_or_unpause(s, m, MONITOR_ACTION_PAUSE);
961 }
962
963 static int unpause_monitor_action(struct mansession *s, const struct message *m)
964 {
965         return do_pause_or_unpause(s, m, MONITOR_ACTION_UNPAUSE);
966 }
967
968 static int load_module(void)
969 {
970         ast_register_application_xml("Monitor", start_monitor_exec);
971         ast_register_application_xml("StopMonitor", stop_monitor_exec);
972         ast_register_application_xml("ChangeMonitor", change_monitor_exec);
973         ast_register_application_xml("PauseMonitor", pause_monitor_exec);
974         ast_register_application_xml("UnpauseMonitor", unpause_monitor_exec);
975         ast_manager_register_xml("Monitor", EVENT_FLAG_CALL, start_monitor_action);
976         ast_manager_register_xml("StopMonitor", EVENT_FLAG_CALL, stop_monitor_action);
977         ast_manager_register_xml("ChangeMonitor", EVENT_FLAG_CALL, change_monitor_action);
978         ast_manager_register_xml("PauseMonitor", EVENT_FLAG_CALL, pause_monitor_action);
979         ast_manager_register_xml("UnpauseMonitor", EVENT_FLAG_CALL, unpause_monitor_action);
980
981         return AST_MODULE_LOAD_SUCCESS;
982 }
983
984 static int unload_module(void)
985 {
986         ast_unregister_application("Monitor");
987         ast_unregister_application("StopMonitor");
988         ast_unregister_application("ChangeMonitor");
989         ast_unregister_application("PauseMonitor");
990         ast_unregister_application("UnpauseMonitor");
991         ast_manager_unregister("Monitor");
992         ast_manager_unregister("StopMonitor");
993         ast_manager_unregister("ChangeMonitor");
994         ast_manager_unregister("PauseMonitor");
995         ast_manager_unregister("UnpauseMonitor");
996
997         return 0;
998 }
999
1000 /* usecount semantics need to be defined */
1001 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Call Monitoring Resource",
1002         .support_level = AST_MODULE_SUPPORT_CORE,
1003         .load = load_module,
1004         .unload = unload_module,
1005         .load_pri = AST_MODPRI_CHANNEL_DEPEND,
1006 );