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