From 9ffe7a545d976f395906d78042216dcfd46d5224 Mon Sep 17 00:00:00 2001 From: kpfleming Date: Wed, 14 Sep 2005 20:00:54 +0000 Subject: allow channel receive gain to be adjusted while recording messages/greetings in voicemail (workaround for issue #2023 from the ancient past) git-svn-id: http://svn.digium.com/svn/asterisk/trunk@6595 f38db490-d61c-443f-a65b-d21fe96a405b --- apps/app_voicemail.c | 1291 ++++++++++++++++++++++++++------------------------ 1 file changed, 671 insertions(+), 620 deletions(-) (limited to 'apps/app_voicemail.c') diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 70b32b5b0..c08424f69 100755 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -97,6 +97,23 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #define ERROR_LOCK_PATH -100 +#define OPT_SILENT (1 << 0) +#define OPT_BUSY_GREETING (1 << 1) +#define OPT_UNAVAIL_GREETING (1 << 2) +#define OPT_RECORDGAIN (1 << 3) +#define OPT_PREPEND_MAILBOX (1 << 4) + +#define OPT_ARG_RECORDGAIN 0 +#define OPT_ARG_ARRAY_SIZE 1 + +AST_DECLARE_OPTIONS(vm_app_options, { + ['s'] = { .flag = OPT_SILENT }, + ['b'] = { .flag = OPT_BUSY_GREETING }, + ['u'] = { .flag = OPT_UNAVAIL_GREETING }, + ['g'] = { .flag = OPT_RECORDGAIN, .arg_index = OPT_ARG_RECORDGAIN + 1}, + ['p'] = { .flag = OPT_PREPEND_MAILBOX }, +}); + static int load_config(void); /* Syntaxes supported, not really language codes. @@ -210,10 +227,13 @@ struct vm_state { int starting; int repeats; }; -static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option); +static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, + int option, signed char record_gain); static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context); -static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir); -static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc); +static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, + char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir, + signed char record_gain); +static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain); static int vm_play_folder_name(struct ast_channel *chan, char *mbox); static void apply_options(struct ast_vm_user *vmu, const char *options); @@ -250,13 +270,14 @@ static char *synopsis_vm = "Leave a voicemail message"; static char *descrip_vm = -" VoiceMail(extension[@context][&extension[@context]][...][|options]): Leaves" -"voicemail for a given extension (must be configured in voicemail.conf).\n" +" VoiceMail(mailbox[@context][&mailbox[@context]][...][|options]): Leaves" +"voicemail for a given mailbox (must be configured in voicemail.conf).\n" " If the options contain: \n" -"* 's' then instructions for leaving the message will be skipped.\n" -"* 'u' then the \"unavailable\" message will be played.\n" -" (/var/lib/asterisk/sounds/vm//unavail) if it exists.\n" -"* 'b' then the the busy message will be played (that is, busy instead of unavail).\n" +"* 's' instructions for leaving the message will be skipped.\n" +"* 'u' the \"unavailable\" greeting will be played.\n" +"* 'b' the \"busy\" greeting will be played.\n" +"* 'g(#)' the specified amount of gain will be requested during message\n" +" recording (units are whole-number decibels (dB))\n" "If the caller presses '0' (zero) during the prompt, the call jumps to\n" "extension 'o' in the current context.\n" "If the caller presses '*' during the prompt, the call jumps to\n" @@ -277,11 +298,14 @@ static char *descrip_vmain = " VoiceMailMain([mailbox][@context][|options]): Enters the main voicemail system\n" "for the checking of voicemail. The mailbox can be passed in,\n" "which will stop the voicemail system from prompting the user for the mailbox.\n" -"If the options contain 's' then the password check will be skipped. If\n" -"the options contain 'p' then the supplied mailbox is prepended to the\n" -"user's entry and the resulting string is used as the mailbox number. This is\n" -"useful for virtual hosting of voicemail boxes. If a context is specified,\n" -"logins are considered in that voicemail context only.\n" +"If the options contain: \n" +"* 's' the password check will be skipped.\n" +"* 'p' the supplied mailbox is prepended to the user's entry and\n" +" the resulting string is used as the mailbox number. This can\n" +" be useful for virtual hosting of voicemail boxes.\n" +"* 'g(#)' the specified amount of gain will be requested during message\n" +" recording (units are whole-number decibels (dB))\n" +"If a context is specified, mailboxes are considered in that voicemail context only.\n" "Returns -1 if the user hangs up or 0 otherwise.\n"; static char *synopsis_vm_box_exists = @@ -2319,8 +2343,12 @@ static void run_externnotify(char *context, char *extension) } } +struct leave_vm_options { + unsigned int flags; + signed char record_gain; +}; -static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail) +static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options) { char txtfile[256]; char callerid[256]; @@ -2362,252 +2390,250 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"); - if ((vmu = find_user(&svm, context, ext))) { - /* Setup pre-file if appropriate */ - if (strcmp(vmu->context, "default")) - snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context); - else - ast_copy_string(ext_context, vmu->context, sizeof(ext_context)); - if (busy) - snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext); - else if (unavail) - snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext); - snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext); - RETRIEVE(tempfile, -1); - if (ast_fileexists(tempfile, NULL, NULL) > 0) - ast_copy_string(prefile, tempfile, sizeof(prefile)); - DISPOSE(tempfile, -1); - make_dir(dir, sizeof(dir), vmu->context, "", ""); - /* It's easier just to try to make it than to check for its existence */ - if (mkdir(dir, 0700) && (errno != EEXIST)) - ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); - make_dir(dir, sizeof(dir), vmu->context, ext, ""); - /* It's easier just to try to make it than to check for its existence */ - if (mkdir(dir, 0700) && (errno != EEXIST)) - ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); - make_dir(dir, sizeof(dir), vmu->context, ext, "INBOX"); - if (mkdir(dir, 0700) && (errno != EEXIST)) - ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); - - /* Check current or macro-calling context for special extensions */ - if (!ast_strlen_zero(vmu->exit)) { - if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) - strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1); - } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) - strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1); - else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) { + if (!(vmu = find_user(&svm, context, ext))) { + ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext); + ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); + return res; + } + + /* Setup pre-file if appropriate */ + if (strcmp(vmu->context, "default")) + snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context); + else + ast_copy_string(ext_context, vmu->context, sizeof(ext_context)); + if (ast_test_flag(options, OPT_BUSY_GREETING)) + snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext); + else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) + snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext); + snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext); + RETRIEVE(tempfile, -1); + if (ast_fileexists(tempfile, NULL, NULL) > 0) + ast_copy_string(prefile, tempfile, sizeof(prefile)); + DISPOSE(tempfile, -1); + make_dir(dir, sizeof(dir), vmu->context, "", ""); + /* It's easier just to try to make it than to check for its existence */ + if (mkdir(dir, 0700) && (errno != EEXIST)) + ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); + make_dir(dir, sizeof(dir), vmu->context, ext, ""); + /* It's easier just to try to make it than to check for its existence */ + if (mkdir(dir, 0700) && (errno != EEXIST)) + ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); + make_dir(dir, sizeof(dir), vmu->context, ext, "INBOX"); + if (mkdir(dir, 0700) && (errno != EEXIST)) + ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); + + /* Check current or macro-calling context for special extensions */ + if (!ast_strlen_zero(vmu->exit)) { + if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1); - ousemacro = 1; - } + } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) + strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1); + else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) { + strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1); + ousemacro = 1; + } - if (!ast_strlen_zero(vmu->exit)) { - if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num)) - strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1); - } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num)) - strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1); - else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) { + if (!ast_strlen_zero(vmu->exit)) { + if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num)) strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1); - ausemacro = 1; - } - + } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num)) + strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1); + else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) { + strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1); + ausemacro = 1; + } - /* Play the beginning intro if desired */ - if (!ast_strlen_zero(prefile)) { - RETRIEVE(prefile, -1); - if (ast_fileexists(prefile, NULL, NULL) > 0) { - if (ast_streamfile(chan, prefile, chan->language) > -1) - res = ast_waitstream(chan, ecodes); - } else { - ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile); - res = invent_message(chan, vmu->context, ext, busy, ecodes); - } - DISPOSE(prefile, -1); - if (res < 0) { - ast_log(LOG_DEBUG, "Hang up during prefile playback\n"); - free_user(vmu); - return -1; - } + /* Play the beginning intro if desired */ + if (!ast_strlen_zero(prefile)) { + RETRIEVE(prefile, -1); + if (ast_fileexists(prefile, NULL, NULL) > 0) { + if (ast_streamfile(chan, prefile, chan->language) > -1) + res = ast_waitstream(chan, ecodes); + } else { + ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile); + res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes); } + DISPOSE(prefile, -1); + if (res < 0) { + ast_log(LOG_DEBUG, "Hang up during prefile playback\n"); + free_user(vmu); + return -1; + } + } + if (res == '#') { + /* On a '#' we skip the instructions */ + ast_set_flag(options, OPT_SILENT); + res = 0; + } + if (!res && !ast_test_flag(options, OPT_SILENT)) { + res = ast_streamfile(chan, INTRO, chan->language); + if (!res) + res = ast_waitstream(chan, ecodes); if (res == '#') { - /* On a '#' we skip the instructions */ - silent = 1; + ast_set_flag(options, OPT_SILENT); res = 0; } - if (!res && !silent) { - res = ast_streamfile(chan, INTRO, chan->language); - if (!res) - res = ast_waitstream(chan, ecodes); - if (res == '#') { - silent = 1; - res = 0; - } + } + if (res > 0) + ast_stopstream(chan); + /* Check for a '*' here in case the caller wants to escape from voicemail to something + other than the operator -- an automated attendant or mailbox login for example */ + if (res == '*') { + chan->exten[0] = 'a'; + chan->exten[1] = '\0'; + if (!ast_strlen_zero(vmu->exit)) { + ast_copy_string(chan->context, vmu->exit, sizeof(chan->context)); + } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) { + ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context)); } - if (res > 0) - ast_stopstream(chan); - /* Check for a '*' here in case the caller wants to escape from voicemail to something - other than the operator -- an automated attendant or mailbox login for example */ - if (res == '*') { - chan->exten[0] = 'a'; + chan->priority = 0; + free_user(vmu); + return 0; + } + /* Check for a '0' here */ + if (res == '0') { + transfer: + if (ast_test_flag(vmu, VM_OPERATOR)) { + chan->exten[0] = 'o'; chan->exten[1] = '\0'; if (!ast_strlen_zero(vmu->exit)) { ast_copy_string(chan->context, vmu->exit, sizeof(chan->context)); - } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) { + } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) { ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context)); } + ast_play_and_wait(chan, "transfer"); chan->priority = 0; free_user(vmu); return 0; + } else { + ast_play_and_wait(chan, "vm-sorry"); + return 0; } - /* Check for a '0' here */ - if (res == '0') { - transfer: - if (ast_test_flag(vmu, VM_OPERATOR)) { - chan->exten[0] = 'o'; - chan->exten[1] = '\0'; - if (!ast_strlen_zero(vmu->exit)) { - ast_copy_string(chan->context, vmu->exit, sizeof(chan->context)); - } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) { - ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context)); - } - ast_play_and_wait(chan, "transfer"); - chan->priority = 0; - free_user(vmu); - return 0; - } else { - ast_play_and_wait(chan, "vm-sorry"); - return 0; - } - } - if (res < 0) { + } + if (res < 0) { + free_user(vmu); + return -1; + } + /* The meat of recording the message... All the announcements and beeps have been played*/ + ast_copy_string(fmt, vmfmts, sizeof(fmt)); + if (!ast_strlen_zero(fmt)) { + msgnum = 0; + + if (vm_lock_path(dir)) { free_user(vmu); - return -1; + return ERROR_LOCK_PATH; } - /* The meat of recording the message... All the announcements and beeps have been played*/ - ast_copy_string(fmt, vmfmts, sizeof(fmt)); - if (!ast_strlen_zero(fmt)) { - msgnum = 0; - - if (vm_lock_path(dir)) { - free_user(vmu); - return ERROR_LOCK_PATH; - } - /* - * This operation can be very expensive if done say over NFS or if the mailbox has 100+ messages - * in the mailbox. So we should get this first so we don't cut off the first few seconds of the - * message. - */ - do { - make_file(fn, sizeof(fn), dir, msgnum); - if (!EXISTS(dir,msgnum,fn,chan->language)) - break; - msgnum++; - } while (msgnum < vmu->maxmsg); + /* + * This operation can be very expensive if done say over NFS or if the mailbox has 100+ messages + * in the mailbox. So we should get this first so we don't cut off the first few seconds of the + * message. + */ + do { + make_file(fn, sizeof(fn), dir, msgnum); + if (!EXISTS(dir,msgnum,fn,chan->language)) + break; + msgnum++; + } while (msgnum < vmu->maxmsg); - /* Now play the beep once we have the message number for our next message. */ - if (res >= 0) { - /* Unless we're *really* silent, try to send the beep */ - res = ast_streamfile(chan, "beep", chan->language); - if (!res) - res = ast_waitstream(chan, ""); - } - if (msgnum < vmu->maxmsg) { - /* assign a variable with the name of the voicemail file */ - pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn); + /* Now play the beep once we have the message number for our next message. */ + if (res >= 0) { + /* Unless we're *really* silent, try to send the beep */ + res = ast_streamfile(chan, "beep", chan->language); + if (!res) + res = ast_waitstream(chan, ""); + } + if (msgnum < vmu->maxmsg) { + /* assign a variable with the name of the voicemail file */ + pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn); - /* Store information */ - snprintf(txtfile, sizeof(txtfile), "%s.txt", fn); - txt = fopen(txtfile, "w+"); - if (txt) { - get_date(date, sizeof(date)); - fprintf(txt, - ";\n" - "; Message Information file\n" - ";\n" - "[message]\n" - "origmailbox=%s\n" - "context=%s\n" - "macrocontext=%s\n" - "exten=%s\n" - "priority=%d\n" - "callerchan=%s\n" - "callerid=%s\n" - "origdate=%s\n" - "origtime=%ld\n" - "category=%s\n", - ext, - chan->context, - chan->macrocontext, - chan->exten, - chan->priority, - chan->name, - ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"), - date, (long)time(NULL), - category ? category : ""); - } else - ast_log(LOG_WARNING, "Error opening text file for output\n"); - res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &duration, dir); - if (res == '0') { - if (txt) - fclose(txt); - goto transfer; - } - if (res > 0) - res = 0; - if (txt) { - fprintf(txt, "duration=%d\n", duration); + /* Store information */ + snprintf(txtfile, sizeof(txtfile), "%s.txt", fn); + txt = fopen(txtfile, "w+"); + if (txt) { + get_date(date, sizeof(date)); + fprintf(txt, + ";\n" + "; Message Information file\n" + ";\n" + "[message]\n" + "origmailbox=%s\n" + "context=%s\n" + "macrocontext=%s\n" + "exten=%s\n" + "priority=%d\n" + "callerchan=%s\n" + "callerid=%s\n" + "origdate=%s\n" + "origtime=%ld\n" + "category=%s\n", + ext, + chan->context, + chan->macrocontext, + chan->exten, + chan->priority, + chan->name, + ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"), + date, (long)time(NULL), + category ? category : ""); + } else + ast_log(LOG_WARNING, "Error opening text file for output\n"); + res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &duration, dir, options->record_gain); + if (res == '0') { + if (txt) fclose(txt); - } + goto transfer; + } + if (res > 0) + res = 0; + if (txt) { + fprintf(txt, "duration=%d\n", duration); + fclose(txt); + } - if (duration < vmminmessage) { - if (option_verbose > 2) - ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage); - DELETE(dir,msgnum,fn); - /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */ - goto leave_vm_out; - } - /* Are there to be more recipients of this message? */ - while (tmpptr) { - struct ast_vm_user recipu, *recip; - char *exten, *context; + if (duration < vmminmessage) { + if (option_verbose > 2) + ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage); + DELETE(dir,msgnum,fn); + /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */ + goto leave_vm_out; + } + /* Are there to be more recipients of this message? */ + while (tmpptr) { + struct ast_vm_user recipu, *recip; + char *exten, *context; - exten = strsep(&tmpptr, "&"); - context = strchr(exten, '@'); - if (context) { - *context = '\0'; - context++; - } - if ((recip = find_user(&recipu, context, exten))) { - copy_message(chan, vmu, 0, msgnum, duration, recip, fmt); - free_user(recip); - } + exten = strsep(&tmpptr, "&"); + context = strchr(exten, '@'); + if (context) { + *context = '\0'; + context++; } - if (ast_fileexists(fn, NULL, NULL)) { - notify_new_message(chan, vmu, msgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name); - STORE(dir, vmu->mailbox, vmu->context, msgnum); - DISPOSE(dir, msgnum); + if ((recip = find_user(&recipu, context, exten))) { + copy_message(chan, vmu, 0, msgnum, duration, recip, fmt); + free_user(recip); } - } else { - ast_unlock_path(dir); - res = ast_streamfile(chan, "vm-mailboxfull", chan->language); - if (!res) - res = ast_waitstream(chan, ""); - ast_log(LOG_WARNING, "No more messages possible\n"); } - } else - ast_log(LOG_WARNING, "No format for saving voicemail?\n"); -leave_vm_out: - free_user(vmu); - } else { - ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext); - /*Send the call to n+101 priority, where n is the current priority*/ - ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); - } + if (ast_fileexists(fn, NULL, NULL)) { + notify_new_message(chan, vmu, msgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name); + STORE(dir, vmu->mailbox, vmu->context, msgnum); + DISPOSE(dir, msgnum); + } + } else { + ast_unlock_path(dir); + res = ast_streamfile(chan, "vm-mailboxfull", chan->language); + if (!res) + res = ast_waitstream(chan, ""); + ast_log(LOG_WARNING, "No more messages possible\n"); + } + } else + ast_log(LOG_WARNING, "No format for saving voicemail?\n"); + leave_vm_out: + free_user(vmu); return res; } - static int resequence_mailbox(struct ast_vm_user *vmu, char *dir) { /* we know max messages, so stop process when number is hit */ @@ -3207,11 +3233,13 @@ static int get_folder2(struct ast_channel *chan, char *fn, int start) return res; } -static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vmfts, char *context) +static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vmfts, + char *context, signed char record_gain) { int cmd = 0; int retries = 0; int duration = 0; + signed char zero_gain = 0; while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) { if (cmd) @@ -3222,7 +3250,11 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, { char file[200]; snprintf(file, sizeof(file), "%s/msg%04d", curdir, curmsg); + if (record_gain) + ast_channel_setoption(chan, AST_OPTION_TXGAIN, &record_gain, sizeof(record_gain), 0); cmd = ast_play_and_prepend(chan, NULL, file, 0, vmfmts, &duration, 1, silencethreshold, maxsilence); + if (record_gain) + ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_gain, sizeof(zero_gain), 0); break; } case '2': @@ -3297,7 +3329,8 @@ static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, return 0; } -static int forward_message(struct ast_channel *chan, char *context, char *dir, int curmsg, struct ast_vm_user *sender, char *fmt,int flag) +static int forward_message(struct ast_channel *chan, char *context, char *dir, int curmsg, struct ast_vm_user *sender, + char *fmt, int flag, signed char record_gain) { char username[70]=""; char sys[256]; @@ -3317,7 +3350,6 @@ static int forward_message(struct ast_channel *chan, char *context, char *dir, i int valid_extensions = 0; while (!res && !valid_extensions) { - int use_directory = 0; if(ast_test_flag((&globalflags), VM_DIRECFORWARD)) { int done = 0; @@ -3431,11 +3463,15 @@ static int forward_message(struct ast_channel *chan, char *context, char *dir, i return res; vmtmp = extensions; if (flag==1) { + struct leave_vm_options leave_options; + /* Send VoiceMail */ - cmd=leave_voicemail(chan,username,0,0,0); + memset(&leave_options, 0, sizeof(leave_options)); + leave_options.record_gain = record_gain; + cmd = leave_voicemail(chan, username, &leave_options); } else { /* Forward VoiceMail */ - cmd = vm_forwardoptions(chan, sender, dir, curmsg, vmfmts, context); + cmd = vm_forwardoptions(chan, sender, dir, curmsg, vmfmts, context, record_gain); if (!cmd) { while (!res && vmtmp) { /* if (ast_play_and_wait(chan, "vm-savedto")) @@ -4523,7 +4559,7 @@ static int vm_instructions(struct ast_channel *chan, struct vm_state *vms, int s return res; } -static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc) +static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain) { int cmd = 0; int duration = 0; @@ -4576,7 +4612,7 @@ static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct /* If forcename is set, have the user record their name */ if (ast_test_flag(vmu, VM_FORCENAME)) { snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username); - cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL); + cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain); if (cmd < 0 || cmd == 't' || cmd == '#') return cmd; } @@ -4584,11 +4620,11 @@ static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct /* If forcegreetings is set, have the user record their greetings */ if (ast_test_flag(vmu, VM_FORCEGREET)) { snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username); - cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL); + cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain); if (cmd < 0 || cmd == 't' || cmd == '#') return cmd; snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username); - cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL); + cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain); if (cmd < 0 || cmd == 't' || cmd == '#') return cmd; } @@ -4596,7 +4632,7 @@ static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct return cmd; } -static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc) +static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain) { int cmd = 0; int retries = 0; @@ -4622,18 +4658,18 @@ static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct switch (cmd) { case '1': snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username); - cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL); + cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain); break; case '2': snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username); - cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL); + cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain); break; case '3': snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username); - cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL); + cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain); break; case '4': - cmd = vm_tempgreeting(chan, vmu, vms, fmtc); + cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain); break; case '5': if (vmu->password[0] == '-') { @@ -4693,7 +4729,7 @@ static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct return cmd; } -static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc) +static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain) { int cmd = 0; int retries = 0; @@ -4718,7 +4754,7 @@ static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, st if (ast_fileexists(prefile, NULL, NULL) > 0) { switch (cmd) { case '1': - cmd = play_record_review(chan,"vm-rec-temp",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL); + cmd = play_record_review(chan,"vm-rec-temp",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain); break; case '2': ast_filedelete(prefile, NULL); @@ -4742,7 +4778,7 @@ static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, st } } } else { - play_record_review(chan,"vm-rec-temp",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL); + play_record_review(chan,"vm-rec-temp",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain); cmd = 't'; } } @@ -4980,88 +5016,93 @@ static int vm_execmain(struct ast_channel *chan, void *data) reason it just seemed a lot easier to do with GOTO's. I feel like I'm back in my GWBASIC days. XXX */ int res=-1; - int valid = 0; - int prefix = 0; int cmd=0; + int valid = 0; struct localuser *u; char prefixstr[80] =""; char ext_context[256]=""; int box; int useadsi = 0; int skipuser = 0; - char tmp[256], *ext; - char fmtc[256] = ""; struct vm_state vms; struct ast_vm_user *vmu = NULL, vmus; char *context=NULL; int silentexit = 0; - char *options; + struct ast_flags flags = { 0 }; + signed char record_gain = 0; LOCAL_USER_ADD(u); + memset(&vms, 0, sizeof(vms)); vms.lastmsg = -1; + memset(&vmus, 0, sizeof(vmus)); - ast_copy_string(fmtc, vmfmts, sizeof(fmtc)); + if (chan->_state != AST_STATE_UP) ast_answer(chan); if (data && !ast_strlen_zero(data)) { - ast_copy_string(tmp, data, sizeof(tmp)); - ext = tmp; - - /* option 's': don't request a password */ - /* option 'p': the supplied name is actually a prefix to be added to the mailbox - number entered by the user */ - if ((options = strchr(ext, '|'))) { - *options++ = '\0'; - while (*options) - switch (*options++) { - case 's': - valid++; - break; - case 'p': - prefix++; - break; + char *tmp; + int argc; + char *argv[2]; + char *opts[OPT_ARG_ARRAY_SIZE]; + + tmp = ast_strdupa(data); + argc = ast_separate_app_args(tmp, '|', argv, sizeof(argv) / sizeof(argv[0])); + if (argc == 2) { + if (ast_parseoptions(vm_app_options, &flags, opts, argv[1])) { + LOCAL_USER_REMOVE(u); + return -1; + } + if (ast_test_flag(&flags, OPT_RECORDGAIN)) { + int gain; + + if (sscanf(opts[OPT_ARG_RECORDGAIN], "%d", &gain) != 1) { + ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]); + LOCAL_USER_REMOVE(u); + return -1; + } else { + record_gain = (signed char) gain; } + } } else { /* old style options parsing */ - while (*ext) { - if (*ext == 's') { - valid++; - ext++; - } else if (*ext == 'p') { - prefix++; - ext++; - } else + while (*argv[0]) { + if (*argv[0] == 's') { + ast_set_flag(&flags, OPT_SILENT); + argv[0]++; + } else if (*argv[0] == 'p') { + ast_set_flag(&flags, OPT_PREPEND_MAILBOX); + argv[0]++; + } else break; } - } - context = strchr(ext, '@'); - if (context) { - *context = '\0'; - context++; } - if (prefix) - ast_copy_string(prefixstr, ext, sizeof(prefixstr)); + valid = ast_test_flag(&flags, OPT_SILENT); + + if ((context = strchr(argv[0], '@'))) + *context++ = '\0'; + + if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX)) + ast_copy_string(prefixstr, argv[0], sizeof(prefixstr)); else - ast_copy_string(vms.username, ext, sizeof(vms.username)); + ast_copy_string(vms.username, argv[0], sizeof(vms.username)); + if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username))) skipuser++; else valid = 0; } - if (!valid) { + if (!valid) res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0); - } if (!res) { valid = 1; - if (!skipuser) { + if (!skipuser) vmu = &vmus; - } } else { res = 0; } @@ -5069,323 +5110,318 @@ static int vm_execmain(struct ast_channel *chan, void *data) /* If ADSI is supported, setup login screen */ adsi_begin(chan, &useadsi); - if (valid) { - vms.deleted = calloc(vmu->maxmsg, sizeof(int)); - vms.heard = calloc(vmu->maxmsg, sizeof(int)); + if (!valid) + goto out; + + vms.deleted = calloc(vmu->maxmsg, sizeof(int)); + vms.heard = calloc(vmu->maxmsg, sizeof(int)); - /* Set language from config to override channel language */ - if (vmu->language && !ast_strlen_zero(vmu->language)) - ast_copy_string(chan->language, vmu->language, sizeof(chan->language)); - snprintf(vms.curdir, sizeof(vms.curdir), "%s/%s", VM_SPOOL_DIR, vmu->context); - mkdir(vms.curdir, 0700); - snprintf(vms.curdir, sizeof(vms.curdir), "%s/%s/%s", VM_SPOOL_DIR, vmu->context, vms.username); - mkdir(vms.curdir, 0700); - /* Retrieve old and new message counts */ + /* Set language from config to override channel language */ + if (vmu->language && !ast_strlen_zero(vmu->language)) + ast_copy_string(chan->language, vmu->language, sizeof(chan->language)); + snprintf(vms.curdir, sizeof(vms.curdir), "%s/%s", VM_SPOOL_DIR, vmu->context); + mkdir(vms.curdir, 0700); + snprintf(vms.curdir, sizeof(vms.curdir), "%s/%s/%s", VM_SPOOL_DIR, vmu->context, vms.username); + mkdir(vms.curdir, 0700); + /* Retrieve old and new message counts */ + res = open_mailbox(&vms, vmu, 1); + if (res == ERROR_LOCK_PATH) + goto out; + vms.oldmessages = vms.lastmsg + 1; + /* Start in INBOX */ + res = open_mailbox(&vms, vmu, 0); + if (res == ERROR_LOCK_PATH) + goto out; + vms.newmessages = vms.lastmsg + 1; + + /* Select proper mailbox FIRST!! */ + if (!vms.newmessages && vms.oldmessages) { + /* If we only have old messages start here */ res = open_mailbox(&vms, vmu, 1); if (res == ERROR_LOCK_PATH) goto out; - vms.oldmessages = vms.lastmsg + 1; - /* Start in INBOX */ - res = open_mailbox(&vms, vmu, 0); - if (res == ERROR_LOCK_PATH) - goto out; - vms.newmessages = vms.lastmsg + 1; - - /* Select proper mailbox FIRST!! */ - if (!vms.newmessages && vms.oldmessages) { - /* If we only have old messages start here */ - res = open_mailbox(&vms, vmu, 1); - if (res == ERROR_LOCK_PATH) - goto out; - } + } - if (useadsi) - adsi_status(chan, &vms); - res = 0; + if (useadsi) + adsi_status(chan, &vms); + res = 0; - /* Check to see if this is a new user */ - if (!strcasecmp(vmu->mailbox, vmu->password) && - (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) { - if (ast_play_and_wait(chan, "vm-newuser") == -1) - ast_log(LOG_WARNING, "Couldn't stream new user file\n"); - cmd = vm_newuser(chan, vmu, &vms, vmfmts); - if ((cmd == 't') || (cmd == '#')) { - /* Timeout */ - res = 0; - goto out; - } else if (cmd < 0) { - /* Hangup */ - res = -1; - goto out; - } + /* Check to see if this is a new user */ + if (!strcasecmp(vmu->mailbox, vmu->password) && + (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) { + if (ast_play_and_wait(chan, "vm-newuser") == -1) + ast_log(LOG_WARNING, "Couldn't stream new user file\n"); + cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain); + if ((cmd == 't') || (cmd == '#')) { + /* Timeout */ + res = 0; + goto out; + } else if (cmd < 0) { + /* Hangup */ + res = -1; + goto out; } + } - cmd = vm_intro(chan, &vms); - - vms.repeats = 0; - vms.starting = 1; - while ((cmd > -1) && (cmd != 't') && (cmd != '#')) { - /* Run main menu */ - switch(cmd) { - case '1': - vms.curmsg = 0; - /* Fall through */ - case '5': - cmd = vm_browse_messages(chan, &vms, vmu); - break; - case '2': /* Change folders */ - if (useadsi) - adsi_folders(chan, 0, "Change to folder..."); - cmd = get_folder2(chan, "vm-changeto", 0); - if (cmd == '#') { - cmd = 0; - } else if (cmd > 0) { - cmd = cmd - '0'; - res = close_mailbox(&vms, vmu); - if (res == ERROR_LOCK_PATH) - goto out; - res = open_mailbox(&vms, vmu, cmd); - if (res == ERROR_LOCK_PATH) - goto out; - cmd = 0; - } - if (useadsi) - adsi_status2(chan, &vms); - - if (!cmd) - cmd = vm_play_folder_name(chan, vms.vmbox); + cmd = vm_intro(chan, &vms); - vms.starting = 1; - break; - case '3': /* Advanced options */ + vms.repeats = 0; + vms.starting = 1; + while ((cmd > -1) && (cmd != 't') && (cmd != '#')) { + /* Run main menu */ + switch(cmd) { + case '1': + vms.curmsg = 0; + /* Fall through */ + case '5': + cmd = vm_browse_messages(chan, &vms, vmu); + break; + case '2': /* Change folders */ + if (useadsi) + adsi_folders(chan, 0, "Change to folder..."); + cmd = get_folder2(chan, "vm-changeto", 0); + if (cmd == '#') { cmd = 0; - vms.repeats = 0; - while ((cmd > -1) && (cmd != 't') && (cmd != '#')) { - switch(cmd) { - case '1': /* Reply */ - if (vms.lastmsg > -1) { - cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1); - if (cmd == ERROR_LOCK_PATH) { - res = cmd; - goto out; - } - } else - cmd = ast_play_and_wait(chan, "vm-sorry"); - cmd = 't'; - break; - case '2': /* Callback */ - ast_verbose( VERBOSE_PREFIX_3 "Callback Requested\n"); - if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1) { - cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2); - if (cmd == 9) { - silentexit = 1; - goto out; - } else if (cmd == ERROR_LOCK_PATH) { - res = cmd; - goto out; - } - } - else - cmd = ast_play_and_wait(chan, "vm-sorry"); - cmd = 't'; - break; - case '3': /* Envelope */ - if (vms.lastmsg > -1) { - cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3); - if (cmd == ERROR_LOCK_PATH) { - res = cmd; - goto out; - } - } else - cmd = ast_play_and_wait(chan, "vm-sorry"); - cmd = 't'; - break; - case '4': /* Dialout */ - if (!ast_strlen_zero(vmu->dialout)) { - cmd = dialout(chan, vmu, NULL, vmu->dialout); - if (cmd == 9) { - silentexit = 1; - goto out; - } - } - else - cmd = ast_play_and_wait(chan, "vm-sorry"); - cmd = 't'; - break; - - case '5': /* Leave VoiceMail */ - if (ast_test_flag(vmu, VM_SVMAIL)) { - cmd = forward_message(chan, context, vms.curdir, vms.curmsg, vmu, vmfmts,1); - if (cmd == ERROR_LOCK_PATH) { - res = cmd; - goto out; - } - } else - cmd = ast_play_and_wait(chan,"vm-sorry"); - cmd='t'; - break; - - case '*': /* Return to main menu */ - cmd = 't'; - break; + } else if (cmd > 0) { + cmd = cmd - '0'; + res = close_mailbox(&vms, vmu); + if (res == ERROR_LOCK_PATH) + goto out; + res = open_mailbox(&vms, vmu, cmd); + if (res == ERROR_LOCK_PATH) + goto out; + cmd = 0; + } + if (useadsi) + adsi_status2(chan, &vms); + + if (!cmd) + cmd = vm_play_folder_name(chan, vms.vmbox); - default: - cmd = 0; - if (!vms.starting) { - cmd = ast_play_and_wait(chan, "vm-toreply"); + vms.starting = 1; + break; + case '3': /* Advanced options */ + cmd = 0; + vms.repeats = 0; + while ((cmd > -1) && (cmd != 't') && (cmd != '#')) { + switch(cmd) { + case '1': /* Reply */ + if (vms.lastmsg > -1) { + cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain); + if (cmd == ERROR_LOCK_PATH) { + res = cmd; + goto out; } - if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) { - cmd = ast_play_and_wait(chan, "vm-tocallback"); + } else + cmd = ast_play_and_wait(chan, "vm-sorry"); + cmd = 't'; + break; + case '2': /* Callback */ + ast_verbose( VERBOSE_PREFIX_3 "Callback Requested\n"); + if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1) { + cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain); + if (cmd == 9) { + silentexit = 1; + goto out; + } else if (cmd == ERROR_LOCK_PATH) { + res = cmd; + goto out; } - - if (!cmd && !vms.starting) { - cmd = ast_play_and_wait(chan, "vm-tohearenv"); + } + else + cmd = ast_play_and_wait(chan, "vm-sorry"); + cmd = 't'; + break; + case '3': /* Envelope */ + if (vms.lastmsg > -1) { + cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain); + if (cmd == ERROR_LOCK_PATH) { + res = cmd; + goto out; } - if (!ast_strlen_zero(vmu->dialout) && !cmd) { - cmd = ast_play_and_wait(chan, "vm-tomakecall"); + } else + cmd = ast_play_and_wait(chan, "vm-sorry"); + cmd = 't'; + break; + case '4': /* Dialout */ + if (!ast_strlen_zero(vmu->dialout)) { + cmd = dialout(chan, vmu, NULL, vmu->dialout); + if (cmd == 9) { + silentexit = 1; + goto out; } - if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) - cmd=ast_play_and_wait(chan, "vm-leavemsg"); - if (!cmd) - cmd = ast_play_and_wait(chan, "vm-starmain"); - if (!cmd) - cmd = ast_waitfordigit(chan,6000); - if (!cmd) - vms.repeats++; - if (vms.repeats > 3) - cmd = 't'; } - } - if (cmd == 't') { - cmd = 0; - vms.repeats = 0; - } - break; - - - + else + cmd = ast_play_and_wait(chan, "vm-sorry"); + cmd = 't'; + break; + case '5': /* Leave VoiceMail */ + if (ast_test_flag(vmu, VM_SVMAIL)) { + cmd = forward_message(chan, context, vms.curdir, vms.curmsg, vmu, vmfmts, 1, record_gain); + if (cmd == ERROR_LOCK_PATH) { + res = cmd; + goto out; + } + } else + cmd = ast_play_and_wait(chan,"vm-sorry"); + cmd='t'; + break; + + case '*': /* Return to main menu */ + cmd = 't'; + break; - case '4': - if (vms.curmsg) { - vms.curmsg--; - cmd = play_message(chan, vmu, &vms); - } else { - cmd = ast_play_and_wait(chan, "vm-nomore"); + default: + cmd = 0; + if (!vms.starting) { + cmd = ast_play_and_wait(chan, "vm-toreply"); + } + if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) { + cmd = ast_play_and_wait(chan, "vm-tocallback"); + } + if (!cmd && !vms.starting) { + cmd = ast_play_and_wait(chan, "vm-tohearenv"); + } + if (!ast_strlen_zero(vmu->dialout) && !cmd) { + cmd = ast_play_and_wait(chan, "vm-tomakecall"); + } + if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) + cmd=ast_play_and_wait(chan, "vm-leavemsg"); + if (!cmd) + cmd = ast_play_and_wait(chan, "vm-starmain"); + if (!cmd) + cmd = ast_waitfordigit(chan,6000); + if (!cmd) + vms.repeats++; + if (vms.repeats > 3) + cmd = 't'; } - break; - case '6': + } + if (cmd == 't') { + cmd = 0; + vms.repeats = 0; + } + break; + case '4': + if (vms.curmsg) { + vms.curmsg--; + cmd = play_message(chan, vmu, &vms); + } else { + cmd = ast_play_and_wait(chan, "vm-nomore"); + } + break; + case '6': + if (vms.curmsg < vms.lastmsg) { + vms.curmsg++; + cmd = play_message(chan, vmu, &vms); + } else { + cmd = ast_play_and_wait(chan, "vm-nomore"); + } + break; + case '7': + vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg]; + if (useadsi) + adsi_delete(chan, &vms); + if (vms.deleted[vms.curmsg]) + cmd = ast_play_and_wait(chan, "vm-deleted"); + else + cmd = ast_play_and_wait(chan, "vm-undeleted"); + if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) { if (vms.curmsg < vms.lastmsg) { vms.curmsg++; cmd = play_message(chan, vmu, &vms); } else { cmd = ast_play_and_wait(chan, "vm-nomore"); } - break; - case '7': - vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg]; - if (useadsi) - adsi_delete(chan, &vms); - if (vms.deleted[vms.curmsg]) - cmd = ast_play_and_wait(chan, "vm-deleted"); - else - cmd = ast_play_and_wait(chan, "vm-undeleted"); - if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) { - if (vms.curmsg < vms.lastmsg) { - vms.curmsg++; - cmd = play_message(chan, vmu, &vms); - } else { - cmd = ast_play_and_wait(chan, "vm-nomore"); - } - } - break; + } + break; - case '8': - if (vms.lastmsg > -1) { - cmd = forward_message(chan, context, vms.curdir, vms.curmsg, vmu, vmfmts,0); - if (cmd == ERROR_LOCK_PATH) { - res = cmd; - goto out; - } - } else - cmd = ast_play_and_wait(chan, "vm-nomore"); - break; - case '9': - if (useadsi) - adsi_folders(chan, 1, "Save to folder..."); - cmd = get_folder2(chan, "vm-savefolder", 1); - box = 0; /* Shut up compiler */ - if (cmd == '#') { - cmd = 0; - break; - } else if (cmd > 0) { - box = cmd = cmd - '0'; - cmd = save_to_folder(vmu, vms.curdir, vms.curmsg, vmu->context, vms.username, cmd); - if (cmd == ERROR_LOCK_PATH) { - res = cmd; - goto out; - } else if (!cmd) { - vms.deleted[vms.curmsg] = 1; - } else { - vms.deleted[vms.curmsg] = 0; - vms.heard[vms.curmsg] = 0; - } + case '8': + if (vms.lastmsg > -1) { + cmd = forward_message(chan, context, vms.curdir, vms.curmsg, vmu, vmfmts, 0, record_gain); + if (cmd == ERROR_LOCK_PATH) { + res = cmd; + goto out; } - make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg); - if (useadsi) - adsi_message(chan, &vms); - snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box)); - if (!cmd) { - cmd = ast_play_and_wait(chan, "vm-message"); - if (!cmd) - cmd = say_and_wait(chan, vms.curmsg + 1, chan->language); - if (!cmd) - cmd = ast_play_and_wait(chan, "vm-savedto"); - if (!cmd) - cmd = vm_play_folder_name(chan, vms.fn); + } else + cmd = ast_play_and_wait(chan, "vm-nomore"); + break; + case '9': + if (useadsi) + adsi_folders(chan, 1, "Save to folder..."); + cmd = get_folder2(chan, "vm-savefolder", 1); + box = 0; /* Shut up compiler */ + if (cmd == '#') { + cmd = 0; + break; + } else if (cmd > 0) { + box = cmd = cmd - '0'; + cmd = save_to_folder(vmu, vms.curdir, vms.curmsg, vmu->context, vms.username, cmd); + if (cmd == ERROR_LOCK_PATH) { + res = cmd; + goto out; + } else if (!cmd) { + vms.deleted[vms.curmsg] = 1; } else { - cmd = ast_play_and_wait(chan, "vm-mailboxfull"); + vms.deleted[vms.curmsg] = 0; + vms.heard[vms.curmsg] = 0; } - if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) { - if (vms.curmsg < vms.lastmsg) { - vms.curmsg++; - cmd = play_message(chan, vmu, &vms); - } else { - cmd = ast_play_and_wait(chan, "vm-nomore"); - } + } + make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg); + if (useadsi) + adsi_message(chan, &vms); + snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box)); + if (!cmd) { + cmd = ast_play_and_wait(chan, "vm-message"); + if (!cmd) + cmd = say_and_wait(chan, vms.curmsg + 1, chan->language); + if (!cmd) + cmd = ast_play_and_wait(chan, "vm-savedto"); + if (!cmd) + cmd = vm_play_folder_name(chan, vms.fn); + } else { + cmd = ast_play_and_wait(chan, "vm-mailboxfull"); + } + if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) { + if (vms.curmsg < vms.lastmsg) { + vms.curmsg++; + cmd = play_message(chan, vmu, &vms); + } else { + cmd = ast_play_and_wait(chan, "vm-nomore"); } - break; - - case '*': - if (!vms.starting) { - cmd = ast_play_and_wait(chan, "vm-onefor"); - if (!cmd) - cmd = vm_play_folder_name(chan, vms.vmbox); - if (!cmd) - cmd = ast_play_and_wait(chan, "vm-opts"); - if (!cmd) - cmd = vm_instructions(chan, &vms, 1); - } else - cmd = 0; - break; - case '0': - cmd = vm_options(chan, vmu, &vms, vmfmts); - if (useadsi) - adsi_status(chan, &vms); - break; - default: /* Nothing */ - cmd = vm_instructions(chan, &vms, 0); - break; } + break; + case '*': + if (!vms.starting) { + cmd = ast_play_and_wait(chan, "vm-onefor"); + if (!cmd) + cmd = vm_play_folder_name(chan, vms.vmbox); + if (!cmd) + cmd = ast_play_and_wait(chan, "vm-opts"); + if (!cmd) + cmd = vm_instructions(chan, &vms, 1); + } else + cmd = 0; + break; + case '0': + cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain); + if (useadsi) + adsi_status(chan, &vms); + break; + default: /* Nothing */ + cmd = vm_instructions(chan, &vms, 0); + break; } - if ((cmd == 't') || (cmd == '#')) { - /* Timeout */ - res = 0; - } else { - /* Hangup */ - res = -1; - } } + if ((cmd == 't') || (cmd == '#')) { + /* Timeout */ + res = 0; + } else { + /* Hangup */ + res = -1; + } + out: if (res > -1) { ast_stopstream(chan); @@ -5421,17 +5457,59 @@ out: static int vm_exec(struct ast_channel *chan, void *data) { - int res=0, silent=0, busy=0, unavail=0; + int res = 0; struct localuser *u; char tmp[256]; - char *ext, *options; + struct leave_vm_options leave_options; + int argc; + char *argv[2]; + struct ast_flags flags = { 0 }; + char *opts[OPT_ARG_ARRAY_SIZE]; + memset(&leave_options, 0, sizeof(leave_options)); + LOCAL_USER_ADD(u); + if (chan->_state != AST_STATE_UP) ast_answer(chan); - if (data && !ast_strlen_zero(data)) + + if (data && !ast_strlen_zero(data)) { ast_copy_string(tmp, data, sizeof(tmp)); - else { + argc = ast_separate_app_args(tmp, '|', argv, sizeof(argv) / sizeof(argv[0])); + if (argc == 2) { + if (ast_parseoptions(vm_app_options, &flags, opts, argv[1])) { + LOCAL_USER_REMOVE(u); + return -1; + } + ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING); + if (ast_test_flag(&flags, OPT_RECORDGAIN)) { + int gain; + + if (sscanf(opts[OPT_ARG_RECORDGAIN], "%d", &gain) != 1) { + ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]); + LOCAL_USER_REMOVE(u); + return -1; + } else { + leave_options.record_gain = (signed char) gain; + } + } + } else { + /* old style options parsing */ + while (*argv[0]) { + if (*argv[0] == 's') { + ast_set_flag(&leave_options, OPT_SILENT); + argv[0]++; + } else if (*argv[0] == 'b') { + ast_set_flag(&leave_options, OPT_BUSY_GREETING); + argv[0]++; + } else if (*argv[0] == 'u') { + ast_set_flag(&leave_options, OPT_UNAVAIL_GREETING); + argv[0]++; + } else + break; + } + } + } else { res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0); if (res < 0) return res; @@ -5439,41 +5517,8 @@ static int vm_exec(struct ast_channel *chan, void *data) return 0; } - ext = tmp; - /* option 's': skip intro message with instructions */ - /* option 'b': play 'busy' greeting */ - /* option 'u': play 'unavailable' greeting */ - if ((options = strchr(ext, '|'))) { - *options++ = '\0'; - while (*options) - switch (*options++) { - case 's': - silent = 2; - break; - case 'b': - busy = 1; - break; - case 'u': - unavail = 1; - break; - } - } else { - /* old style options parsing */ - while (*ext) { - if (*ext == 's') { - silent = 2; - ext++; - } else if (*ext == 'b') { - busy = 1; - ext++; - } else if (*ext == 'u') { - unavail = 1; - ext++; - } else - break; - } - } - res = leave_voicemail(chan, ext, silent, busy, unavail); + res = leave_voicemail(chan, argv[0], &leave_options); + LOCAL_USER_REMOVE(u); if (res == ERROR_LOCK_PATH) { @@ -6260,7 +6305,8 @@ static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, return 0; } -static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option) +static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, + int option, signed char record_gain) { int res = 0; char filename[256],*origtime, *cid, *context, *name, *num; @@ -6388,8 +6434,13 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s return res; } else { if (find_user(NULL, vmu->context, num)) { + struct leave_vm_options leave_options; + ast_verbose(VERBOSE_PREFIX_3 "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context); - res = leave_voicemail(chan, num, 1, 0, 1); + + memset(&leave_options, 0, sizeof(leave_options)); + leave_options.record_gain = record_gain; + res = leave_voicemail(chan, num, &leave_options); if (!res) res = 't'; return res; @@ -6414,15 +6465,10 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s } return res; } - - - - - - - -static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir) +static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, + int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir, + signed char record_gain) { /* Record message & let caller review or re-record it, or set options if applicable */ int res = 0; @@ -6431,6 +6477,7 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re int attempts = 0; int recorded = 0; int message_exists = 0; + signed char zero_gain = 0; /* Note that urgent and private are for flagging messages as such in the future */ /* barf if no pointer passed to store duration in */ @@ -6477,7 +6524,11 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re } recorded = 1; /* After an attempt has been made to record message, we have to take care of INTRO and beep for incoming messages, but not for greetings */ + if (record_gain) + ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0); cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir); + if (record_gain) + ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0); if (cmd == -1) { /* User has hung up, no options to give */ return cmd; -- cgit v1.2.3