00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 61961 $")
00029
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <errno.h>
00033 #include <string.h>
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <libgen.h>
00037
00038 #include "asterisk/lock.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/logger.h"
00041 #include "asterisk/file.h"
00042 #include "asterisk/pbx.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/manager.h"
00045 #include "asterisk/cli.h"
00046 #include "asterisk/monitor.h"
00047 #include "asterisk/app.h"
00048 #include "asterisk/utils.h"
00049 #include "asterisk/config.h"
00050
00051 AST_MUTEX_DEFINE_STATIC(monitorlock);
00052
00053 #define LOCK_IF_NEEDED(lock, needed) do { \
00054 if (needed) \
00055 ast_channel_lock(lock); \
00056 } while(0)
00057
00058 #define UNLOCK_IF_NEEDED(lock, needed) do { \
00059 if (needed) \
00060 ast_channel_unlock(lock); \
00061 } while (0)
00062
00063 static unsigned long seq = 0;
00064
00065 static char *monitor_synopsis = "Monitor a channel";
00066
00067 static char *monitor_descrip = "Monitor([file_format[:urlbase]|[fname_base]|[options]]):\n"
00068 "Used to start monitoring a channel. The channel's input and output\n"
00069 "voice packets are logged to files until the channel hangs up or\n"
00070 "monitoring is stopped by the StopMonitor application.\n"
00071 " file_format optional, if not set, defaults to \"wav\"\n"
00072 " fname_base if set, changes the filename used to the one specified.\n"
00073 " options:\n"
00074 " m - when the recording ends mix the two leg files into one and\n"
00075 " delete the two leg files. If the variable MONITOR_EXEC is set, the\n"
00076 " application referenced in it will be executed instead of\n"
00077 " soxmix and the raw leg files will NOT be deleted automatically.\n"
00078 " soxmix or MONITOR_EXEC is handed 3 arguments, the two leg files\n"
00079 " and a target mixed file name which is the same as the leg file names\n"
00080 " only without the in/out designator.\n"
00081 " If MONITOR_EXEC_ARGS is set, the contents will be passed on as\n"
00082 " additional arguements to MONITOR_EXEC\n"
00083 " Both MONITOR_EXEC and the Mix flag can be set from the\n"
00084 " administrator interface\n"
00085 "\n"
00086 " b - Don't begin recording unless a call is bridged to another channel\n"
00087 "\nReturns -1 if monitor files can't be opened or if the channel is already\n"
00088 "monitored, otherwise 0.\n"
00089 ;
00090
00091 static char *stopmonitor_synopsis = "Stop monitoring a channel";
00092
00093 static char *stopmonitor_descrip = "StopMonitor\n"
00094 "Stops monitoring a channel. Has no effect if the channel is not monitored\n";
00095
00096 static char *changemonitor_synopsis = "Change monitoring filename of a channel";
00097
00098 static char *changemonitor_descrip = "ChangeMonitor(filename_base)\n"
00099 "Changes monitoring filename of a channel. Has no effect if the channel is not monitored\n"
00100 "The argument is the new filename base to use for monitoring this channel.\n";
00101
00102 static char *pausemonitor_synopsis = "Pause monitoring of a channel";
00103
00104 static char *pausemonitor_descrip = "PauseMonitor\n"
00105 "Pauses monitoring of a channel until it is re-enabled by a call to UnpauseMonitor.\n";
00106
00107 static char *unpausemonitor_synopsis = "Unpause monitoring of a channel";
00108
00109 static char *unpausemonitor_descrip = "UnpauseMonitor\n"
00110 "Unpauses monitoring of a channel on which monitoring had\n"
00111 "previously been paused with PauseMonitor.\n";
00112
00113 static int ast_monitor_set_state(struct ast_channel *chan, int state)
00114 {
00115 LOCK_IF_NEEDED(chan, 1);
00116 if (!chan->monitor) {
00117 UNLOCK_IF_NEEDED(chan, 1);
00118 return -1;
00119 }
00120 chan->monitor->state = state;
00121 UNLOCK_IF_NEEDED(chan, 1);
00122 return 0;
00123 }
00124
00125
00126 int ast_monitor_start( struct ast_channel *chan, const char *format_spec,
00127 const char *fname_base, int need_lock)
00128 {
00129 int res = 0;
00130 char tmp[256];
00131
00132 LOCK_IF_NEEDED(chan, need_lock);
00133
00134 if (!(chan->monitor)) {
00135 struct ast_channel_monitor *monitor;
00136 char *channel_name, *p;
00137
00138
00139 if (mkdir(ast_config_AST_MONITOR_DIR, 0770) < 0) {
00140 if (errno != EEXIST) {
00141 ast_log(LOG_WARNING, "Unable to create audio monitor directory: %s\n",
00142 strerror(errno));
00143 }
00144 }
00145
00146 if (!(monitor = ast_calloc(1, sizeof(*monitor)))) {
00147 UNLOCK_IF_NEEDED(chan, need_lock);
00148 return -1;
00149 }
00150
00151
00152 if (!ast_strlen_zero(fname_base)) {
00153 int directory = strchr(fname_base, '/') ? 1 : 0;
00154
00155 if (directory) {
00156 char *name = strdup(fname_base);
00157 snprintf(tmp, sizeof(tmp), "mkdir -p \"%s\"",dirname(name));
00158 free(name);
00159 ast_safe_system(tmp);
00160 }
00161 snprintf(monitor->read_filename, FILENAME_MAX, "%s/%s-in",
00162 directory ? "" : ast_config_AST_MONITOR_DIR, fname_base);
00163 snprintf(monitor->write_filename, FILENAME_MAX, "%s/%s-out",
00164 directory ? "" : ast_config_AST_MONITOR_DIR, fname_base);
00165 ast_copy_string(monitor->filename_base, fname_base, sizeof(monitor->filename_base));
00166 } else {
00167 ast_mutex_lock(&monitorlock);
00168 snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%ld",
00169 ast_config_AST_MONITOR_DIR, seq);
00170 snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%ld",
00171 ast_config_AST_MONITOR_DIR, seq);
00172 seq++;
00173 ast_mutex_unlock(&monitorlock);
00174
00175 channel_name = ast_strdupa(chan->name);
00176 while ((p = strchr(channel_name, '/'))) {
00177 *p = '-';
00178 }
00179 snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
00180 ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name);
00181 monitor->filename_changed = 1;
00182 }
00183
00184 monitor->stop = ast_monitor_stop;
00185
00186
00187 if (!ast_strlen_zero(format_spec)) {
00188 monitor->format = strdup(format_spec);
00189 } else {
00190 monitor->format = strdup("wav");
00191 }
00192
00193
00194 if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0) {
00195 ast_filedelete(monitor->read_filename, NULL);
00196 }
00197 if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
00198 monitor->format, NULL,
00199 O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) {
00200 ast_log(LOG_WARNING, "Could not create file %s\n",
00201 monitor->read_filename);
00202 free(monitor);
00203 UNLOCK_IF_NEEDED(chan, need_lock);
00204 return -1;
00205 }
00206 if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
00207 ast_filedelete(monitor->write_filename, NULL);
00208 }
00209 if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
00210 monitor->format, NULL,
00211 O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) {
00212 ast_log(LOG_WARNING, "Could not create file %s\n",
00213 monitor->write_filename);
00214 ast_closestream(monitor->read_stream);
00215 free(monitor);
00216 UNLOCK_IF_NEEDED(chan, need_lock);
00217 return -1;
00218 }
00219 chan->monitor = monitor;
00220 ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
00221
00222 pbx_builtin_setvar_helper(chan, "__MONITORED","true");
00223 } else {
00224 ast_log(LOG_DEBUG,"Cannot start monitoring %s, already monitored\n",
00225 chan->name);
00226 res = -1;
00227 }
00228
00229 UNLOCK_IF_NEEDED(chan, need_lock);
00230
00231 return res;
00232 }
00233
00234
00235
00236
00237
00238
00239 static const char *get_soxmix_format(const char *format)
00240 {
00241 const char *res = format;
00242
00243 if (!strcasecmp(format,"ulaw"))
00244 res = "ul";
00245 if (!strcasecmp(format,"alaw"))
00246 res = "al";
00247
00248 return res;
00249 }
00250
00251
00252 int ast_monitor_stop(struct ast_channel *chan, int need_lock)
00253 {
00254 int delfiles = 0;
00255
00256 LOCK_IF_NEEDED(chan, need_lock);
00257
00258 if (chan->monitor) {
00259 char filename[ FILENAME_MAX ];
00260
00261 if (chan->monitor->read_stream) {
00262 ast_closestream(chan->monitor->read_stream);
00263 }
00264 if (chan->monitor->write_stream) {
00265 ast_closestream(chan->monitor->write_stream);
00266 }
00267
00268 if (chan->monitor->filename_changed && !ast_strlen_zero(chan->monitor->filename_base)) {
00269 if (ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0) {
00270 snprintf(filename, FILENAME_MAX, "%s-in", chan->monitor->filename_base);
00271 if (ast_fileexists(filename, NULL, NULL) > 0) {
00272 ast_filedelete(filename, NULL);
00273 }
00274 ast_filerename(chan->monitor->read_filename, filename, chan->monitor->format);
00275 } else {
00276 ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->read_filename);
00277 }
00278
00279 if (ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) {
00280 snprintf(filename, FILENAME_MAX, "%s-out", chan->monitor->filename_base);
00281 if (ast_fileexists(filename, NULL, NULL) > 0) {
00282 ast_filedelete(filename, NULL);
00283 }
00284 ast_filerename(chan->monitor->write_filename, filename, chan->monitor->format);
00285 } else {
00286 ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->write_filename);
00287 }
00288 }
00289
00290 if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) {
00291 char tmp[1024];
00292 char tmp2[1024];
00293 const char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format;
00294 char *name = chan->monitor->filename_base;
00295 int directory = strchr(name, '/') ? 1 : 0;
00296 char *dir = directory ? "" : ast_config_AST_MONITOR_DIR;
00297 const char *execute, *execute_args;
00298
00299
00300 execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC");
00301 if (ast_strlen_zero(execute)) {
00302 execute = "nice -n 19 soxmix";
00303 format = get_soxmix_format(format);
00304 delfiles = 1;
00305 }
00306 execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS");
00307 if (ast_strlen_zero(execute_args)) {
00308 execute_args = "";
00309 }
00310
00311 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);
00312 if (delfiles) {
00313 snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s/%s-\"* ) &",tmp, dir ,name);
00314 ast_copy_string(tmp, tmp2, sizeof(tmp));
00315 }
00316 ast_log(LOG_DEBUG,"monitor executing %s\n",tmp);
00317 if (ast_safe_system(tmp) == -1)
00318 ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
00319 }
00320
00321 free(chan->monitor->format);
00322 free(chan->monitor);
00323 chan->monitor = NULL;
00324 }
00325
00326 UNLOCK_IF_NEEDED(chan, need_lock);
00327
00328 return 0;
00329 }
00330
00331
00332
00333 int ast_monitor_pause(struct ast_channel *chan)
00334 {
00335 return ast_monitor_set_state(chan, AST_MONITOR_PAUSED);
00336 }
00337
00338
00339 int ast_monitor_unpause(struct ast_channel *chan)
00340 {
00341 return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
00342 }
00343
00344 static int pause_monitor_exec(struct ast_channel *chan, void *data)
00345 {
00346 return ast_monitor_pause(chan);
00347 }
00348
00349 static int unpause_monitor_exec(struct ast_channel *chan, void *data)
00350 {
00351 return ast_monitor_unpause(chan);
00352 }
00353
00354
00355 int ast_monitor_change_fname(struct ast_channel *chan, const char *fname_base, int need_lock)
00356 {
00357 char tmp[256];
00358 if (ast_strlen_zero(fname_base)) {
00359 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null\n", chan->name);
00360 return -1;
00361 }
00362
00363 LOCK_IF_NEEDED(chan, need_lock);
00364
00365 if (chan->monitor) {
00366 int directory = strchr(fname_base, '/') ? 1 : 0;
00367
00368 if (directory) {
00369 char *name = strdup(fname_base);
00370 snprintf(tmp, sizeof(tmp), "mkdir -p %s",dirname(name));
00371 free(name);
00372 ast_safe_system(tmp);
00373 }
00374
00375 snprintf(chan->monitor->filename_base, FILENAME_MAX, "%s/%s", directory ? "" : ast_config_AST_MONITOR_DIR, fname_base);
00376 chan->monitor->filename_changed = 1;
00377 } else {
00378 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", chan->name, fname_base);
00379 }
00380
00381 UNLOCK_IF_NEEDED(chan, need_lock);
00382
00383 return 0;
00384 }
00385
00386 static int start_monitor_exec(struct ast_channel *chan, void *data)
00387 {
00388 char *arg = NULL;
00389 char *format = NULL;
00390 char *fname_base = NULL;
00391 char *options = NULL;
00392 char *delay = NULL;
00393 char *urlprefix = NULL;
00394 char tmp[256];
00395 int joinfiles = 0;
00396 int waitforbridge = 0;
00397 int res = 0;
00398
00399
00400 if (!ast_strlen_zero((char*)data)) {
00401 arg = ast_strdupa((char*)data);
00402 format = arg;
00403 fname_base = strchr(arg, '|');
00404 if (fname_base) {
00405 *fname_base = 0;
00406 fname_base++;
00407 if ((options = strchr(fname_base, '|'))) {
00408 *options = 0;
00409 options++;
00410 if (strchr(options, 'm'))
00411 joinfiles = 1;
00412 if (strchr(options, 'b'))
00413 waitforbridge = 1;
00414 }
00415 }
00416 arg = strchr(format,':');
00417 if (arg) {
00418 *arg++ = 0;
00419 urlprefix = arg;
00420 }
00421 }
00422 if (urlprefix) {
00423 snprintf(tmp,sizeof(tmp) - 1,"%s/%s.%s",urlprefix,fname_base,
00424 ((strcmp(format,"gsm")) ? "wav" : "gsm"));
00425 if (!chan->cdr && !(chan->cdr = ast_cdr_alloc()))
00426 return -1;
00427 ast_cdr_setuserfield(chan, tmp);
00428 }
00429 if (waitforbridge) {
00430
00431
00432
00433
00434 delay = ast_strdupa(data);
00435 options = strrchr(delay, '|');
00436 if (options) {
00437 arg = strchr(options, 'b');
00438 if (arg) {
00439 *arg = 'X';
00440 pbx_builtin_setvar_helper(chan,"AUTO_MONITOR",delay);
00441 }
00442 }
00443 return 0;
00444 }
00445
00446 res = ast_monitor_start(chan, format, fname_base, 1);
00447 if (res < 0)
00448 res = ast_monitor_change_fname(chan, fname_base, 1);
00449 ast_monitor_setjoinfiles(chan, joinfiles);
00450
00451 return res;
00452 }
00453
00454 static int stop_monitor_exec(struct ast_channel *chan, void *data)
00455 {
00456 return ast_monitor_stop(chan, 1);
00457 }
00458
00459 static int change_monitor_exec(struct ast_channel *chan, void *data)
00460 {
00461 return ast_monitor_change_fname(chan, (const char*)data, 1);
00462 }
00463
00464 static char start_monitor_action_help[] =
00465 "Description: The 'Monitor' action may be used to record the audio on a\n"
00466 " specified channel. The following parameters may be used to control\n"
00467 " this:\n"
00468 " Channel - Required. Used to specify the channel to record.\n"
00469 " File - Optional. Is the name of the file created in the\n"
00470 " monitor spool directory. Defaults to the same name\n"
00471 " as the channel (with slashes replaced with dashes).\n"
00472 " Format - Optional. Is the audio recording format. Defaults\n"
00473 " to \"wav\".\n"
00474 " Mix - Optional. Boolean parameter as to whether to mix\n"
00475 " the input and output channels together after the\n"
00476 " recording is finished.\n";
00477
00478 static int start_monitor_action(struct mansession *s, const struct message *m)
00479 {
00480 struct ast_channel *c = NULL;
00481 const char *name = astman_get_header(m, "Channel");
00482 const char *fname = astman_get_header(m, "File");
00483 const char *format = astman_get_header(m, "Format");
00484 const char *mix = astman_get_header(m, "Mix");
00485 char *d;
00486
00487 if (ast_strlen_zero(name)) {
00488 astman_send_error(s, m, "No channel specified");
00489 return 0;
00490 }
00491 c = ast_get_channel_by_name_locked(name);
00492 if (!c) {
00493 astman_send_error(s, m, "No such channel");
00494 return 0;
00495 }
00496
00497 if (ast_strlen_zero(fname)) {
00498
00499 if (!(fname = ast_strdup(c->name))) {
00500 astman_send_error(s, m, "Could not start monitoring channel");
00501 ast_channel_unlock(c);
00502 return 0;
00503 }
00504
00505 if ((d = strchr(fname, '/')))
00506 *d = '-';
00507 }
00508
00509 if (ast_monitor_start(c, format, fname, 1)) {
00510 if (ast_monitor_change_fname(c, fname, 1)) {
00511 astman_send_error(s, m, "Could not start monitoring channel");
00512 ast_channel_unlock(c);
00513 return 0;
00514 }
00515 }
00516
00517 if (ast_true(mix)) {
00518 ast_monitor_setjoinfiles(c, 1);
00519 }
00520
00521 ast_channel_unlock(c);
00522 astman_send_ack(s, m, "Started monitoring channel");
00523 return 0;
00524 }
00525
00526 static char stop_monitor_action_help[] =
00527 "Description: The 'StopMonitor' action may be used to end a previously\n"
00528 " started 'Monitor' action. The only parameter is 'Channel', the name\n"
00529 " of the channel monitored.\n";
00530
00531 static int stop_monitor_action(struct mansession *s, const struct message *m)
00532 {
00533 struct ast_channel *c = NULL;
00534 const char *name = astman_get_header(m, "Channel");
00535 int res;
00536 if (ast_strlen_zero(name)) {
00537 astman_send_error(s, m, "No channel specified");
00538 return 0;
00539 }
00540 c = ast_get_channel_by_name_locked(name);
00541 if (!c) {
00542 astman_send_error(s, m, "No such channel");
00543 return 0;
00544 }
00545 res = ast_monitor_stop(c, 1);
00546 ast_channel_unlock(c);
00547 if (res) {
00548 astman_send_error(s, m, "Could not stop monitoring channel");
00549 return 0;
00550 }
00551 astman_send_ack(s, m, "Stopped monitoring channel");
00552 return 0;
00553 }
00554
00555 static char change_monitor_action_help[] =
00556 "Description: The 'ChangeMonitor' action may be used to change the file\n"
00557 " started by a previous 'Monitor' action. The following parameters may\n"
00558 " be used to control this:\n"
00559 " Channel - Required. Used to specify the channel to record.\n"
00560 " File - Required. Is the new name of the file created in the\n"
00561 " monitor spool directory.\n";
00562
00563 static int change_monitor_action(struct mansession *s, const struct message *m)
00564 {
00565 struct ast_channel *c = NULL;
00566 const char *name = astman_get_header(m, "Channel");
00567 const char *fname = astman_get_header(m, "File");
00568 if (ast_strlen_zero(name)) {
00569 astman_send_error(s, m, "No channel specified");
00570 return 0;
00571 }
00572 if (ast_strlen_zero(fname)) {
00573 astman_send_error(s, m, "No filename specified");
00574 return 0;
00575 }
00576 c = ast_get_channel_by_name_locked(name);
00577 if (!c) {
00578 astman_send_error(s, m, "No such channel");
00579 return 0;
00580 }
00581 if (ast_monitor_change_fname(c, fname, 1)) {
00582 astman_send_error(s, m, "Could not change monitored filename of channel");
00583 ast_channel_unlock(c);
00584 return 0;
00585 }
00586 ast_channel_unlock(c);
00587 astman_send_ack(s, m, "Changed monitor filename");
00588 return 0;
00589 }
00590
00591 void ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon)
00592 {
00593 if (chan->monitor)
00594 chan->monitor->joinfiles = turnon;
00595 }
00596
00597 #define IS_NULL_STRING(string) ((!(string)) || (ast_strlen_zero((string))))
00598
00599 enum MONITOR_PAUSING_ACTION
00600 {
00601 MONITOR_ACTION_PAUSE,
00602 MONITOR_ACTION_UNPAUSE
00603 };
00604
00605 static int do_pause_or_unpause(struct mansession *s, const struct message *m, int action)
00606 {
00607 struct ast_channel *c = NULL;
00608 const char *name = astman_get_header(m, "Channel");
00609
00610 if (IS_NULL_STRING(name)) {
00611 astman_send_error(s, m, "No channel specified");
00612 return -1;
00613 }
00614
00615 c = ast_get_channel_by_name_locked(name);
00616 if (!c) {
00617 astman_send_error(s, m, "No such channel");
00618 return -1;
00619 }
00620
00621 if (action == MONITOR_ACTION_PAUSE)
00622 ast_monitor_pause(c);
00623 else
00624 ast_monitor_unpause(c);
00625
00626 ast_channel_unlock(c);
00627 astman_send_ack(s, m, (action == MONITOR_ACTION_PAUSE ? "Paused monitoring of the channel" : "Unpaused monitoring of the channel"));
00628 return 0;
00629 }
00630
00631 static char pause_monitor_action_help[] =
00632 "Description: The 'PauseMonitor' action may be used to temporarily stop the\n"
00633 " recording of a channel. The following parameters may\n"
00634 " be used to control this:\n"
00635 " Channel - Required. Used to specify the channel to record.\n";
00636
00637 static int pause_monitor_action(struct mansession *s, const struct message *m)
00638 {
00639 return do_pause_or_unpause(s, m, MONITOR_ACTION_PAUSE);
00640 }
00641
00642 static char unpause_monitor_action_help[] =
00643 "Description: The 'UnpauseMonitor' action may be used to re-enable recording\n"
00644 " of a channel after calling PauseMonitor. The following parameters may\n"
00645 " be used to control this:\n"
00646 " Channel - Required. Used to specify the channel to record.\n";
00647
00648 static int unpause_monitor_action(struct mansession *s, const struct message *m)
00649 {
00650 return do_pause_or_unpause(s, m, MONITOR_ACTION_UNPAUSE);
00651 }
00652
00653
00654 static int load_module(void)
00655 {
00656 ast_register_application("Monitor", start_monitor_exec, monitor_synopsis, monitor_descrip);
00657 ast_register_application("StopMonitor", stop_monitor_exec, stopmonitor_synopsis, stopmonitor_descrip);
00658 ast_register_application("ChangeMonitor", change_monitor_exec, changemonitor_synopsis, changemonitor_descrip);
00659 ast_register_application("PauseMonitor", pause_monitor_exec, pausemonitor_synopsis, pausemonitor_descrip);
00660 ast_register_application("UnpauseMonitor", unpause_monitor_exec, unpausemonitor_synopsis, unpausemonitor_descrip);
00661 ast_manager_register2("Monitor", EVENT_FLAG_CALL, start_monitor_action, monitor_synopsis, start_monitor_action_help);
00662 ast_manager_register2("StopMonitor", EVENT_FLAG_CALL, stop_monitor_action, stopmonitor_synopsis, stop_monitor_action_help);
00663 ast_manager_register2("ChangeMonitor", EVENT_FLAG_CALL, change_monitor_action, changemonitor_synopsis, change_monitor_action_help);
00664 ast_manager_register2("PauseMonitor", EVENT_FLAG_CALL, pause_monitor_action, pausemonitor_synopsis, pause_monitor_action_help);
00665 ast_manager_register2("UnpauseMonitor", EVENT_FLAG_CALL, unpause_monitor_action, unpausemonitor_synopsis, unpause_monitor_action_help);
00666
00667 return 0;
00668 }
00669
00670 static int unload_module(void)
00671 {
00672 ast_unregister_application("Monitor");
00673 ast_unregister_application("StopMonitor");
00674 ast_unregister_application("ChangeMonitor");
00675 ast_unregister_application("PauseMonitor");
00676 ast_unregister_application("UnpauseMonitor");
00677 ast_manager_unregister("Monitor");
00678 ast_manager_unregister("StopMonitor");
00679 ast_manager_unregister("ChangeMonitor");
00680 ast_manager_unregister("PauseMonitor");
00681 ast_manager_unregister("UnpauseMonitor");
00682
00683 return 0;
00684 }
00685
00686
00687 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Monitoring Resource",
00688 .load = load_module,
00689 .unload = unload_module,
00690 );