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