since the module API is changing, it's a good time to const-ify the description(...
[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 <stdio.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <libgen.h>             /* dirname() */
33
34 #define STATIC_MODULE
35
36 #include "asterisk.h"
37
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
39
40 #include "asterisk/lock.h"
41 #include "asterisk/channel.h"
42 #include "asterisk/logger.h"
43 #include "asterisk/file.h"
44 #include "asterisk/pbx.h"
45 #include "asterisk/module.h"
46 #include "asterisk/manager.h"
47 #include "asterisk/cli.h"
48 #include "asterisk/monitor.h"
49 #include "asterisk/app.h"
50 #include "asterisk/utils.h"
51 #include "asterisk/config.h"
52
53 AST_MUTEX_DEFINE_STATIC(monitorlock);
54
55 #define LOCK_IF_NEEDED(lock, needed)                                                            \
56         do {                                                                                                                    \
57                 if (needed) {                                                                                           \
58                         if (ast_mutex_lock(lock)) {                                                             \
59                                 ast_log(LOG_WARNING, "Unable to lock channel\n");       \
60                                 return -1;                                                                                      \
61                         }                                                                                                               \
62                 }                                                                                                                       \
63         } while(0)
64
65 #define UNLOCK_IF_NEEDED(lock, needed)                  \
66         do {                                                                            \
67                 if (needed) {                                                   \
68                         ast_mutex_unlock(lock);                         \
69                 }                                                                               \
70         } while(0)                                                                      \
71
72 static unsigned long seq = 0;
73
74 static char *monitor_synopsis = "Monitor a channel";
75
76 static char *monitor_descrip = "Monitor([file_format[:urlbase]|[fname_base]|[options]]):\n"
77 "Used to start monitoring a channel. The channel's input and output\n"
78 "voice packets are logged to files until the channel hangs up or\n"
79 "monitoring is stopped by the StopMonitor application.\n"
80 "  file_format          optional, if not set, defaults to \"wav\"\n"
81 "  fname_base           if set, changes the filename used to the one specified.\n"
82 "  options:\n"
83 "    m   - when the recording ends mix the two leg files into one and\n"
84 "          delete the two leg files.  If the variable MONITOR_EXEC is set, the\n"
85 "          application referenced in it will be executed instead of\n"
86 "          soxmix and the raw leg files will NOT be deleted automatically.\n"
87 "          soxmix or MONITOR_EXEC is handed 3 arguments, the two leg files\n"
88 "          and a target mixed file name which is the same as the leg file names\n"
89 "          only without the in/out designator.\n"
90 "          If MONITOR_EXEC_ARGS is set, the contents will be passed on as\n"
91 "          additional arguements to MONITOR_EXEC\n"
92 "          Both MONITOR_EXEC and the Mix flag can be set from the\n"
93 "          administrator interface\n"
94 "\n"
95 "    b   - Don't begin recording unless a call is bridged to another channel\n"
96 "\nReturns -1 if monitor files can't be opened or if the channel is already\n"
97 "monitored, otherwise 0.\n"
98 ;
99
100 static char *stopmonitor_synopsis = "Stop monitoring a channel";
101
102 static char *stopmonitor_descrip = "StopMonitor\n"
103         "Stops monitoring a channel. Has no effect if the channel is not monitored\n";
104
105 static char *changemonitor_synopsis = "Change monitoring filename of a channel";
106
107 static char *changemonitor_descrip = "ChangeMonitor(filename_base)\n"
108         "Changes monitoring filename of a channel. Has no effect if the channel is not monitored\n"
109         "The argument is the new filename base to use for monitoring this channel.\n";
110
111 static char *pausemonitor_synopsis = "Pause monitoring of a channel";
112
113 static char *pausemonitor_descrip = "PauseMonitor\n"
114         "Pauses monitoring of a channel until it is re-enabled by a call to UnpauseMonitor.\n";
115
116 static char *unpausemonitor_synopsis = "Unpause monitoring of a channel";
117
118 static char *unpausemonitor_descrip = "UnpauseMonitor\n"
119         "Unpauses monitoring of a channel on which monitoring had\n"
120         "previously been paused with PauseMonitor.\n";
121
122 static int ast_monitor_set_state(struct ast_channel *chan, int state)
123 {
124         LOCK_IF_NEEDED(&chan->lock, 1);
125         if (!chan->monitor) {
126                 UNLOCK_IF_NEEDED(&chan->lock, 1);
127                 return -1;
128         }
129         chan->monitor->state = state;
130         UNLOCK_IF_NEEDED(&chan->lock, 1);
131         return 0;
132 }
133
134 /* Start monitoring a channel */
135 int ast_monitor_start(  struct ast_channel *chan, const char *format_spec,
136                 const char *fname_base, int need_lock)
137 {
138         int res = 0;
139         char tmp[256];
140
141         LOCK_IF_NEEDED(&chan->lock, need_lock);
142
143         if (!(chan->monitor)) {
144                 struct ast_channel_monitor *monitor;
145                 char *channel_name, *p;
146
147                 /* Create monitoring directory if needed */
148                 if (mkdir(ast_config_AST_MONITOR_DIR, 0770) < 0) {
149                         if (errno != EEXIST) {
150                                 ast_log(LOG_WARNING, "Unable to create audio monitor directory: %s\n",
151                                         strerror(errno));
152                         }
153                 }
154
155                 if (!(monitor = ast_calloc(1, sizeof(*monitor)))) {
156                         UNLOCK_IF_NEEDED(&chan->lock, need_lock);
157                         return -1;
158                 }
159
160                 /* Determine file names */
161                 if (!ast_strlen_zero(fname_base)) {
162                         int directory = strchr(fname_base, '/') ? 1 : 0;
163                         /* try creating the directory just in case it doesn't exist */
164                         if (directory) {
165                                 char *name = strdup(fname_base);
166                                 snprintf(tmp, sizeof(tmp), "mkdir -p \"%s\"",dirname(name));
167                                 free(name);
168                                 ast_safe_system(tmp);
169                         }
170                         snprintf(monitor->read_filename, FILENAME_MAX, "%s/%s-in",
171                                                 directory ? "" : ast_config_AST_MONITOR_DIR, fname_base);
172                         snprintf(monitor->write_filename, FILENAME_MAX, "%s/%s-out",
173                                                 directory ? "" : ast_config_AST_MONITOR_DIR, fname_base);
174                         ast_copy_string(monitor->filename_base, fname_base, sizeof(monitor->filename_base));
175                 } else {
176                         ast_mutex_lock(&monitorlock);
177                         snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%ld",
178                                                 ast_config_AST_MONITOR_DIR, seq);
179                         snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%ld",
180                                                 ast_config_AST_MONITOR_DIR, seq);
181                         seq++;
182                         ast_mutex_unlock(&monitorlock);
183
184                         if((channel_name = ast_strdupa(chan->name))) {
185                                 while((p = strchr(channel_name, '/'))) {
186                                         *p = '-';
187                                 }
188                                 snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
189                                                  ast_config_AST_MONITOR_DIR, (int)time(NULL),channel_name);
190                                 monitor->filename_changed = 1;
191                         } else {
192                                 ast_log(LOG_ERROR,"Failed to allocate Memory\n");
193                                 return -1;
194                         }
195                 }
196
197                 monitor->stop = ast_monitor_stop;
198
199                 /* Determine file format */
200                 if (!ast_strlen_zero(format_spec)) {
201                         monitor->format = strdup(format_spec);
202                 } else {
203                         monitor->format = strdup("wav");
204                 }
205                 
206                 /* open files */
207                 if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0) {
208                         ast_filedelete(monitor->read_filename, NULL);
209                 }
210                 if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
211                                                 monitor->format, NULL,
212                                                 O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) {
213                         ast_log(LOG_WARNING, "Could not create file %s\n",
214                                                 monitor->read_filename);
215                         free(monitor);
216                         ast_mutex_unlock(&chan->lock);
217                         return -1;
218                 }
219                 if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
220                         ast_filedelete(monitor->write_filename, NULL);
221                 }
222                 if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
223                                                 monitor->format, NULL,
224                                                 O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) {
225                         ast_log(LOG_WARNING, "Could not create file %s\n",
226                                                 monitor->write_filename);
227                         ast_closestream(monitor->read_stream);
228                         free(monitor);
229                         ast_mutex_unlock(&chan->lock);
230                         return -1;
231                 }
232                 chan->monitor = monitor;
233                 ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
234                 /* so we know this call has been monitored in case we need to bill for it or something */
235                 pbx_builtin_setvar_helper(chan, "__MONITORED","true");
236         } else {
237                 ast_log(LOG_DEBUG,"Cannot start monitoring %s, already monitored\n",
238                                         chan->name);
239                 res = -1;
240         }
241
242         UNLOCK_IF_NEEDED(&chan->lock, need_lock);
243
244         return res;
245 }
246
247 /* Stop monitoring a channel */
248 int ast_monitor_stop(struct ast_channel *chan, int need_lock)
249 {
250         int delfiles = 0;
251
252         LOCK_IF_NEEDED(&chan->lock, need_lock);
253
254         if (chan->monitor) {
255                 char filename[ FILENAME_MAX ];
256
257                 if (chan->monitor->read_stream) {
258                         ast_closestream(chan->monitor->read_stream);
259                 }
260                 if (chan->monitor->write_stream) {
261                         ast_closestream(chan->monitor->write_stream);
262                 }
263
264                 if (chan->monitor->filename_changed && !ast_strlen_zero(chan->monitor->filename_base)) {
265                         if (ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0) {
266                                 snprintf(filename, FILENAME_MAX, "%s-in", chan->monitor->filename_base);
267                                 if (ast_fileexists(filename, NULL, NULL) > 0) {
268                                         ast_filedelete(filename, NULL);
269                                 }
270                                 ast_filerename(chan->monitor->read_filename, filename, chan->monitor->format);
271                         } else {
272                                 ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->read_filename);
273                         }
274
275                         if (ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) {
276                                 snprintf(filename, FILENAME_MAX, "%s-out", chan->monitor->filename_base);
277                                 if (ast_fileexists(filename, NULL, NULL) > 0) {
278                                         ast_filedelete(filename, NULL);
279                                 }
280                                 ast_filerename(chan->monitor->write_filename, filename, chan->monitor->format);
281                         } else {
282                                 ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->write_filename);
283                         }
284                 }
285
286                 if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) {
287                         char tmp[1024];
288                         char tmp2[1024];
289                         char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format;
290                         char *name = chan->monitor->filename_base;
291                         int directory = strchr(name, '/') ? 1 : 0;
292                         char *dir = directory ? "" : ast_config_AST_MONITOR_DIR;
293                         const char *execute, *execute_args;
294
295                         /* Set the execute application */
296                         execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC");
297                         if (ast_strlen_zero(execute)) { 
298                                 execute = "nice -n 19 soxmix";
299                                 delfiles = 1;
300                         } 
301                         execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS");
302                         if (ast_strlen_zero(execute_args)) {
303                                 execute_args = "";
304                         }
305                         
306                         snprintf(tmp, sizeof(tmp), "%s \"%s/%s-in.%s\" \"%s/%s-out.%s\" \"%s/%s.%s\" %s &", execute, dir, name, format, dir, name, format, dir, name, format,execute_args);
307                         if (delfiles) {
308                                 snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s/%s-\"* ) &",tmp, dir ,name); /* remove legs when done mixing */
309                                 ast_copy_string(tmp, tmp2, sizeof(tmp));
310                         }
311                         ast_log(LOG_DEBUG,"monitor executing %s\n",tmp);
312                         if (ast_safe_system(tmp) == -1)
313                                 ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
314                 }
315                 
316                 free(chan->monitor->format);
317                 free(chan->monitor);
318                 chan->monitor = NULL;
319         }
320
321         UNLOCK_IF_NEEDED(&chan->lock, need_lock);
322
323         return 0;
324 }
325
326
327 /* Pause monitoring of a channel */
328 int ast_monitor_pause(struct ast_channel *chan)
329 {
330         return ast_monitor_set_state(chan, AST_MONITOR_PAUSED);
331 }
332
333 /* Unpause monitoring of a channel */
334 int ast_monitor_unpause(struct ast_channel *chan)
335 {
336         return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
337 }
338
339 int pause_monitor_exec(struct ast_channel *chan, void *data)
340 {
341         return ast_monitor_pause(chan);
342 }
343
344 int unpause_monitor_exec(struct ast_channel *chan, void *data)
345 {
346         return ast_monitor_unpause(chan);
347 }
348
349 /* Change monitoring filename of a channel */
350 int ast_monitor_change_fname(struct ast_channel *chan, const char *fname_base, int need_lock)
351 {
352         char tmp[256];
353         if (ast_strlen_zero(fname_base)) {
354                 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null", chan->name);
355                 return -1;
356         }
357
358         LOCK_IF_NEEDED(&chan->lock, need_lock);
359
360         if (chan->monitor) {
361                 int directory = strchr(fname_base, '/') ? 1 : 0;
362                 /* try creating the directory just in case it doesn't exist */
363                 if (directory) {
364                         char *name = strdup(fname_base);
365                         snprintf(tmp, sizeof(tmp), "mkdir -p %s",dirname(name));
366                         free(name);
367                         ast_safe_system(tmp);
368                 }
369
370                 snprintf(chan->monitor->filename_base, FILENAME_MAX, "%s/%s", directory ? "" : ast_config_AST_MONITOR_DIR, fname_base);
371         } else {
372                 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", chan->name, fname_base);
373         }
374
375         UNLOCK_IF_NEEDED(&chan->lock, need_lock);
376
377         return 0;
378 }
379
380 static int start_monitor_exec(struct ast_channel *chan, void *data)
381 {
382         char *arg = NULL;
383         char *format = NULL;
384         char *fname_base = NULL;
385         char *options = NULL;
386         char *delay = NULL;
387         char *urlprefix = NULL;
388         char tmp[256];
389         int joinfiles = 0;
390         int waitforbridge = 0;
391         int res = 0;
392         
393         /* Parse arguments. */
394         if (!ast_strlen_zero((char*)data)) {
395                 arg = ast_strdupa((char*)data);
396                 format = arg;
397                 fname_base = strchr(arg, '|');
398                 if (fname_base) {
399                         *fname_base = 0;
400                         fname_base++;
401                         if ((options = strchr(fname_base, '|'))) {
402                                 *options = 0;
403                                 options++;
404                                 if (strchr(options, 'm'))
405                                         joinfiles = 1;
406                                 if (strchr(options, 'b'))
407                                         waitforbridge = 1;
408                         }
409                 }
410                 arg = strchr(format,':');
411                 if (arg) {
412                         *arg++ = 0;
413                         urlprefix = arg;
414                 }
415         }
416         if (urlprefix) {
417                 snprintf(tmp,sizeof(tmp) - 1,"%s/%s.%s",urlprefix,fname_base,
418                         ((strcmp(format,"gsm")) ? "wav" : "gsm"));
419                 if (!chan->cdr && !(chan->cdr = ast_cdr_alloc()))
420                         return -1;
421                 ast_cdr_setuserfield(chan, tmp);
422         }
423         if (waitforbridge) {
424                 /* We must remove the "b" option if listed.  In principle none of
425                    the following could give NULL results, but we check just to
426                    be pedantic. Reconstructing with checks for 'm' option does not
427                    work if we end up adding more options than 'm' in the future. */
428                 delay = ast_strdupa((char*)data);
429                 if (delay) {
430                         options = strrchr(delay, '|');
431                         if (options) {
432                                 arg = strchr(options, 'b');
433                                 if (arg) {
434                                         *arg = 'X';
435                                         pbx_builtin_setvar_helper(chan,"AUTO_MONITOR",delay);
436                                 }
437                         }
438                 }
439                 return 0;
440         }
441
442         res = ast_monitor_start(chan, format, fname_base, 1);
443         if (res < 0)
444                 res = ast_monitor_change_fname(chan, fname_base, 1);
445         ast_monitor_setjoinfiles(chan, joinfiles);
446
447         return res;
448 }
449
450 static int stop_monitor_exec(struct ast_channel *chan, void *data)
451 {
452         return ast_monitor_stop(chan, 1);
453 }
454
455 static int change_monitor_exec(struct ast_channel *chan, void *data)
456 {
457         return ast_monitor_change_fname(chan, (const char*)data, 1);
458 }
459
460 static char start_monitor_action_help[] =
461 "Description: The 'Monitor' action may be used to record the audio on a\n"
462 "  specified channel.  The following parameters may be used to control\n"
463 "  this:\n"
464 "  Channel     - Required.  Used to specify the channel to record.\n"
465 "  File        - Optional.  Is the name of the file created in the\n"
466 "                monitor spool directory.  Defaults to the same name\n"
467 "                as the channel (with slashes replaced with dashes).\n"
468 "  Format      - Optional.  Is the audio recording format.  Defaults\n"
469 "                to \"wav\".\n"
470 "  Mix         - Optional.  Boolean parameter as to whether to mix\n"
471 "                the input and output channels together after the\n"
472 "                recording is finished.\n";
473
474 static int start_monitor_action(struct mansession *s, struct message *m)
475 {
476         struct ast_channel *c = NULL;
477         char *name = astman_get_header(m, "Channel");
478         char *fname = astman_get_header(m, "File");
479         char *format = astman_get_header(m, "Format");
480         char *mix = astman_get_header(m, "Mix");
481         char *d;
482         
483         if (ast_strlen_zero(name)) {
484                 astman_send_error(s, m, "No channel specified");
485                 return 0;
486         }
487         c = ast_get_channel_by_name_locked(name);
488         if (!c) {
489                 astman_send_error(s, m, "No such channel");
490                 return 0;
491         }
492
493         if (ast_strlen_zero(fname)) {
494                 /* No filename base specified, default to channel name as per CLI */            
495                 if (!(fname = ast_strdup(c->name))) {
496                         astman_send_error(s, m, "Could not start monitoring channel");
497                         ast_mutex_unlock(&c->lock);
498                         return 0;
499                 }
500                 /* Channels have the format technology/channel_name - have to replace that /  */
501                 if ((d = strchr(fname, '/'))) 
502                         *d = '-';
503         }
504         
505         if (ast_monitor_start(c, format, fname, 1)) {
506                 if (ast_monitor_change_fname(c, fname, 1)) {
507                         astman_send_error(s, m, "Could not start monitoring channel");
508                         ast_mutex_unlock(&c->lock);
509                         return 0;
510                 }
511         }
512
513         if (ast_true(mix)) {
514                 ast_monitor_setjoinfiles(c, 1);
515         }
516
517         ast_mutex_unlock(&c->lock);
518         astman_send_ack(s, m, "Started monitoring channel");
519         return 0;
520 }
521
522 static char stop_monitor_action_help[] =
523 "Description: The 'StopMonitor' action may be used to end a previously\n"
524 "  started 'Monitor' action.  The only parameter is 'Channel', the name\n"
525 "  of the channel monitored.\n";
526
527 static int stop_monitor_action(struct mansession *s, struct message *m)
528 {
529         struct ast_channel *c = NULL;
530         char *name = astman_get_header(m, "Channel");
531         int res;
532         if (ast_strlen_zero(name)) {
533                 astman_send_error(s, m, "No channel specified");
534                 return 0;
535         }
536         c = ast_get_channel_by_name_locked(name);
537         if (!c) {
538                 astman_send_error(s, m, "No such channel");
539                 return 0;
540         }
541         res = ast_monitor_stop(c, 1);
542         ast_mutex_unlock(&c->lock);
543         if (res) {
544                 astman_send_error(s, m, "Could not stop monitoring channel");
545                 return 0;
546         }
547         astman_send_ack(s, m, "Stopped monitoring channel");
548         return 0;
549 }
550
551 static char change_monitor_action_help[] =
552 "Description: The 'ChangeMonitor' action may be used to change the file\n"
553 "  started by a previous 'Monitor' action.  The following parameters may\n"
554 "  be used to control this:\n"
555 "  Channel     - Required.  Used to specify the channel to record.\n"
556 "  File        - Required.  Is the new name of the file created in the\n"
557 "                monitor spool directory.\n";
558
559 static int change_monitor_action(struct mansession *s, struct message *m)
560 {
561         struct ast_channel *c = NULL;
562         char *name = astman_get_header(m, "Channel");
563         char *fname = astman_get_header(m, "File");
564         if (ast_strlen_zero(name)) {
565                 astman_send_error(s, m, "No channel specified");
566                 return 0;
567         }
568         if (ast_strlen_zero(fname)) {
569                 astman_send_error(s, m, "No filename specified");
570                 return 0;
571         }
572         c = ast_get_channel_by_name_locked(name);
573         if (!c) {
574                 astman_send_error(s, m, "No such channel");
575                 return 0;
576         }
577         if (ast_monitor_change_fname(c, fname, 1)) {
578                 astman_send_error(s, m, "Could not change monitored filename of channel");
579                 ast_mutex_unlock(&c->lock);
580                 return 0;
581         }
582         ast_mutex_unlock(&c->lock);
583         astman_send_ack(s, m, "Changed monitor filename");
584         return 0;
585 }
586
587 void ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon)
588 {
589         if (chan->monitor)
590                 chan->monitor->joinfiles = turnon;
591 }
592
593 #define IS_NULL_STRING(string) ((!(string)) || (ast_strlen_zero((string))))
594
595 enum MONITOR_PAUSING_ACTION
596 {
597         MONITOR_ACTION_PAUSE,
598         MONITOR_ACTION_UNPAUSE
599 };
600           
601 static int do_pause_or_unpause(struct mansession *s, struct message *m, int action)
602 {
603         struct ast_channel *c = NULL;
604         char *name = astman_get_header(m, "Channel");
605         
606         if (IS_NULL_STRING(name)) {
607                 astman_send_error(s, m, "No channel specified");
608                 return -1;
609         }
610         
611         c = ast_get_channel_by_name_locked(name);
612         if (!c) {
613                 astman_send_error(s, m, "No such channel");
614                 return -1;
615         }
616
617         if (action == MONITOR_ACTION_PAUSE)
618                 ast_monitor_pause(c);
619         else
620                 ast_monitor_unpause(c);
621         
622         ast_mutex_unlock(&c->lock);
623         astman_send_ack(s, m, "Paused monitoring of the channel");
624         return 0;       
625 }
626
627 static char pause_monitor_action_help[] =
628         "Description: The 'PauseMonitor' action may be used to temporarily stop the\n"
629         " recording of a channel.  The following parameters may\n"
630         " be used to control this:\n"
631         "  Channel     - Required.  Used to specify the channel to record.\n";
632
633 static int pause_monitor_action(struct mansession *s, struct message *m)
634 {
635         return do_pause_or_unpause(s, m, MONITOR_ACTION_PAUSE);
636 }
637
638 static char unpause_monitor_action_help[] =
639         "Description: The 'UnpauseMonitor' action may be used to re-enable recording\n"
640         "  of a channel after calling PauseMonitor.  The following parameters may\n"
641         "  be used to control this:\n"
642         "  Channel     - Required.  Used to specify the channel to record.\n";
643
644 static int unpause_monitor_action(struct mansession *s, struct message *m)
645 {
646         return do_pause_or_unpause(s, m, MONITOR_ACTION_UNPAUSE);
647 }
648         
649
650 STATIC_MODULE int load_module(void)
651 {
652         ast_register_application("Monitor", start_monitor_exec, monitor_synopsis, monitor_descrip);
653         ast_register_application("StopMonitor", stop_monitor_exec, stopmonitor_synopsis, stopmonitor_descrip);
654         ast_register_application("ChangeMonitor", change_monitor_exec, changemonitor_synopsis, changemonitor_descrip);
655         ast_register_application("PauseMonitor", pause_monitor_exec, pausemonitor_synopsis, pausemonitor_descrip);
656         ast_register_application("UnpauseMonitor", unpause_monitor_exec, unpausemonitor_synopsis, unpausemonitor_descrip);
657         ast_manager_register2("Monitor", EVENT_FLAG_CALL, start_monitor_action, monitor_synopsis, start_monitor_action_help);
658         ast_manager_register2("StopMonitor", EVENT_FLAG_CALL, stop_monitor_action, stopmonitor_synopsis, stop_monitor_action_help);
659         ast_manager_register2("ChangeMonitor", EVENT_FLAG_CALL, change_monitor_action, changemonitor_synopsis, change_monitor_action_help);
660         ast_manager_register2("PauseMonitor", EVENT_FLAG_CALL, pause_monitor_action, pausemonitor_synopsis, pause_monitor_action_help);
661         ast_manager_register2("UnpauseMonitor", EVENT_FLAG_CALL, unpause_monitor_action, unpausemonitor_synopsis, unpause_monitor_action_help);
662
663         return 0;
664 }
665
666 STATIC_MODULE int unload_module(void)
667 {
668         ast_unregister_application("Monitor");
669         ast_unregister_application("StopMonitor");
670         ast_unregister_application("ChangeMonitor");
671         ast_unregister_application("PauseMonitor");
672         ast_unregister_application("UnpauseMonitor");
673         ast_manager_unregister("Monitor");
674         ast_manager_unregister("StopMonitor");
675         ast_manager_unregister("ChangeMonitor");
676         ast_unregister_application("PauseMonitor");
677         ast_unregister_application("UnpauseMonitor");
678
679         return 0;
680 }
681
682 STATIC_MODULE const char *description(void)
683 {
684         return "Call Monitoring Resource";
685 }
686
687 STATIC_MODULE int usecount(void)
688 {
689         /* Never allow monitor to be unloaded because it will
690            unresolve needed symbols in the channel */
691 #if 0
692         int res;
693         STANDARD_USECOUNT(res);
694         return res;
695 #else
696         return 1;
697 #endif
698 }
699
700 STATIC_MODULE const char *key(void)
701 {
702         return ASTERISK_GPL_KEY;
703 }
704
705 STD_MOD(MOD_0, NULL, NULL, NULL);       /* MOD_0 because it exports some symbols */