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