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