be9c2a84d9e977d07d7963ff3bde9d2c2917a88c
[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                         channel_name = ast_strdupa(ast_channel_name(chan));
337                         while ((p = strchr(channel_name, '/'))) {
338                                 *p = '-';
339                         }
340                         snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
341                                          ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name);
342                         monitor->filename_changed = 1;
343                 }
344
345                 monitor->stop = ast_monitor_stop;
346
347                 /* Determine file format */
348                 if (!ast_strlen_zero(format_spec)) {
349                         monitor->format = ast_strdup(format_spec);
350                 } else {
351                         monitor->format = ast_strdup("wav");
352                 }
353                 
354                 /* open files */
355                 if (stream_action & X_REC_IN) {
356                         if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0)
357                                 ast_filedelete(monitor->read_filename, NULL);
358                         if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
359                                                         monitor->format, NULL,
360                                                         O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
361                                 ast_log(LOG_WARNING, "Could not create file %s\n",
362                                                         monitor->read_filename);
363                                 ast_free(monitor);
364                                 UNLOCK_IF_NEEDED(chan, need_lock);
365                                 return -1;
366                         }
367                 } else
368                         monitor->read_stream = NULL;
369
370                 if (stream_action & X_REC_OUT) {
371                         if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
372                                 ast_filedelete(monitor->write_filename, NULL);
373                         }
374                         if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
375                                                         monitor->format, NULL,
376                                                         O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
377                                 ast_log(LOG_WARNING, "Could not create file %s\n",
378                                                         monitor->write_filename);
379                                 ast_closestream(monitor->read_stream);
380                                 ast_free(monitor);
381                                 UNLOCK_IF_NEEDED(chan, need_lock);
382                                 return -1;
383                         }
384                 } else
385                         monitor->write_stream = NULL;
386
387                 chan->monitor = monitor;
388                 ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
389                 /* so we know this call has been monitored in case we need to bill for it or something */
390                 pbx_builtin_setvar_helper(chan, "__MONITORED","true");
391
392                 ast_manager_event(chan, EVENT_FLAG_CALL, "MonitorStart",
393                                         "Channel: %s\r\n"
394                                                 "Uniqueid: %s\r\n",
395                                 ast_channel_name(chan),
396                                         ast_channel_uniqueid(chan));
397         } else {
398                 ast_debug(1,"Cannot start monitoring %s, already monitored\n", ast_channel_name(chan));
399                 res = -1;
400         }
401
402         UNLOCK_IF_NEEDED(chan, need_lock);
403
404         return res;
405 }
406
407 /*!
408  * \brief Get audio format.
409  * \param format recording format.
410  * The file format extensions that Asterisk uses are not all the same as that
411  * which soxmix expects.  This function ensures that the format used as the
412  * extension on the filename is something soxmix will understand.
413  */
414 static const char *get_soxmix_format(const char *format)
415 {
416         const char *res = format;
417
418         if (!strcasecmp(format,"ulaw"))
419                 res = "ul";
420         if (!strcasecmp(format,"alaw"))
421                 res = "al";
422         
423         return res;
424 }
425
426 /*! 
427  * \brief Stop monitoring channel 
428  * \param chan 
429  * \param need_lock
430  * Stop the recording, close any open streams, mix in/out channels if required
431  * \return Always 0
432 */
433 int AST_OPTIONAL_API_NAME(ast_monitor_stop)(struct ast_channel *chan, int need_lock)
434 {
435         int delfiles = 0;
436
437         LOCK_IF_NEEDED(chan, need_lock);
438
439         if (chan->monitor) {
440                 char filename[ FILENAME_MAX ];
441
442                 if (chan->monitor->read_stream) {
443                         ast_closestream(chan->monitor->read_stream);
444                 }
445                 if (chan->monitor->write_stream) {
446                         ast_closestream(chan->monitor->write_stream);
447                 }
448
449                 if (chan->monitor->filename_changed && !ast_strlen_zero(chan->monitor->filename_base)) {
450                         if (ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0) {
451                                 snprintf(filename, FILENAME_MAX, "%s-in", chan->monitor->filename_base);
452                                 if (ast_fileexists(filename, NULL, NULL) > 0) {
453                                         ast_filedelete(filename, NULL);
454                                 }
455                                 ast_filerename(chan->monitor->read_filename, filename, chan->monitor->format);
456                         } else {
457                                 ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->read_filename);
458                         }
459
460                         if (ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) {
461                                 snprintf(filename, FILENAME_MAX, "%s-out", chan->monitor->filename_base);
462                                 if (ast_fileexists(filename, NULL, NULL) > 0) {
463                                         ast_filedelete(filename, NULL);
464                                 }
465                                 ast_filerename(chan->monitor->write_filename, filename, chan->monitor->format);
466                         } else {
467                                 ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->write_filename);
468                         }
469                 }
470
471                 if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) {
472                         char tmp[1024];
473                         char tmp2[1024];
474                         const char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format;
475                         char *fname_base = chan->monitor->filename_base;
476                         const char *execute, *execute_args;
477                         /* at this point, fname_base really is the full path */
478
479                         /* Set the execute application */
480                         execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC");
481                         if (ast_strlen_zero(execute)) {
482 #ifdef HAVE_SOXMIX
483                                 execute = "nice -n 19 soxmix";
484 #else
485                                 execute = "nice -n 19 sox -m";
486 #endif
487                                 format = get_soxmix_format(format);
488                                 delfiles = 1;
489                         } 
490                         execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS");
491                         if (ast_strlen_zero(execute_args)) {
492                                 execute_args = "";
493                         }
494                         
495                         snprintf(tmp, sizeof(tmp), "%s \"%s-in.%s\" \"%s-out.%s\" \"%s.%s\" %s &",
496                                 execute, fname_base, format, fname_base, format, fname_base, format,execute_args);
497                         if (delfiles) {
498                                 snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s-\"* ) &",tmp, fname_base); /* remove legs when done mixing */
499                                 ast_copy_string(tmp, tmp2, sizeof(tmp));
500                         }
501                         ast_debug(1,"monitor executing %s\n",tmp);
502                         if (ast_safe_system(tmp) == -1)
503                                 ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
504                 }
505                 
506                 ast_free(chan->monitor->format);
507                 ast_free(chan->monitor);
508                 chan->monitor = NULL;
509
510                 ast_manager_event(chan, EVENT_FLAG_CALL, "MonitorStop",
511                                         "Channel: %s\r\n"
512                                 "Uniqueid: %s\r\n",
513                                 ast_channel_name(chan),
514                                 ast_channel_uniqueid(chan)
515                                 );
516                 pbx_builtin_setvar_helper(chan, "MONITORED", NULL);
517         }
518         pbx_builtin_setvar_helper(chan, "AUTO_MONITOR", NULL);
519
520         UNLOCK_IF_NEEDED(chan, need_lock);
521
522         return 0;
523 }
524
525
526 /*! \brief Pause monitoring of channel */
527 int AST_OPTIONAL_API_NAME(ast_monitor_pause)(struct ast_channel *chan)
528 {
529         return ast_monitor_set_state(chan, AST_MONITOR_PAUSED);
530 }
531
532 /*! \brief Unpause monitoring of channel */
533 int AST_OPTIONAL_API_NAME(ast_monitor_unpause)(struct ast_channel *chan)
534 {
535         return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
536 }
537
538 /*! \brief Wrapper for ast_monitor_pause */
539 static int pause_monitor_exec(struct ast_channel *chan, const char *data)
540 {
541         return ast_monitor_pause(chan);
542 }
543
544 /*! \brief Wrapper for ast_monitor_unpause */
545 static int unpause_monitor_exec(struct ast_channel *chan, const char *data)
546 {
547         return ast_monitor_unpause(chan);
548 }
549
550 /*! 
551  * \brief Change monitored filename of channel 
552  * \param chan
553  * \param fname_base new filename
554  * \param need_lock
555  * \retval 0 on success.
556  * \retval -1 on failure.
557 */
558 int AST_OPTIONAL_API_NAME(ast_monitor_change_fname)(struct ast_channel *chan, const char *fname_base, int need_lock)
559 {
560         if (ast_strlen_zero(fname_base)) {
561                 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null\n", ast_channel_name(chan));
562                 return -1;
563         }
564
565         LOCK_IF_NEEDED(chan, need_lock);
566
567         if (chan->monitor) {
568                 int directory = strchr(fname_base, '/') ? 1 : 0;
569                 const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR;
570                 const char *absolute_suffix = *fname_base == '/' ? "" : "/";
571                 char tmpstring[sizeof(chan->monitor->filename_base)] = "";
572                 int i, fd[2] = { -1, -1 }, doexit = 0;
573
574                 /* before continuing, see if we're trying to rename the file to itself... */
575                 snprintf(tmpstring, sizeof(tmpstring), "%s%s%s", absolute, absolute_suffix, fname_base);
576
577                 /* try creating the directory just in case it doesn't exist */
578                 if (directory) {
579                         char *name = ast_strdupa(tmpstring);
580                         ast_mkdir(dirname(name), 0777);
581                 }
582
583                 /*!\note We cannot just compare filenames, due to symlinks, relative
584                  * paths, and other possible filesystem issues.  We could use
585                  * realpath(3), but its use is discouraged.  However, if we try to
586                  * create the same file from two different paths, the second will
587                  * fail, and so we have our notification that the filenames point to
588                  * the same path.
589                  *
590                  * Remember, also, that we're using the basename of the file (i.e.
591                  * the file without the format suffix), so it does not already exist
592                  * and we aren't interfering with the recording itself.
593                  */
594                 ast_debug(2, "comparing tmpstring %s to filename_base %s\n", tmpstring, chan->monitor->filename_base);
595                 
596                 if ((fd[0] = open(tmpstring, O_CREAT | O_WRONLY, 0644)) < 0 ||
597                         (fd[1] = open(chan->monitor->filename_base, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) {
598                         if (fd[0] < 0) {
599                                 ast_log(LOG_ERROR, "Unable to compare filenames: %s\n", strerror(errno));
600                         } else {
601                                 ast_debug(2, "No need to rename monitor filename to itself\n");
602                         }
603                         doexit = 1;
604                 }
605
606                 /* Cleanup temporary files */
607                 for (i = 0; i < 2; i++) {
608                         if (fd[i] >= 0) {
609                                 while (close(fd[i]) < 0 && errno == EINTR);
610                         }
611                 }
612                 unlink(tmpstring);
613                 /* if previous monitor file existed in a subdirectory, the directory will not be removed */
614                 unlink(chan->monitor->filename_base);
615
616                 if (doexit) {
617                         UNLOCK_IF_NEEDED(chan, need_lock);
618                         return 0;
619                 }
620
621                 ast_copy_string(chan->monitor->filename_base, tmpstring, sizeof(chan->monitor->filename_base));
622                 chan->monitor->filename_changed = 1;
623         } else {
624                 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", ast_channel_name(chan), fname_base);
625         }
626
627         UNLOCK_IF_NEEDED(chan, need_lock);
628
629         return 0;
630 }
631
632  
633 /*!
634  * \brief Start monitor
635  * \param chan
636  * \param data arguments passed fname|options
637  * \retval 0 on success.
638  * \retval -1 on failure.
639 */
640 static int start_monitor_exec(struct ast_channel *chan, const char *data)
641 {
642         char *arg = NULL;
643         char *options = NULL;
644         char *delay = NULL;
645         char *urlprefix = NULL;
646         char tmp[256];
647         int stream_action = X_REC_IN | X_REC_OUT;
648         int joinfiles = 0;
649         int waitforbridge = 0;
650         int res = 0;
651         char *parse;
652         AST_DECLARE_APP_ARGS(args,
653                 AST_APP_ARG(format);
654                 AST_APP_ARG(fname_base);
655                 AST_APP_ARG(options);
656         );
657         
658         /* Parse arguments. */
659         if (ast_strlen_zero(data)) {
660                 ast_log(LOG_ERROR, "Monitor requires an argument\n");
661                 return 0;
662         }
663
664         parse = ast_strdupa(data);
665         AST_STANDARD_APP_ARGS(args, parse);
666
667         if (!ast_strlen_zero(args.options)) {
668                 if (strchr(args.options, 'm'))
669                         stream_action |= X_JOIN;
670                 if (strchr(args.options, 'b'))
671                         waitforbridge = 1;
672                 if (strchr(args.options, 'i'))
673                         stream_action &= ~X_REC_IN;
674                 if (strchr(args.options, 'o'))
675                         stream_action &= ~X_REC_OUT;
676         }
677
678         arg = strchr(args.format, ':');
679         if (arg) {
680                 *arg++ = 0;
681                 urlprefix = arg;
682         }
683
684         if (urlprefix) {
685                 snprintf(tmp, sizeof(tmp), "%s/%s.%s", urlprefix, args.fname_base,
686                         ((strcmp(args.format, "gsm")) ? "wav" : "gsm"));
687                 ast_channel_lock(chan);
688                 if (!chan->cdr && !(chan->cdr = ast_cdr_alloc())) {
689                         ast_channel_unlock(chan);
690                         return -1;
691                 }
692                 ast_cdr_setuserfield(chan, tmp);
693                 ast_channel_unlock(chan);
694         }
695         if (waitforbridge) {
696                 /* We must remove the "b" option if listed.  In principle none of
697                    the following could give NULL results, but we check just to
698                    be pedantic. Reconstructing with checks for 'm' option does not
699                    work if we end up adding more options than 'm' in the future. */
700                 delay = ast_strdupa(data);
701                 options = strrchr(delay, ',');
702                 if (options) {
703                         arg = strchr(options, 'b');
704                         if (arg) {
705                                 *arg = 'X';
706                                 pbx_builtin_setvar_helper(chan,"AUTO_MONITOR", delay);
707                         }
708                 }
709                 return 0;
710         }
711
712         res = ast_monitor_start(chan, args.format, args.fname_base, 1, stream_action);
713         if (res < 0)
714                 res = ast_monitor_change_fname(chan, args.fname_base, 1);
715
716         if (stream_action & X_JOIN) {
717                 if ((stream_action & X_REC_IN) && (stream_action & X_REC_OUT))
718                         joinfiles = 1;
719                 else
720                         ast_log(LOG_WARNING, "Won't mix streams unless both input and output streams are recorded\n");
721         }
722         ast_monitor_setjoinfiles(chan, joinfiles);
723
724         return res;
725 }
726
727 /*! \brief Wrapper function \see ast_monitor_stop */
728 static int stop_monitor_exec(struct ast_channel *chan, const char *data)
729 {
730         return ast_monitor_stop(chan, 1);
731 }
732
733 /*! \brief Wrapper function \see ast_monitor_change_fname */
734 static int change_monitor_exec(struct ast_channel *chan, const char *data)
735 {
736         return ast_monitor_change_fname(chan, data, 1);
737 }
738
739 /*! \brief Start monitoring a channel by manager connection */
740 static int start_monitor_action(struct mansession *s, const struct message *m)
741 {
742         struct ast_channel *c = NULL;
743         const char *name = astman_get_header(m, "Channel");
744         const char *fname = astman_get_header(m, "File");
745         const char *format = astman_get_header(m, "Format");
746         const char *mix = astman_get_header(m, "Mix");
747         char *d;
748
749         if (ast_strlen_zero(name)) {
750                 astman_send_error(s, m, "No channel specified");
751                 return 0;
752         }
753
754         if (!(c = ast_channel_get_by_name(name))) {
755                 astman_send_error(s, m, "No such channel");
756                 return 0;
757         }
758
759         if (ast_strlen_zero(fname)) {
760                 /* No filename base specified, default to channel name as per CLI */
761                 ast_channel_lock(c);
762                 fname = ast_strdupa(ast_channel_name(c));
763                 ast_channel_unlock(c);
764                 /* Channels have the format technology/channel_name - have to replace that /  */
765                 if ((d = strchr(fname, '/'))) {
766                         *d = '-';
767                 }
768         }
769
770         if (ast_monitor_start(c, format, fname, 1, X_REC_IN | X_REC_OUT)) {
771                 if (ast_monitor_change_fname(c, fname, 1)) {
772                         astman_send_error(s, m, "Could not start monitoring channel");
773                         c = ast_channel_unref(c);
774                         return 0;
775                 }
776         }
777
778         if (ast_true(mix)) {
779                 ast_channel_lock(c);
780                 ast_monitor_setjoinfiles(c, 1);
781                 ast_channel_unlock(c);
782         }
783
784         c = ast_channel_unref(c);
785
786         astman_send_ack(s, m, "Started monitoring channel");
787
788         return 0;
789 }
790
791 /*! \brief Stop monitoring a channel by manager connection */
792 static int stop_monitor_action(struct mansession *s, const struct message *m)
793 {
794         struct ast_channel *c = NULL;
795         const char *name = astman_get_header(m, "Channel");
796         int res;
797
798         if (ast_strlen_zero(name)) {
799                 astman_send_error(s, m, "No channel specified");
800                 return 0;
801         }
802
803         if (!(c = ast_channel_get_by_name(name))) {
804                 astman_send_error(s, m, "No such channel");
805                 return 0;
806         }
807
808         res = ast_monitor_stop(c, 1);
809
810         c = ast_channel_unref(c);
811
812         if (res) {
813                 astman_send_error(s, m, "Could not stop monitoring channel");
814                 return 0;
815         }
816
817         astman_send_ack(s, m, "Stopped monitoring channel");
818
819         return 0;
820 }
821
822 /*! \brief Change filename of a monitored channel by manager connection */
823 static int change_monitor_action(struct mansession *s, const struct message *m)
824 {
825         struct ast_channel *c = NULL;
826         const char *name = astman_get_header(m, "Channel");
827         const char *fname = astman_get_header(m, "File");
828
829         if (ast_strlen_zero(name)) {
830                 astman_send_error(s, m, "No channel specified");
831                 return 0;
832         }
833
834         if (ast_strlen_zero(fname)) {
835                 astman_send_error(s, m, "No filename specified");
836                 return 0;
837         }
838
839         if (!(c = ast_channel_get_by_name(name))) {
840                 astman_send_error(s, m, "No such channel");
841                 return 0;
842         }
843
844         if (ast_monitor_change_fname(c, fname, 1)) {
845                 c = ast_channel_unref(c);
846                 astman_send_error(s, m, "Could not change monitored filename of channel");
847                 return 0;
848         }
849
850         c = ast_channel_unref(c);
851
852         astman_send_ack(s, m, "Changed monitor filename");
853
854         return 0;
855 }
856
857 void AST_OPTIONAL_API_NAME(ast_monitor_setjoinfiles)(struct ast_channel *chan, int turnon)
858 {
859         if (chan->monitor)
860                 chan->monitor->joinfiles = turnon;
861 }
862
863 enum MONITOR_PAUSING_ACTION
864 {
865         MONITOR_ACTION_PAUSE,
866         MONITOR_ACTION_UNPAUSE
867 };
868  
869 static int do_pause_or_unpause(struct mansession *s, const struct message *m, int action)
870 {
871         struct ast_channel *c = NULL;
872         const char *name = astman_get_header(m, "Channel");
873
874         if (ast_strlen_zero(name)) {
875                 astman_send_error(s, m, "No channel specified");
876                 return -1;
877         }
878
879         if (!(c = ast_channel_get_by_name(name))) {
880                 astman_send_error(s, m, "No such channel");
881                 return -1;
882         }
883
884         if (action == MONITOR_ACTION_PAUSE) {
885                 ast_monitor_pause(c);
886         } else {
887                 ast_monitor_unpause(c);
888         }
889
890         c = ast_channel_unref(c);
891
892         astman_send_ack(s, m, (action == MONITOR_ACTION_PAUSE ? "Paused monitoring of the channel" : "Unpaused monitoring of the channel"));
893
894         return 0;
895 }
896
897 static int pause_monitor_action(struct mansession *s, const struct message *m)
898 {
899         return do_pause_or_unpause(s, m, MONITOR_ACTION_PAUSE);
900 }
901
902 static int unpause_monitor_action(struct mansession *s, const struct message *m)
903 {
904         return do_pause_or_unpause(s, m, MONITOR_ACTION_UNPAUSE);
905 }
906         
907
908 static int load_module(void)
909 {
910         ast_register_application_xml("Monitor", start_monitor_exec);
911         ast_register_application_xml("StopMonitor", stop_monitor_exec);
912         ast_register_application_xml("ChangeMonitor", change_monitor_exec);
913         ast_register_application_xml("PauseMonitor", pause_monitor_exec);
914         ast_register_application_xml("UnpauseMonitor", unpause_monitor_exec);
915         ast_manager_register_xml("Monitor", EVENT_FLAG_CALL, start_monitor_action);
916         ast_manager_register_xml("StopMonitor", EVENT_FLAG_CALL, stop_monitor_action);
917         ast_manager_register_xml("ChangeMonitor", EVENT_FLAG_CALL, change_monitor_action);
918         ast_manager_register_xml("PauseMonitor", EVENT_FLAG_CALL, pause_monitor_action);
919         ast_manager_register_xml("UnpauseMonitor", EVENT_FLAG_CALL, unpause_monitor_action);
920
921         return AST_MODULE_LOAD_SUCCESS;
922 }
923
924 static int unload_module(void)
925 {
926         ast_unregister_application("Monitor");
927         ast_unregister_application("StopMonitor");
928         ast_unregister_application("ChangeMonitor");
929         ast_unregister_application("PauseMonitor");
930         ast_unregister_application("UnpauseMonitor");
931         ast_manager_unregister("Monitor");
932         ast_manager_unregister("StopMonitor");
933         ast_manager_unregister("ChangeMonitor");
934         ast_manager_unregister("PauseMonitor");
935         ast_manager_unregister("UnpauseMonitor");
936
937         return 0;
938 }
939
940 /* usecount semantics need to be defined */
941 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Call Monitoring Resource",
942                 .load = load_module,
943                 .unload = unload_module,
944                 .load_pri = AST_MODPRI_CHANNEL_DEPEND,
945                 );