[Freeswitch-svn] [commit] r3183 - in freeswitch/branches/ptinsley/voicemail/src: . include mod/applications/mod_voicemail
Freeswitch SVN
ptinsley at freeswitch.org
Tue Oct 24 15:43:24 EDT 2006
Author: ptinsley
Date: Tue Oct 24 15:43:23 2006
New Revision: 3183
Added:
freeswitch/branches/ptinsley/voicemail/src/mod/applications/mod_voicemail/ (props changed)
freeswitch/branches/ptinsley/voicemail/src/mod/applications/mod_voicemail/mod_voicemail.c
Modified:
freeswitch/branches/ptinsley/voicemail/src/include/switch_ivr.h
freeswitch/branches/ptinsley/voicemail/src/switch_ivr.c
Log:
Getting my pre-cluecon code in a branch so i can get it up to date and finished up, pretty much ignore the voicemail stuff ATM, just me learning the modules way back
Modified: freeswitch/branches/ptinsley/voicemail/src/include/switch_ivr.h
==============================================================================
--- freeswitch/branches/ptinsley/voicemail/src/include/switch_ivr.h (original)
+++ freeswitch/branches/ptinsley/voicemail/src/include/switch_ivr.h Tue Oct 24 15:43:23 2006
@@ -152,6 +152,48 @@
void *buf,
unsigned int buflen);
+/*!
+ \brief Function to evaluate an expression against a string
+ \param target The string to find a match in
+ \param expression The regular expression to run against the string
+ \return Boolean if a match was found or not
+*/
+SWITCH_DECLARE(switch_status_t) switch_regex_match(char *target, char *expression);
+
+/*!
+ \brief Play a sound and gather digits with the number of retries specified if the user doesn't give digits in the set time
+ \param session the current session to play sound to and collect digits
+ \param min_digits the fewest digits allowed for the response to be valid
+ \param max_digits the max number of digits to accept
+ \param max_tries number of times to replay the sound and capture digits
+ \param timeout time to wait for input (this is per iteration, so total possible time = max_tries * (timeout + audio playback length)
+ \param valid_terminators for input that can include # or * (useful for variable length prompts)
+ \param audio_file file to play
+ \param bad_input_audio_file file to play if the input from the user was invalid
+ \param digit_buffer variable digits captured will be put back into (empty if capture failed)
+ \param digit_buffer_length length of the buffer for digits (should be the same or larger than max_digits)
+ \return switch status, used to note status of channel (will still return success if digit capture failed)
+ \note to test for digit capture failure look for \0 in the first position of the buffer
+*/
+SWITCH_DECLARE(switch_status_t) switch_play_and_get_digits(switch_core_session_t *session,
+ unsigned int min_digits,
+ unsigned int max_digits,
+ unsigned int max_tries,
+ unsigned int timeout,
+ char* valid_terminators,
+ char* audio_file,
+ char* bad_input_audio_file,
+ void* digit_buffer,
+ unsigned int digit_buffer_length,
+ char* digits_regex);
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session_t *session,
+ switch_speech_handle_t *sh, switch_codec_t *codec,
+ switch_timer_t *timer, switch_input_callback_function_t dtmf_callback,
+ char *text, void *buf,
+ unsigned int buflen);
+
+
SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session_t *session,
switch_speech_handle_t *sh,
Added: freeswitch/branches/ptinsley/voicemail/src/mod/applications/mod_voicemail/mod_voicemail.c
==============================================================================
--- (empty file)
+++ freeswitch/branches/ptinsley/voicemail/src/mod/applications/mod_voicemail/mod_voicemail.c Tue Oct 24 15:43:23 2006
@@ -0,0 +1,339 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Paul Tinsley <jackhammer at gmail.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthmct at yahoo.com>
+ * Paul Tinsley <jackhammer at gmail.com>
+ *
+ *
+ * mod_voicemail.c -- A basic voicemail system
+ *
+ */
+#include <switch.h>
+#include <unistd.h>
+#include <pcre.h>
+#include <stdio.h>
+
+static const char modname[] = "mod_voicemail";
+static const char global_cf_name[] = "voicemail.conf";
+
+typedef struct voicemail_user voicemail_user;
+typedef struct voicemail_message voicemail_message;
+
+struct voicemail_user {
+ switch_core_session_t *session;
+ char mailbox[10];
+ char password[10];
+ int nopass;
+ int isvalid;
+ char context[25];
+ char prompt_dir[1024];
+};
+
+struct voicemail_message {
+ char message_id[40];
+ int unread;
+ struct tm time_recieved;
+ voicemail_user *vm_user;
+};
+
+static switch_status_t _get_credentials(voicemail_user *vm_user);
+static void _authenticate_user(voicemail_user *vm_user);
+
+/*!
+ \brief Function to populate a time struct with the current time details
+ \return tm structure (time.h)
+*/
+struct tm *current_time() {
+ time_t now;
+ now = time(0);
+
+ return localtime(&now);
+}
+
+/*!
+ \brief Function to write out an xml description file of the details of a voicemail (date, CID, etc...)
+ \param voicemail_message to save the details of
+ \return Succes or failure of file write
+*/
+#ifdef ASDF
+static int save_message_detail_xml(voicemail_message *vm_message) {
+
+}
+#endif
+
+static switch_status_t _get_credentials(voicemail_user *vm_user) {
+ switch_channel_t *channel; //used to hold the current channel in session
+ char input[10];
+
+ // Get the associated channel
+ channel = switch_core_session_get_channel(vm_user->session);
+
+ //see if we already have a mailbox
+ if(!strlen(vm_user->mailbox)) {
+ //try to get the mailbox # from the user
+ switch_play_and_get_digits(vm_user->session, 3, 3, 3, 7000, "#", "/usr/local/freeswitch/voicemail/prompts/en-us/mailbox.gsm", "NULL", input, sizeof(input), "^13[68]$");
+
+ //see if we got a mailbox back
+ if(!strlen(input)) {
+ //say goodbye
+ return switch_channel_get_state(channel);
+ } else {
+ //save the input
+ strncpy(vm_user->mailbox, input, sizeof(vm_user->mailbox));
+ }
+ }
+
+ //See if we need the password
+ if(!vm_user->nopass) {
+ //try and get the password
+ switch_play_and_get_digits(vm_user->session, 1, 10, 3, 7000, "#", "/usr/local/freeswitch/voicemail/prompts/en-us/password.gsm", "NULL", input, sizeof(input), NULL);
+
+ //see if we got the password
+ if(!strlen(input)) {
+ // say goodbye
+ return switch_channel_get_state(channel);
+ } else {
+ //save the input
+ strncpy(vm_user->password, input, sizeof(vm_user->password));
+ }
+ }
+
+ //if we get here we should be in good shape
+ return switch_channel_get_state(channel);
+}
+
+static switch_status_t _main_menu(voicemail_user *vm_user) {
+ switch_channel_t *channel; //used to hold the channel variable
+ switch_status_t status; //used to hold the status variable
+ char input[10]; //used to hold the input from the user
+
+ // Get the associated channel
+ channel = switch_core_session_get_channel(vm_user->session);
+
+ //retrieve the current status
+ status = switch_channel_get_state(channel);
+
+ //Make sure we are in good standing before we start
+ if(status != CS_EXECUTE) {
+ //Bail
+ return status;
+ }
+
+ //Forever, muhahahahaha
+ while(1) {
+ //play the main menu and get user input (1 digit, 3 tries, 7 second timeout, 123789 allowed)
+ status = switch_play_and_get_digits(vm_user->session, 1, 1, 3, 7000, "", "/usr/local/freeswitch/voicemail/prompts/en-us/main-menu.wav", NULL, input, sizeof(input), "^[123789]$");
+
+ //Make sure everything is still copasetic
+ if(status != CS_EXECUTE) {
+ //Bail
+ return status;
+ }
+
+ //Figure out where to go
+ switch(input[0]) {
+ case '1': { //press 1 to listen to your messages
+ break;
+ }
+ case '2': { //press 2 to change your current folder
+ break;
+ }
+ case '3': { //press 3 to send a message to another user
+ break;
+ }
+ case '7': { //Press 7 to change your greetings
+ break;
+ }
+ case '8': { //Press 8 to change your password
+ break;
+ }
+ case '9': { //Press 9 to logout
+ //User is done, bail
+ return status;
+ }
+ default: {
+ //User didn't respond in time, bail
+ return status;
+ }
+ }
+ }
+
+
+ //Stuff rolls down hill...
+ return switch_channel_get_state(channel);
+}
+
+static void _authenticate_user(voicemail_user *vm_user) {
+ if(!strcmp(vm_user->mailbox, "136")) {
+ if(!strcmp(vm_user->password, "1234")) {
+ vm_user->isvalid = 1;
+ }
+ }
+}
+
+static void login_function(switch_core_session_t *session, char *data) {
+ switch_channel_t *channel;
+ voicemail_user *vm_user; //Struct that holds details about the logged in user
+ switch_status_t status;
+
+ //voicemail_user foo;
+
+ //vm_user = &foo;
+
+ //allocate our user struct
+ if(!(vm_user = switch_core_session_alloc(session, sizeof(*vm_user)))) {
+ //bad things
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "COULDN't Allocate\n");
+ return;
+ }
+
+
+ // Parse the data coming from the dialplan
+ switch_xml_t parameters = switch_xml_parse_str(data, strlen(data));
+
+ //pull off all of the individual params
+ char *context = (char*) switch_xml_attr_soft(parameters, "context");
+
+ //setup the user
+ vm_user->isvalid = 0;
+ strncpy(vm_user->context, context, sizeof(vm_user->context));
+ strncpy(vm_user->prompt_dir, "/usr/local/freeswitch/voicemail/prompts", sizeof(vm_user->context));
+ vm_user->session = session;
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "STRUCT %s", vm_user->prompt_dir);
+
+
+ // Get the associated channel
+ channel = switch_core_session_get_channel(session);
+
+ // Make sure somebody is home
+ assert(channel != NULL);
+
+ //Answer the channel if we haven't already
+ switch_channel_answer(channel);
+
+ int tries_left;
+
+ for(tries_left = 3; tries_left > 0 && (switch_channel_get_state(channel) == CS_EXECUTE); tries_left--) {
+ //prompt the user for their credentials
+ status = _get_credentials(vm_user);
+
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "STRUCT %s\n", vm_user->mailbox);
+
+ //Make sure the channel is in good standing
+ if (status != SWITCH_STATUS_SUCCESS && status != CS_EXECUTE) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ return;
+ }
+
+ //make sure we got what we needed.
+ if(!(strlen(vm_user->mailbox) && (strlen(vm_user->password) || vm_user->nopass))) {
+ //Can't go on without user info...
+ return;
+ }
+
+ _authenticate_user(vm_user);
+
+ if(vm_user->isvalid) {
+ break;
+ }
+ }
+
+ if(!vm_user->isvalid) {
+ // say goodbye
+ switch_ivr_play_file(session, NULL, "/usr/local/freeswitch/voicemail/prompts/en-us/goodbye.gsm", NULL, NULL, NULL, 0);
+ return;
+ }
+
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "WORKED\n");
+
+ //User is authenticated
+ status = _main_menu(vm_user);
+
+ //If we get here we should be done
+ switch_ivr_play_file(session, NULL, "/usr/local/freeswitch/voicemail/prompts/en-us/goodbye.gsm", NULL, NULL, NULL, 0);
+ return;
+}
+
+
+/*
+static switch_status_t my_on_hangup(switch_core_session_t *session)
+{
+ switch_channel_t *channel;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "I globally hooked to [%s] on the hangup event\n", switch_channel_get_name(channel));
+ return SWITCH_STATUS_SUCCESS;
+
+}
+*/
+
+static const switch_state_handler_table_t state_handlers = {
+ /*.on_init */ NULL,
+ /*.on_ring */ NULL,
+ /*.on_execute */ NULL,
+ /*.on_hangup */ NULL,
+ /*.on_loopback */ NULL,
+ /*.on_transmit */ NULL
+};
+
+static const switch_application_interface_t voicemail_login_application_interface = {
+ /*.interface_name */ "voicemail_login",
+ /*.application_function */ login_function,
+ NULL, NULL, NULL,
+ /*.next*/ NULL
+};
+
+static const switch_loadable_module_interface_t mod_voicemail_module_interface = {
+ /*.module_name = */ modname,
+ /*.endpoint_interface = */ NULL,
+ /*.timer_interface = */ NULL,
+ /*.dialplan_interface = */ NULL,
+ /*.codec_interface = */ NULL,
+ /*.application_interface */ &voicemail_login_application_interface
+};
+
+SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename) {
+
+ /* connect my internal structure to the blank pointer passed to me */
+ *module_interface = &mod_voicemail_module_interface;
+
+ /* test global state handlers */
+ switch_core_add_state_handler(&state_handlers);
+
+ /* indicate that the module should continue to be loaded */
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* 'switch_module_runtime' will start up in a thread by itself just by having it exist
+ if it returns anything but SWITCH_STATUS_TERM it will be called again automaticly
+*/
+
+
+//switch_status_t switch_module_runtime(void)
Modified: freeswitch/branches/ptinsley/voicemail/src/switch_ivr.c
==============================================================================
--- freeswitch/branches/ptinsley/voicemail/src/switch_ivr.c (original)
+++ freeswitch/branches/ptinsley/voicemail/src/switch_ivr.c Tue Oct 24 15:43:23 2006
@@ -933,6 +933,172 @@
return status;
}
+SWITCH_DECLARE(switch_status_t) switch_regex_match(char *target, char *expression) {
+ const char* error = NULL; //Used to hold any errors
+ int error_offset = 0; //Holds the offset of an error
+ pcre* pcre_prepared = NULL; //Holds the compiled regex
+ int match_count = 0; //Number of times the regex was matched
+ int offset_vectors[2]; //not used, but has to exist or pcre won't even try to find a match
+
+ //Compile the expression
+ pcre_prepared = pcre_compile(expression, 0, &error, &error_offset, NULL);
+
+ //See if there was an error in the expression
+ if(error != NULL) {
+ //Clean up after ourselves
+ if(pcre_prepared) {
+ pcre_free(pcre_prepared);
+ pcre_prepared = NULL;
+ }
+
+ //Note our error
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Regular Expression Error expression[%s] error[%s] location[%d]\n", expression, error, error_offset);
+
+ //We definitely didn't match anything
+ return SWITCH_STATUS_FALSE;
+ }
+
+ //So far so good, run the regex
+ match_count = pcre_exec(pcre_prepared, NULL, target, (int) strlen(target), 0, 0, offset_vectors, sizeof(offset_vectors) / sizeof(offset_vectors[0]));
+
+ //Clean up
+ if(pcre_prepared) {
+ pcre_free(pcre_prepared);
+ pcre_prepared = NULL;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "number of matches: %d\n", match_count);
+
+ //Was it a match made in heaven?
+ if(match_count > 0) {
+ return SWITCH_STATUS_SUCCESS;
+ } else {
+ return SWITCH_STATUS_FALSE;
+ }
+}
+
+SWITCH_DECLARE(switch_status_t) switch_play_and_get_digits(switch_core_session_t *session,
+ unsigned int min_digits,
+ unsigned int max_digits,
+ unsigned int max_tries,
+ unsigned int timeout,
+ char* valid_terminators,
+ char* prompt_audio_file,
+ char* bad_input_audio_file,
+ void* digit_buffer,
+ unsigned int digit_buffer_length,
+ char* digits_regex) {
+
+ char terminator; //used to hold terminator recieved from
+ switch_channel_t *channel; //the channel contained in session
+ switch_status_t status; //used to recieve state out of called functions
+
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "switch_play_and_get_digits(session, %d, %d, %d, %d, %s, %s, %s, digit_buffer, %d, %s)\n", min_digits, max_digits, max_tries, timeout, valid_terminators, prompt_audio_file, bad_input_audio_file, digit_buffer_length, digits_regex);
+
+ //Get the channel
+ channel = switch_core_session_get_channel(session);
+
+ //Make sure somebody is home
+ assert(channel != NULL);
+
+ //Answer the channel if it hasn't already been answered
+ switch_channel_answer(channel);
+
+ //Start pestering the user for input
+ for(;(switch_channel_get_state(channel) == CS_EXECUTE) && max_tries > 0; max_tries--) {
+ //make the buffer so fresh and so clean clean
+ memset(digit_buffer, 0, digit_buffer_length);
+
+ //Play the file
+ status = switch_ivr_play_file(session, NULL, prompt_audio_file, NULL, NULL, digit_buffer, digit_buffer_length);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "play gave up %s", digit_buffer);
+
+ //Make sure we made it out alive
+ if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ break;
+ }
+
+ //we only get one digit out of playback, see if thats all we needed and what we got
+ if(max_digits == 1 && status == SWITCH_STATUS_BREAK) {
+ //Check the digit if we have a regex
+ if(digits_regex != NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Checking regex [%s] on [%s]\n", digits_regex, digit_buffer);
+
+ //Make sure the digit is allowed
+ if(switch_regex_match(digit_buffer, digits_regex) == SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Match found!\n");
+ //jobs done
+ break;
+ } else {
+ //See if a bad input prompt was specified, if so, play it
+ if(strlen(bad_input_audio_file) > 0) {
+ status = switch_ivr_play_file(session, NULL, bad_input_audio_file, NULL, NULL, NULL, 0);
+
+ //Make sure we made it out alive
+ if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ break;
+ }
+ }
+ }
+ } else {
+ //jobs done
+ break;
+ }
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Calling more digits try %d\n", max_tries);
+
+ //Try to grab some more digits for the timeout period
+ status = switch_ivr_collect_digits_count(session, digit_buffer, digit_buffer_length, max_digits, valid_terminators, &terminator, timeout);
+
+ //Make sure we made it out alive
+ if(status != SWITCH_STATUS_SUCCESS) {
+ //Bail
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ break;
+ }
+
+ //see if we got enough
+ if(min_digits <= strlen(digit_buffer)) {
+ //See if we need to test a regex
+ if(digits_regex != NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Checking regex [%s] on [%s]\n", digits_regex, digit_buffer);
+ //Test the regex
+ if(switch_regex_match(digit_buffer, digits_regex) == SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Match found!\n");
+ //Jobs done
+ return switch_channel_get_state(channel);
+ } else {
+ //See if a bad input prompt was specified, if so, play it
+ if(strlen(bad_input_audio_file) > 0) {
+ status = switch_ivr_play_file(session, NULL, bad_input_audio_file, NULL, NULL, NULL, 0);
+
+ //Make sure we made it out alive
+ if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ break;
+ }
+ }
+
+ }
+ } else {
+ //Jobs done
+ return switch_channel_get_state(channel);
+ }
+ }
+ }
+
+ //if we got here, we got no digits or lost the channel
+ memset(digit_buffer, 0, sizeof(digit_buffer));
+ return switch_channel_get_state(channel);
+}
+
+
+
+
More information about the Freeswitch-svn
mailing list