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
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include "asterisk.h"
00041
00042 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 404045 $")
00043
00044 #include "asterisk/paths.h"
00045 #include "asterisk/stringfields.h"
00046 #include "asterisk/file.h"
00047 #include "asterisk/audiohook.h"
00048 #include "asterisk/pbx.h"
00049 #include "asterisk/module.h"
00050 #include "asterisk/cli.h"
00051 #include "asterisk/app.h"
00052 #include "asterisk/channel.h"
00053 #include "asterisk/autochan.h"
00054 #include "asterisk/manager.h"
00055 #include "asterisk/callerid.h"
00056 #include "asterisk/mod_format.h"
00057 #include "asterisk/linkedlists.h"
00058 #include "asterisk/test.h"
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 #define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
00249
00250 static const char * const app = "MixMonitor";
00251
00252 static const char * const stop_app = "StopMixMonitor";
00253
00254 static const char * const mixmonitor_spy_type = "MixMonitor";
00255
00256
00257
00258
00259
00260 struct vm_recipient {
00261 char mailbox[AST_MAX_CONTEXT];
00262 char context[AST_MAX_EXTENSION];
00263 char folder[80];
00264 AST_LIST_ENTRY(vm_recipient) list;
00265 };
00266
00267 struct mixmonitor {
00268 struct ast_audiohook audiohook;
00269 struct ast_callid *callid;
00270 char *filename;
00271 char *filename_read;
00272 char *filename_write;
00273 char *post_process;
00274 char *name;
00275 unsigned int flags;
00276 struct ast_autochan *autochan;
00277 struct mixmonitor_ds *mixmonitor_ds;
00278
00279
00280 AST_DECLARE_STRING_FIELDS(
00281 AST_STRING_FIELD(call_context);
00282 AST_STRING_FIELD(call_macrocontext);
00283 AST_STRING_FIELD(call_extension);
00284 AST_STRING_FIELD(call_callerchan);
00285 AST_STRING_FIELD(call_callerid);
00286 );
00287 int call_priority;
00288
00289
00290
00291 AST_LIST_HEAD_NOLOCK(, vm_recipient) recipient_list;
00292 };
00293
00294 enum mixmonitor_flags {
00295 MUXFLAG_APPEND = (1 << 1),
00296 MUXFLAG_BRIDGED = (1 << 2),
00297 MUXFLAG_VOLUME = (1 << 3),
00298 MUXFLAG_READVOLUME = (1 << 4),
00299 MUXFLAG_WRITEVOLUME = (1 << 5),
00300 MUXFLAG_READ = (1 << 6),
00301 MUXFLAG_WRITE = (1 << 7),
00302 MUXFLAG_COMBINED = (1 << 8),
00303 MUXFLAG_UID = (1 << 9),
00304 MUXFLAG_VMRECIPIENTS = (1 << 10),
00305 };
00306
00307 enum mixmonitor_args {
00308 OPT_ARG_READVOLUME = 0,
00309 OPT_ARG_WRITEVOLUME,
00310 OPT_ARG_VOLUME,
00311 OPT_ARG_WRITENAME,
00312 OPT_ARG_READNAME,
00313 OPT_ARG_UID,
00314 OPT_ARG_VMRECIPIENTS,
00315 OPT_ARG_ARRAY_SIZE,
00316 };
00317
00318 AST_APP_OPTIONS(mixmonitor_opts, {
00319 AST_APP_OPTION('a', MUXFLAG_APPEND),
00320 AST_APP_OPTION('b', MUXFLAG_BRIDGED),
00321 AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME),
00322 AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME),
00323 AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
00324 AST_APP_OPTION_ARG('r', MUXFLAG_READ, OPT_ARG_READNAME),
00325 AST_APP_OPTION_ARG('t', MUXFLAG_WRITE, OPT_ARG_WRITENAME),
00326 AST_APP_OPTION_ARG('i', MUXFLAG_UID, OPT_ARG_UID),
00327 AST_APP_OPTION_ARG('m', MUXFLAG_VMRECIPIENTS, OPT_ARG_VMRECIPIENTS),
00328 });
00329
00330 struct mixmonitor_ds {
00331 unsigned int destruction_ok;
00332 ast_cond_t destruction_condition;
00333 ast_mutex_t lock;
00334
00335
00336
00337 int fs_quit;
00338
00339 struct ast_filestream *fs;
00340 struct ast_filestream *fs_read;
00341 struct ast_filestream *fs_write;
00342
00343 struct ast_audiohook *audiohook;
00344
00345 unsigned int samp_rate;
00346 };
00347
00348
00349
00350
00351
00352 static void mixmonitor_ds_close_fs(struct mixmonitor_ds *mixmonitor_ds)
00353 {
00354 unsigned char quitting = 0;
00355
00356 if (mixmonitor_ds->fs) {
00357 quitting = 1;
00358 ast_closestream(mixmonitor_ds->fs);
00359 mixmonitor_ds->fs = NULL;
00360 ast_verb(2, "MixMonitor close filestream (mixed)\n");
00361 }
00362
00363 if (mixmonitor_ds->fs_read) {
00364 quitting = 1;
00365 ast_closestream(mixmonitor_ds->fs_read);
00366 mixmonitor_ds->fs_read = NULL;
00367 ast_verb(2, "MixMonitor close filestream (read)\n");
00368 }
00369
00370 if (mixmonitor_ds->fs_write) {
00371 quitting = 1;
00372 ast_closestream(mixmonitor_ds->fs_write);
00373 mixmonitor_ds->fs_write = NULL;
00374 ast_verb(2, "MixMonitor close filestream (write)\n");
00375 }
00376
00377 if (quitting) {
00378 mixmonitor_ds->fs_quit = 1;
00379 }
00380 }
00381
00382 static void mixmonitor_ds_destroy(void *data)
00383 {
00384 struct mixmonitor_ds *mixmonitor_ds = data;
00385
00386 ast_mutex_lock(&mixmonitor_ds->lock);
00387 mixmonitor_ds->audiohook = NULL;
00388 mixmonitor_ds->destruction_ok = 1;
00389 ast_cond_signal(&mixmonitor_ds->destruction_condition);
00390 ast_mutex_unlock(&mixmonitor_ds->lock);
00391 }
00392
00393 static const struct ast_datastore_info mixmonitor_ds_info = {
00394 .type = "mixmonitor",
00395 .destroy = mixmonitor_ds_destroy,
00396 };
00397
00398 static void destroy_monitor_audiohook(struct mixmonitor *mixmonitor)
00399 {
00400 if (mixmonitor->mixmonitor_ds) {
00401 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00402 mixmonitor->mixmonitor_ds->audiohook = NULL;
00403 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00404 }
00405
00406 ast_audiohook_lock(&mixmonitor->audiohook);
00407 ast_audiohook_detach(&mixmonitor->audiohook);
00408 ast_audiohook_unlock(&mixmonitor->audiohook);
00409 ast_audiohook_destroy(&mixmonitor->audiohook);
00410 }
00411
00412 static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
00413 {
00414 struct ast_channel *peer = NULL;
00415 int res = 0;
00416
00417 if (!chan)
00418 return -1;
00419
00420 ast_audiohook_attach(chan, audiohook);
00421
00422 if (!res && ast_test_flag(ast_channel_flags(chan), AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
00423 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
00424
00425 return res;
00426 }
00427
00428
00429
00430
00431
00432
00433
00434 static void add_vm_recipients_from_string(struct mixmonitor *mixmonitor, const char *vm_recipients)
00435 {
00436
00437 char *cur_mailbox = ast_strdupa(vm_recipients);
00438 char *cur_context;
00439 char *cur_folder;
00440 char *next;
00441 int elements_processed = 0;
00442
00443 while (!ast_strlen_zero(cur_mailbox)) {
00444 ast_debug(3, "attempting to add next element %d from %s\n", elements_processed, cur_mailbox);
00445 if ((next = strchr(cur_mailbox, ',')) || (next = strchr(cur_mailbox, '&'))) {
00446 *(next++) = '\0';
00447 }
00448
00449 if ((cur_folder = strchr(cur_mailbox, '/'))) {
00450 *(cur_folder++) = '\0';
00451 } else {
00452 cur_folder = "INBOX";
00453 }
00454
00455 if ((cur_context = strchr(cur_mailbox, '@'))) {
00456 *(cur_context++) = '\0';
00457 } else {
00458 cur_context = "default";
00459 }
00460
00461 if (!ast_strlen_zero(cur_mailbox) && !ast_strlen_zero(cur_context)) {
00462 struct vm_recipient *recipient;
00463 if (!(recipient = ast_malloc(sizeof(*recipient)))) {
00464 ast_log(LOG_ERROR, "Failed to allocate recipient. Aborting function.\n");
00465 return;
00466 }
00467 ast_copy_string(recipient->context, cur_context, sizeof(recipient->context));
00468 ast_copy_string(recipient->mailbox, cur_mailbox, sizeof(recipient->mailbox));
00469 ast_copy_string(recipient->folder, cur_folder, sizeof(recipient->folder));
00470
00471
00472 ast_verb(5, "Adding %s@%s to recipient list\n", recipient->mailbox, recipient->context);
00473 AST_LIST_INSERT_HEAD(&mixmonitor->recipient_list, recipient, list);
00474 } else {
00475 ast_log(LOG_ERROR, "Failed to properly parse extension and/or context from element %d of recipient string: %s\n", elements_processed, vm_recipients);
00476 }
00477
00478 cur_mailbox = next;
00479 elements_processed++;
00480 }
00481 }
00482
00483 static void clear_mixmonitor_recipient_list(struct mixmonitor *mixmonitor)
00484 {
00485 struct vm_recipient *current;
00486 while ((current = AST_LIST_REMOVE_HEAD(&mixmonitor->recipient_list, list))) {
00487
00488 ast_free(current);
00489 }
00490 }
00491
00492 #define SAMPLES_PER_FRAME 160
00493
00494 static void mixmonitor_free(struct mixmonitor *mixmonitor)
00495 {
00496 if (mixmonitor) {
00497 if (mixmonitor->mixmonitor_ds) {
00498 ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
00499 ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
00500 ast_free(mixmonitor->mixmonitor_ds);
00501 }
00502
00503 ast_free(mixmonitor->name);
00504 ast_free(mixmonitor->post_process);
00505 ast_free(mixmonitor->filename);
00506 ast_free(mixmonitor->filename_write);
00507 ast_free(mixmonitor->filename_read);
00508
00509
00510 clear_mixmonitor_recipient_list(mixmonitor);
00511
00512
00513 ast_string_field_free_memory(mixmonitor);
00514
00515 if (mixmonitor->callid) {
00516 ast_callid_unref(mixmonitor->callid);
00517 }
00518
00519 ast_free(mixmonitor);
00520 }
00521 }
00522
00523
00524
00525
00526
00527
00528
00529 static void copy_to_voicemail(struct mixmonitor *mixmonitor, const char *ext, const char *filename)
00530 {
00531 struct vm_recipient *recipient = NULL;
00532 struct ast_vm_recording_data recording_data;
00533 if (ast_string_field_init(&recording_data, 512)) {
00534 ast_log(LOG_ERROR, "Failed to string_field_init, skipping copy_to_voicemail\n");
00535 return;
00536 }
00537
00538
00539 ast_string_field_set(&recording_data, recording_file, filename);
00540 ast_string_field_set(&recording_data, recording_ext, ext);
00541 ast_string_field_set(&recording_data, call_context, mixmonitor->call_context);
00542 ast_string_field_set(&recording_data, call_macrocontext, mixmonitor->call_macrocontext);
00543 ast_string_field_set(&recording_data, call_extension, mixmonitor->call_extension);
00544 ast_string_field_set(&recording_data, call_callerchan, mixmonitor->call_callerchan);
00545 ast_string_field_set(&recording_data, call_callerid, mixmonitor->call_callerid);
00546
00547 recording_data.call_priority = mixmonitor->call_priority;
00548
00549 AST_LIST_TRAVERSE(&mixmonitor->recipient_list, recipient, list) {
00550
00551 ast_string_field_set(&recording_data, context, recipient->context);
00552 ast_string_field_set(&recording_data, mailbox, recipient->mailbox);
00553 ast_string_field_set(&recording_data, folder, recipient->folder);
00554
00555 ast_verb(4, "MixMonitor attempting to send voicemail copy to %s@%s\n", recording_data.mailbox,
00556 recording_data.context);
00557 ast_app_copy_recording_to_vm(&recording_data);
00558 }
00559
00560
00561 ast_string_field_free_memory(&recording_data);
00562 }
00563
00564 static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag, char **ext)
00565 {
00566
00567 char *last_slash = NULL;
00568 if (!ast_strlen_zero(filename)) {
00569 if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
00570 *oflags = O_CREAT | O_WRONLY;
00571 *oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
00572
00573 last_slash = strrchr(filename, '/');
00574
00575 if ((*ext = strrchr(filename, '.')) && (*ext > last_slash)) {
00576 **ext = '\0';
00577 *ext = *ext + 1;
00578 } else {
00579 *ext = "raw";
00580 }
00581
00582 if (!(*fs = ast_writefile(filename, *ext, NULL, *oflags, 0, 0666))) {
00583 ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, *ext);
00584 *errflag = 1;
00585 } else {
00586 struct ast_filestream *tmp = *fs;
00587 mixmonitor->mixmonitor_ds->samp_rate = MAX(mixmonitor->mixmonitor_ds->samp_rate, ast_format_rate(&tmp->fmt->format));
00588 }
00589 }
00590 }
00591 }
00592
00593 static void *mixmonitor_thread(void *obj)
00594 {
00595 struct mixmonitor *mixmonitor = obj;
00596 char *fs_ext = "";
00597 char *fs_read_ext = "";
00598 char *fs_write_ext = "";
00599
00600 struct ast_filestream **fs = NULL;
00601 struct ast_filestream **fs_read = NULL;
00602 struct ast_filestream **fs_write = NULL;
00603
00604 unsigned int oflags;
00605 int errflag = 0;
00606 struct ast_format format_slin;
00607
00608
00609 if (mixmonitor->callid) {
00610 ast_callid_threadassoc_add(mixmonitor->callid);
00611 }
00612
00613 ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
00614
00615 fs = &mixmonitor->mixmonitor_ds->fs;
00616 fs_read = &mixmonitor->mixmonitor_ds->fs_read;
00617 fs_write = &mixmonitor->mixmonitor_ds->fs_write;
00618
00619 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00620 mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag, &fs_ext);
00621 mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag, &fs_read_ext);
00622 mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag, &fs_write_ext);
00623
00624 ast_format_set(&format_slin, ast_format_slin_by_rate(mixmonitor->mixmonitor_ds->samp_rate), 0);
00625
00626 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00627
00628
00629
00630 ast_audiohook_lock(&mixmonitor->audiohook);
00631 while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
00632 struct ast_frame *fr = NULL;
00633 struct ast_frame *fr_read = NULL;
00634 struct ast_frame *fr_write = NULL;
00635
00636 if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME, &format_slin,
00637 &fr_read, &fr_write))) {
00638 ast_audiohook_trigger_wait(&mixmonitor->audiohook);
00639
00640 if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
00641 break;
00642 }
00643 continue;
00644 }
00645
00646
00647
00648 ast_audiohook_unlock(&mixmonitor->audiohook);
00649
00650 if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) {
00651 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00652
00653
00654 if ((*fs_read) && (fr_read)) {
00655 struct ast_frame *cur;
00656
00657 for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
00658 ast_writestream(*fs_read, cur);
00659 }
00660 }
00661
00662 if ((*fs_write) && (fr_write)) {
00663 struct ast_frame *cur;
00664
00665 for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
00666 ast_writestream(*fs_write, cur);
00667 }
00668 }
00669
00670 if ((*fs) && (fr)) {
00671 struct ast_frame *cur;
00672
00673 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
00674 ast_writestream(*fs, cur);
00675 }
00676 }
00677 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00678 }
00679
00680 if (fr) {
00681 ast_frame_free(fr, 0);
00682 }
00683 if (fr_read) {
00684 ast_frame_free(fr_read, 0);
00685 }
00686 if (fr_write) {
00687 ast_frame_free(fr_write, 0);
00688 }
00689
00690 fr = NULL;
00691 fr_write = NULL;
00692 fr_read = NULL;
00693
00694 ast_audiohook_lock(&mixmonitor->audiohook);
00695 }
00696
00697
00698 ast_test_suite_event_notify("MIXMONITOR_END", "Channel: %s\r\n"
00699 "File: %s\r\n",
00700 ast_channel_name(mixmonitor->autochan->chan),
00701 mixmonitor->filename);
00702
00703 ast_audiohook_unlock(&mixmonitor->audiohook);
00704
00705 ast_autochan_destroy(mixmonitor->autochan);
00706
00707
00708 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00709 mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
00710 if (!mixmonitor->mixmonitor_ds->destruction_ok) {
00711 ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
00712 }
00713 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00714
00715
00716 destroy_monitor_audiohook(mixmonitor);
00717
00718 if (mixmonitor->post_process) {
00719 ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
00720 ast_safe_system(mixmonitor->post_process);
00721 }
00722
00723 ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
00724
00725 if (!AST_LIST_EMPTY(&mixmonitor->recipient_list)) {
00726 if (ast_strlen_zero(fs_ext)) {
00727 ast_log(LOG_ERROR, "No file extension set for Mixmonitor %s. Skipping copy to voicemail.\n",
00728 mixmonitor -> name);
00729 } else {
00730 ast_verb(3, "Copying recordings for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
00731 copy_to_voicemail(mixmonitor, fs_ext, mixmonitor->filename);
00732 }
00733 if (!ast_strlen_zero(fs_read_ext)) {
00734 ast_verb(3, "Copying read recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
00735 copy_to_voicemail(mixmonitor, fs_read_ext, mixmonitor->filename_read);
00736 }
00737 if (!ast_strlen_zero(fs_write_ext)) {
00738 ast_verb(3, "Copying write recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
00739 copy_to_voicemail(mixmonitor, fs_write_ext, mixmonitor->filename_write);
00740 }
00741 } else {
00742 ast_debug(3, "No recipients to forward monitor to, moving on.\n");
00743 }
00744
00745 mixmonitor_free(mixmonitor);
00746
00747 ast_module_unref(ast_module_info->self);
00748 return NULL;
00749 }
00750
00751 static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id)
00752 {
00753 struct ast_datastore *datastore = NULL;
00754 struct mixmonitor_ds *mixmonitor_ds;
00755
00756 if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
00757 return -1;
00758 }
00759
00760 if (ast_asprintf(datastore_id, "%p", mixmonitor_ds) == -1) {
00761 ast_log(LOG_ERROR, "Failed to allocate memory for MixMonitor ID.\n");
00762 }
00763
00764 ast_mutex_init(&mixmonitor_ds->lock);
00765 ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
00766
00767 if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, *datastore_id))) {
00768 ast_mutex_destroy(&mixmonitor_ds->lock);
00769 ast_cond_destroy(&mixmonitor_ds->destruction_condition);
00770 ast_free(mixmonitor_ds);
00771 return -1;
00772 }
00773
00774
00775 mixmonitor_ds->samp_rate = 8000;
00776 mixmonitor_ds->audiohook = &mixmonitor->audiohook;
00777 datastore->data = mixmonitor_ds;
00778
00779 ast_channel_lock(chan);
00780 ast_channel_datastore_add(chan, datastore);
00781 ast_channel_unlock(chan);
00782
00783 mixmonitor->mixmonitor_ds = mixmonitor_ds;
00784 return 0;
00785 }
00786
00787 static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
00788 unsigned int flags, int readvol, int writevol,
00789 const char *post_process, const char *filename_write,
00790 char *filename_read, const char *uid_channel_var,
00791 const char *recipients)
00792 {
00793 pthread_t thread;
00794 struct mixmonitor *mixmonitor;
00795 char postprocess2[1024] = "";
00796 char *datastore_id = NULL;
00797
00798 postprocess2[0] = 0;
00799
00800 if (!ast_strlen_zero(post_process)) {
00801 char *p1, *p2;
00802
00803 p1 = ast_strdupa(post_process);
00804 for (p2 = p1; *p2; p2++) {
00805 if (*p2 == '^' && *(p2+1) == '{') {
00806 *p2 = '$';
00807 }
00808 }
00809 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
00810 }
00811
00812
00813 if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
00814 return -1;
00815 }
00816
00817
00818 if (ast_string_field_init(mixmonitor, 512)) {
00819 mixmonitor_free(mixmonitor);
00820 return -1;
00821 }
00822
00823
00824 if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type, 0)) {
00825 mixmonitor_free(mixmonitor);
00826 return -1;
00827 }
00828
00829
00830 mixmonitor->flags = flags;
00831 if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
00832 mixmonitor_free(mixmonitor);
00833 return -1;
00834 }
00835
00836 if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id)) {
00837 ast_autochan_destroy(mixmonitor->autochan);
00838 mixmonitor_free(mixmonitor);
00839 ast_free(datastore_id);
00840 return -1;
00841 }
00842
00843 if (!ast_strlen_zero(uid_channel_var)) {
00844 if (datastore_id) {
00845 pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
00846 }
00847 }
00848 ast_free(datastore_id);
00849
00850 mixmonitor->name = ast_strdup(ast_channel_name(chan));
00851
00852 if (!ast_strlen_zero(postprocess2)) {
00853 mixmonitor->post_process = ast_strdup(postprocess2);
00854 }
00855
00856 if (!ast_strlen_zero(filename)) {
00857 mixmonitor->filename = ast_strdup(filename);
00858 }
00859
00860 if (!ast_strlen_zero(filename_write)) {
00861 mixmonitor->filename_write = ast_strdup(filename_write);
00862 }
00863
00864 if (!ast_strlen_zero(filename_read)) {
00865 mixmonitor->filename_read = ast_strdup(filename_read);
00866 }
00867
00868 if (!ast_strlen_zero(recipients)) {
00869 char callerid[256];
00870 struct ast_party_connected_line *connected;
00871
00872 ast_channel_lock(chan);
00873
00874
00875
00876 connected = ast_channel_connected(chan);
00877 ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid,
00878 connected->id.name.str, connected->id.number.valid,
00879 connected->id.number.str);
00880 ast_callerid_merge(callerid, sizeof(callerid),
00881 S_COR(connected->id.name.valid, connected->id.name.str, NULL),
00882 S_COR(connected->id.number.valid, connected->id.number.str, NULL),
00883 "Unknown");
00884
00885 ast_string_field_set(mixmonitor, call_context, ast_channel_context(chan));
00886 ast_string_field_set(mixmonitor, call_macrocontext, ast_channel_macrocontext(chan));
00887 ast_string_field_set(mixmonitor, call_extension, ast_channel_exten(chan));
00888 ast_string_field_set(mixmonitor, call_callerchan, ast_channel_name(chan));
00889 ast_string_field_set(mixmonitor, call_callerid, callerid);
00890 mixmonitor->call_priority = ast_channel_priority(chan);
00891
00892 ast_channel_unlock(chan);
00893
00894 add_vm_recipients_from_string(mixmonitor, recipients);
00895 }
00896
00897 ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
00898
00899 if (readvol)
00900 mixmonitor->audiohook.options.read_volume = readvol;
00901 if (writevol)
00902 mixmonitor->audiohook.options.write_volume = writevol;
00903
00904 if (startmon(chan, &mixmonitor->audiohook)) {
00905 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
00906 mixmonitor_spy_type, ast_channel_name(chan));
00907 ast_audiohook_destroy(&mixmonitor->audiohook);
00908 mixmonitor_free(mixmonitor);
00909 return -1;
00910 }
00911
00912
00913 mixmonitor->callid = ast_read_threadstorage_callid();
00914
00915 return ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor);
00916 }
00917
00918
00919
00920 static char *filename_parse(char *filename, char *buffer, size_t len)
00921 {
00922 char *slash;
00923 if (ast_strlen_zero(filename)) {
00924 ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
00925 } else if (filename[0] != '/') {
00926 char *build;
00927 build = ast_alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(filename) + 3);
00928 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, filename);
00929 filename = build;
00930 }
00931
00932 ast_copy_string(buffer, filename, len);
00933
00934 if ((slash = strrchr(filename, '/'))) {
00935 *slash = '\0';
00936 }
00937 ast_mkdir(filename, 0777);
00938
00939 return buffer;
00940 }
00941
00942 static int mixmonitor_exec(struct ast_channel *chan, const char *data)
00943 {
00944 int x, readvol = 0, writevol = 0;
00945 char *filename_read = NULL;
00946 char *filename_write = NULL;
00947 char filename_buffer[1024] = "";
00948 char *uid_channel_var = NULL;
00949
00950 struct ast_flags flags = { 0 };
00951 char *recipients = NULL;
00952 char *parse;
00953 AST_DECLARE_APP_ARGS(args,
00954 AST_APP_ARG(filename);
00955 AST_APP_ARG(options);
00956 AST_APP_ARG(post_process);
00957 );
00958
00959 if (ast_strlen_zero(data)) {
00960 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
00961 return -1;
00962 }
00963
00964 parse = ast_strdupa(data);
00965
00966 AST_STANDARD_APP_ARGS(args, parse);
00967
00968 if (args.options) {
00969 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
00970
00971 ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
00972
00973 if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
00974 if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
00975 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
00976 } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00977 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
00978 } else {
00979 readvol = get_volfactor(x);
00980 }
00981 }
00982
00983 if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
00984 if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
00985 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
00986 } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00987 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
00988 } else {
00989 writevol = get_volfactor(x);
00990 }
00991 }
00992
00993 if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
00994 if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
00995 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
00996 } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00997 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
00998 } else {
00999 readvol = writevol = get_volfactor(x);
01000 }
01001 }
01002
01003 if (ast_test_flag(&flags, MUXFLAG_VMRECIPIENTS)) {
01004 if (ast_strlen_zero(opts[OPT_ARG_VMRECIPIENTS])) {
01005 ast_log(LOG_WARNING, "No voicemail recipients were specified for the vm copy ('m') option.\n");
01006 } else {
01007 recipients = ast_strdupa(opts[OPT_ARG_VMRECIPIENTS]);
01008 }
01009 }
01010
01011 if (ast_test_flag(&flags, MUXFLAG_WRITE)) {
01012 filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer)));
01013 }
01014
01015 if (ast_test_flag(&flags, MUXFLAG_READ)) {
01016 filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
01017 }
01018
01019 if (ast_test_flag(&flags, MUXFLAG_UID)) {
01020 uid_channel_var = opts[OPT_ARG_UID];
01021 }
01022 }
01023
01024
01025 if (!ast_test_flag(&flags, MUXFLAG_WRITE) && !ast_test_flag(&flags, MUXFLAG_READ) && ast_strlen_zero(args.filename)) {
01026 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
01027 return -1;
01028 }
01029
01030
01031 if (!(ast_strlen_zero(args.filename))) {
01032 args.filename = ast_strdupa(filename_parse(args.filename, filename_buffer, sizeof(filename_buffer)));
01033 }
01034
01035 pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
01036
01037
01038 ast_module_ref(ast_module_info->self);
01039 if (launch_monitor_thread(chan,
01040 args.filename,
01041 flags.flags,
01042 readvol,
01043 writevol,
01044 args.post_process,
01045 filename_write,
01046 filename_read,
01047 uid_channel_var,
01048 recipients)) {
01049 ast_module_unref(ast_module_info->self);
01050 }
01051
01052 return 0;
01053 }
01054
01055 static int stop_mixmonitor_full(struct ast_channel *chan, const char *data)
01056 {
01057 struct ast_datastore *datastore = NULL;
01058 char *parse = "";
01059 struct mixmonitor_ds *mixmonitor_ds;
01060
01061 AST_DECLARE_APP_ARGS(args,
01062 AST_APP_ARG(mixmonid);
01063 );
01064
01065 if (!ast_strlen_zero(data)) {
01066 parse = ast_strdupa(data);
01067 }
01068
01069 AST_STANDARD_APP_ARGS(args, parse);
01070
01071 ast_channel_lock(chan);
01072
01073 if (!(datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.mixmonid))) {
01074 ast_channel_unlock(chan);
01075 return -1;
01076 }
01077 mixmonitor_ds = datastore->data;
01078
01079 ast_mutex_lock(&mixmonitor_ds->lock);
01080
01081
01082
01083 mixmonitor_ds_close_fs(mixmonitor_ds);
01084
01085
01086
01087
01088 if (mixmonitor_ds->audiohook) {
01089 if (mixmonitor_ds->audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
01090 ast_audiohook_update_status(mixmonitor_ds->audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
01091 }
01092 ast_audiohook_lock(mixmonitor_ds->audiohook);
01093 ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
01094 ast_audiohook_unlock(mixmonitor_ds->audiohook);
01095 mixmonitor_ds->audiohook = NULL;
01096 }
01097
01098 ast_mutex_unlock(&mixmonitor_ds->lock);
01099
01100
01101 if (!ast_channel_datastore_remove(chan, datastore)) {
01102 ast_datastore_free(datastore);
01103 }
01104 ast_channel_unlock(chan);
01105
01106 return 0;
01107 }
01108
01109 static int stop_mixmonitor_exec(struct ast_channel *chan, const char *data)
01110 {
01111 stop_mixmonitor_full(chan, data);
01112 return 0;
01113 }
01114
01115 static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01116 {
01117 struct ast_channel *chan;
01118 struct ast_datastore *datastore = NULL;
01119 struct mixmonitor_ds *mixmonitor_ds = NULL;
01120
01121 switch (cmd) {
01122 case CLI_INIT:
01123 e->command = "mixmonitor {start|stop|list}";
01124 e->usage =
01125 "Usage: mixmonitor <start|stop|list> <chan_name> [args]\n"
01126 " The optional arguments are passed to the MixMonitor\n"
01127 " application when the 'start' command is used.\n";
01128 return NULL;
01129 case CLI_GENERATE:
01130 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
01131 }
01132
01133 if (a->argc < 3) {
01134 return CLI_SHOWUSAGE;
01135 }
01136
01137 if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
01138 ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
01139
01140 return CLI_SUCCESS;
01141 }
01142
01143 ast_channel_lock(chan);
01144
01145 if (!strcasecmp(a->argv[1], "start")) {
01146 mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
01147 ast_channel_unlock(chan);
01148 } else if (!strcasecmp(a->argv[1], "stop")){
01149 ast_channel_unlock(chan);
01150 stop_mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
01151 } else if (!strcasecmp(a->argv[1], "list")) {
01152 ast_cli(a->fd, "MixMonitor ID\tFile\tReceive File\tTransmit File\n");
01153 ast_cli(a->fd, "=========================================================================\n");
01154 AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
01155 if (datastore->info == &mixmonitor_ds_info) {
01156 char *filename = "";
01157 char *filename_read = "";
01158 char *filename_write = "";
01159 mixmonitor_ds = datastore->data;
01160 if (mixmonitor_ds->fs)
01161 filename = ast_strdupa(mixmonitor_ds->fs->filename);
01162 if (mixmonitor_ds->fs_read)
01163 filename_read = ast_strdupa(mixmonitor_ds->fs_read->filename);
01164 if (mixmonitor_ds->fs_write)
01165 filename_write = ast_strdupa(mixmonitor_ds->fs_write->filename);
01166 ast_cli(a->fd, "%p\t%s\t%s\t%s\n", mixmonitor_ds, filename, filename_read, filename_write);
01167 }
01168 }
01169 ast_channel_unlock(chan);
01170 } else {
01171 ast_channel_unlock(chan);
01172 chan = ast_channel_unref(chan);
01173 return CLI_SHOWUSAGE;
01174 }
01175
01176 chan = ast_channel_unref(chan);
01177
01178 return CLI_SUCCESS;
01179 }
01180
01181
01182 static int manager_mute_mixmonitor(struct mansession *s, const struct message *m)
01183 {
01184 struct ast_channel *c = NULL;
01185
01186 const char *name = astman_get_header(m, "Channel");
01187 const char *id = astman_get_header(m, "ActionID");
01188 const char *state = astman_get_header(m, "State");
01189 const char *direction = astman_get_header(m,"Direction");
01190
01191 int clearmute = 1;
01192
01193 enum ast_audiohook_flags flag;
01194
01195 if (ast_strlen_zero(direction)) {
01196 astman_send_error(s, m, "No direction specified. Must be read, write or both");
01197 return AMI_SUCCESS;
01198 }
01199
01200 if (!strcasecmp(direction, "read")) {
01201 flag = AST_AUDIOHOOK_MUTE_READ;
01202 } else if (!strcasecmp(direction, "write")) {
01203 flag = AST_AUDIOHOOK_MUTE_WRITE;
01204 } else if (!strcasecmp(direction, "both")) {
01205 flag = AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE;
01206 } else {
01207 astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
01208 return AMI_SUCCESS;
01209 }
01210
01211 if (ast_strlen_zero(name)) {
01212 astman_send_error(s, m, "No channel specified");
01213 return AMI_SUCCESS;
01214 }
01215
01216 if (ast_strlen_zero(state)) {
01217 astman_send_error(s, m, "No state specified");
01218 return AMI_SUCCESS;
01219 }
01220
01221 clearmute = ast_false(state);
01222 c = ast_channel_get_by_name(name);
01223
01224 if (!c) {
01225 astman_send_error(s, m, "No such channel");
01226 return AMI_SUCCESS;
01227 }
01228
01229 if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) {
01230 c = ast_channel_unref(c);
01231 astman_send_error(s, m, "Cannot set mute flag");
01232 return AMI_SUCCESS;
01233 }
01234
01235 astman_append(s, "Response: Success\r\n");
01236
01237 if (!ast_strlen_zero(id)) {
01238 astman_append(s, "ActionID: %s\r\n", id);
01239 }
01240
01241 astman_append(s, "\r\n");
01242
01243 c = ast_channel_unref(c);
01244
01245 return AMI_SUCCESS;
01246 }
01247
01248 static int manager_mixmonitor(struct mansession *s, const struct message *m)
01249 {
01250 struct ast_channel *c = NULL;
01251
01252 const char *name = astman_get_header(m, "Channel");
01253 const char *id = astman_get_header(m, "ActionID");
01254 const char *file = astman_get_header(m, "File");
01255 const char *options = astman_get_header(m, "Options");
01256 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
01257 struct ast_flags flags = { 0 };
01258 char *uid_channel_var = NULL;
01259 const char *mixmonitor_id = NULL;
01260
01261 int res;
01262 char args[PATH_MAX] = "";
01263 if (ast_strlen_zero(name)) {
01264 astman_send_error(s, m, "No channel specified");
01265 return AMI_SUCCESS;
01266 }
01267
01268 c = ast_channel_get_by_name(name);
01269
01270 if (!c) {
01271 astman_send_error(s, m, "No such channel");
01272 return AMI_SUCCESS;
01273 }
01274
01275 if (!ast_strlen_zero(options)) {
01276 ast_app_parse_options(mixmonitor_opts, &flags, opts, ast_strdupa(options));
01277 }
01278
01279 snprintf(args, sizeof(args), "%s,%s", file, options);
01280
01281 ast_channel_lock(c);
01282 res = mixmonitor_exec(c, args);
01283
01284 if (ast_test_flag(&flags, MUXFLAG_UID)) {
01285 uid_channel_var = opts[OPT_ARG_UID];
01286 mixmonitor_id = pbx_builtin_getvar_helper(c, uid_channel_var);
01287 }
01288 ast_channel_unlock(c);
01289
01290 if (res) {
01291 c = ast_channel_unref(c);
01292 astman_send_error(s, m, "Could not start monitoring channel");
01293 return AMI_SUCCESS;
01294 }
01295
01296 astman_append(s, "Response: Success\r\n");
01297
01298 if (!ast_strlen_zero(id)) {
01299 astman_append(s, "ActionID: %s\r\n", id);
01300 }
01301
01302 if (!ast_strlen_zero(mixmonitor_id)) {
01303 astman_append(s, "MixMonitorID: %s\r\n", mixmonitor_id);
01304 }
01305
01306 astman_append(s, "\r\n");
01307
01308 c = ast_channel_unref(c);
01309
01310 return AMI_SUCCESS;
01311 }
01312
01313 static int manager_stop_mixmonitor(struct mansession *s, const struct message *m)
01314 {
01315 struct ast_channel *c = NULL;
01316
01317 const char *name = astman_get_header(m, "Channel");
01318 const char *id = astman_get_header(m, "ActionID");
01319 const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
01320
01321 int res;
01322 if (ast_strlen_zero(name)) {
01323 astman_send_error(s, m, "No channel specified");
01324 return AMI_SUCCESS;
01325 }
01326
01327 c = ast_channel_get_by_name(name);
01328
01329 if (!c) {
01330 astman_send_error(s, m, "No such channel");
01331 return AMI_SUCCESS;
01332 }
01333
01334 res = stop_mixmonitor_full(c, mixmonitor_id);
01335
01336 if (res) {
01337 ast_channel_unref(c);
01338 astman_send_error(s, m, "Could not stop monitoring channel");
01339 return AMI_SUCCESS;
01340 }
01341
01342 astman_append(s, "Response: Success\r\n");
01343
01344 if (!ast_strlen_zero(id)) {
01345 astman_append(s, "ActionID: %s\r\n", id);
01346 }
01347
01348 astman_append(s, "\r\n");
01349
01350 c = ast_channel_unref(c);
01351
01352 return AMI_SUCCESS;
01353 }
01354
01355 static struct ast_cli_entry cli_mixmonitor[] = {
01356 AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
01357 };
01358
01359 static int unload_module(void)
01360 {
01361 int res;
01362
01363 ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
01364 res = ast_unregister_application(stop_app);
01365 res |= ast_unregister_application(app);
01366 res |= ast_manager_unregister("MixMonitorMute");
01367 res |= ast_manager_unregister("MixMonitor");
01368 res |= ast_manager_unregister("StopMixMonitor");
01369 return res;
01370 }
01371
01372 static int load_module(void)
01373 {
01374 int res;
01375
01376 ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
01377 res = ast_register_application_xml(app, mixmonitor_exec);
01378 res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec);
01379 res |= ast_manager_register_xml("MixMonitorMute", 0, manager_mute_mixmonitor);
01380 res |= ast_manager_register_xml("MixMonitor", 0, manager_mixmonitor);
01381 res |= ast_manager_register_xml("StopMixMonitor", 0, manager_stop_mixmonitor);
01382
01383 return res;
01384 }
01385
01386 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mixed Audio Monitoring Application");