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