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